Files
syno-scripts/Powershell/TESTING/New-VulnhubVM.ps1
T

223 lines
8.6 KiB
PowerShell
Executable File

[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[ValidateScript({$_.Host -eq 'download.vulnhub.com'})]
[System.Uri]
$VulnhubURI,
[Parameter(Mandatory = $true)]
[ValidateScript({
if (-not (Test-Path $_)) {
throw "Specified path does not exist:`n$_"
}
else {
return $true
}
})]
[String]
$DownloadDirectory,
[Parameter(Mandatory = $true)]
[ValidateScript({
$id = $_
$id -ge 0
if (Invoke-Command -ScriptBlock {qm status $id 2>/dev/null}) {
throw "VM with ID: $id already exists."
}
elseif (Invoke-Command -ScriptBlock {pct status $id 2>/dev/null}) {
throw "Container with ID: $id already exists."
}
else {
return $true
}
})]
[Int]
$VMID,
[Parameter(
Mandatory = $true,
HelpMessage = 'other: unspecified OS; wxp: Windows XP; w2k: Windows 2000; w2k3: Windows 2003; w2k8: Windows 2008; wvista: Windows Vista; win7: Windows 7; win8: Windows 8; win10: Windows 10; l24: Linux Kernel 2.4; l26: Linux Kernel 2.6; solaris: Solaris/OpenSolaris/OpenIndiana kernel'
)]
[ValidateSet('other', 'wxp', 'w2k', 'w2k3', 'w2k8', 'wvista', 'win7','win8', 'win10', 'l24', 'l26', 'solaris')]
[String]
$GuestOSType,
[Parameter(
Mandatory = $true,
HelpMessage = 'Example: local-lvm. This is where the guest boot disk will be stored on the Proxmox node.'
)]
[ValidateScript({
if (-not (pvesm list $_ 2>/dev/null)) {
throw "Storage volume: $_ does not exist."
}
else {
return $true
}
})]
[String]
$VMDiskStorageVolume,
[Parameter(HelpMessage = 'Example: vmbr0')]
[ValidateNotNullOrEmpty()]
[ValidateScript({
if (-not (ip link show $_)) {
throw "Network interface not found."
}
else {
return $true
}
})]
[String]
$NetworkBridge,
[Parameter(HelpMessage = 'Enter an integer between 0 and 4094')]
[ValidateRange(0,4094)]
[Int]
$VlanTag,
[Parameter(HelpMessage = 'Strictly for administrative purposes only.')]
[ValidateNotNullOrEmpty()]
[String]
$VMName,
[Parameter(HelpMessage = 'Example: 2048')]
[Int]
$MemoryMiB
)
begin {
if (-not (which unar)) {
throw "This script requires the program, unar, which is a single archive decompression tool that works on a variety or archive types.`nPlease install that program and re-run the script."
}
function Find-VMDK ($Directory) {
$files = Get-ChildItem $Directory -Recurse
$vmdk = $files | Where-Object {$_.Extension -eq '.vmdk'}
if (-not $vmdk) {
$files | ForEach-Object {
$file = $_
$type = file $file.FullName
$isArchive = $type -like '*archive*' -or $type -like '*compressed*'
if ($isArchive) {
Write-Host "Nested archive found: " -NoNewLine
Write-Host $file.FullName -ForegroundColor Green
$archiveFileFound = $file
}
}
if ($archiveFileFound) {
$subdirectory = "$Directory/temp$(Get-Random)"
unar $archiveFileFound.FullName -o $subdirectory
Find-VMDK -Directory $subdirectory
}
else {
throw "No .vmdk file found and finished recursively checking for archives without results."
}
}
else {
return $vmdk
}
}
if (-not [System.IO.Path]::EndsInDirectorySeparator($DownloadDirectory)) { $DownloadDirectory = $DownloadDirectory + '/' }
$fileName = $VulnhubURI.Segments[-1] # Define the download file name based on the URI provided.
if ($fileName -like '*.iso') { throw "Creating VMs from ISO files not yet implemented." }
$downloadPath = $DownloadDirectory + $fileName
$archiveOutputDirectory = $DownloadDirectory + "temp$(Get-Random)"
$parameterCollection = @()
$parameterCollection += "--ostype $GuestOSType"
$parameterCollection += "--storage $VMDiskStorageVolume"
if ($PSBoundParameters['NetworkBridge']) {
if ($PSBoundParameters['VlanTag']) {
$parameterCollection += "--net0 model=virtio,bridge=$NetworkBridge,firewall=0,tag=$VlanTag"
}
else {
$parameterCollection += "--net0 model=virtio,bridge=$NetworkBridge,firewall=0"
}
}
if ($PSBoundParameters['VMName']) { $parameterCollection += "--name $VMName" }
if ($PSBoundParameters['MemoryMiB']) { $parameterCollection += "--memory $MemoryMiB" }
$parameterString = $parameterCollection -join ' '
}
process {
Write-Host "[+] Downloading VM from Vulnhub. Please be patient...`n" -ForegroundColor Green
wget $VulnhubURI.ToString() -q --show-progress -O $downloadPath
$downloadedVM = Get-ChildItem $downloadPath
try {
Write-Host "[+] Decompressing archive: $downloadedVM to $archiveOutputDirectory`n" -ForegroundColor Green
Write-Host "[!] This may take a while depending on the size of the archive.`n" -ForegroundColor Yellow
unar $downloadedVM.FullName -o $archiveOutputDirectory
}
catch {
throw "Error expanding archive:`n$_"
}
try {
Write-Host "[+] Replacing any whitespace from file paths for compatibility.`n" -ForegroundColor Green
Get-ChildItem $archiveOutputDirectory -Recurse | ForEach-Object { # Arbitrarily try to remove any whitespace in file path, as this has been an issue before
$removeWhiteSpace = $_.FullName -replace ' ', '_'
if ($removeWhiteSpace -ne $_.FullName) {
Move-Item $_.FullName $removeWhiteSpace
}
}
Write-Host "[+] Searching for the .vmdk disk file(s) in $archiveOutputDirectory`n" -ForegroundColor Green
$vmDisk = Find-VMDK -Directory $archiveOutputDirectory
$vmDisk = Find-VMDK -Directory $archiveOutputDirectory # Rediscover the renamed disks
Write-Host "[+] Attempting to convert the VMDK file(s) to QCOW2 to support snapshots.`n" -ForegroundColor Green
$qcow2Disks = @()
$vmDisk | ForEach-Object {
$vmdkfile = $_
$qcow2file = $vmdkfile.FullName -replace 'vmdk', 'qcow2'
$qcow2Disks += $qcow2file
Start-Process qemu-img -ArgumentList "convert -f vmdk -O qcow2 $($vmdkfile.FullName) $qcow2file" -Wait
}
}
catch {
Get-Item $downloadPath, $archiveOutputDirectory | Remove-Item -Recurse -Force # Clean up any artifacts after error.
throw $_
}
try {
Write-Host "[+] Attempting to create the VM with the following command: qm create $VMID $parameterString.`n" -ForegroundColor Green
Start-Process qm -ArgumentList "create $VMID $parameterString" -Wait -RedirectStandardOutput /dev/null
Write-Host "[+] Attempting to import the QCOW2 file(s) as a disk.`n" -ForegroundColor Green
$qcow2Disks | ForEach-Object {
$disk = $_
Write-Host "[+] Running command: qm importdisk $VMID $disk $VMDiskStorageVolume --format qcow2`n" -ForegroundColor Green
Start-Process qm -ArgumentList "importdisk $VMID $disk $VMDiskStorageVolume --format qcow2" -Wait -RedirectStandardOutput /dev/null
}
$iteration = 0
$qcow2Disks | ForEach-Object {
Write-Host "[+] Attempting to attach the disk to the VM's SATA controller.`n" -ForegroundColor Green
Write-Host "[+] Running command: qm set $VMID --sata$iteration $($VMDiskStorageVolume):vm-$VMID-disk-$iteration`n" -ForegroundColor Green
Start-Process qm -ArgumentList "set $VMID --sata$iteration $($VMDiskStorageVolume):vm-$VMID-disk-$iteration" -Wait -RedirectStandardOutput /dev/null
$iteration++
}
Write-Host "[+] Setting sata0 as the boot device.`n" -ForegroundColor Green
Start-Process qm -ArgumentList "set $VMID --boot=`"order=sata0`"" -Wait -RedirectStandardOutput /dev/null
Write-Host "[+] All commands completed successfully`n" -ForegroundColor Green
}
catch {
throw "Command failed with the following error:`n$_"
}
}
end {
if ((Test-Path $downloadPath -ErrorAction SilentlyContinue) -or (Test-Path $archiveOutputDirectory -ErrorAction SilentlyContinue)) {
Write-Host "[+] Removing any files created by the script.`n" -ForegroundColor Green
Remove-Item $downloadPath -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
Remove-Item $archiveOutputDirectory -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
}