/Hyper-V-Automation

Collection of Powershell scripts to create Windows and Ubuntu VMs in Hyper-V.

Primary LanguagePowerShell

Hyper-V automation scripts

Collection of Powershell scripts to create Windows, Ubuntu and Debian VMs in Hyper-V.

For Windows Server 2016+, Windows 8.1+ only.

For Hyper-V Generation 2 (UEFI) VMs only.

To migrate an existing Windows VM from Hyper-V to Proxmox (QEMU) see Windows: Prepare a VHDX for QEMU migration.

How to install

To download all scripts into your $env:temp folder:

iex (iwr 'https://raw.githubusercontent.com/ezhische/Hyper-V-Automation/master/bootstrap.ps1' -UseBasicParsing)

Command summary

(*) Requires administrative privileges.

For Windows VMs

New-WindowsUnattendFile

New-WindowsUnattendFile.ps1 [-AdministratorPassword] <string> [-Version] <string> [[-ComputerName] <string>] [[-FilePath] <string>] [[-Locale] <string>] [<CommonParameters>]

Creates an unattend.xml file to initialize a Windows VM. Used by New-VMFromWindowsImage.

Returns the full path of created file.

New-VMFromWindowsImage (*)

New-VMFromWindowsImage.ps1 [-SourcePath] <string> [-Edition] <string> [-VMName] <string> [-VHDXSizeBytes] <uint64> [-AdministratorPassword] <string> [-Version] <string> [-MemoryStartupBytes] <long> [[-VMProcessorCount] <long>] [[-VMSwitchName] <string>] [[-VMMacAddress] <string>] [[-Locale] <string>] [-EnableDynamicMemory] [<CommonParameters>]

Creates a Windows VM from an ISO image.

For the -Edition parameter use Get-WindowsImage -ImagePath <path-to-install.wim> to see all available images. Or just use "1" for the first one.

The -Version parameter is required to set the product key (required for a full unattended install).

Returns the VirtualMachine created.

(*) Requires administrative privileges.

New-VHDXFromWindowsImage (*)

New-VHDXFromWindowsImage.ps1 [-SourcePath] <string> [-Edition] <string> [-ComputerName] <string> [[-VHDXPath] <string>] [-VHDXSizeBytes] <uint64> [-AdministratorPassword] <string> [-Version] <string> [[-Locale] <string>] [[-AddVirtioDrivers] <string>] [<CommonParameters>]

Creates a Windows VHDX from an ISO image. Similar to New-VMFromWindowsImage but without creating a VM.

You can add VirtIO drivers with -AddVirtioDrivers. In this case you must inform the path of VirtIO ISO (see Get-VirtioImage). This is useful if you wish to import the created VHDX in a KVM environment.

Returns the path for the VHDX file created.

(*) Requires administrative privileges.

New-VMSession

New-VMSession.ps1 [-VMName] <string> [-AdministratorPassword] <string> [[-DomainName] <string>] [<CommonParameters>]

Creates a new PSSession into a VM. In case of error, keeps retrying until connected. Useful for wait until a VM is ready to accept commands.

Returns the PSSession created.

Enable-RemoteManagementViaSession

Enable-RemoteManagementViaSession.ps1 [-Session] <PSSession[]> [<CommonParameters>]

Enables Powershell Remoting, CredSSP server authentication and sets WinRM firewall rule to Any remote address (default: LocalSubnet).

Set-NetIPAddressViaSession

Set-NetIPAddressViaSession.ps1 [-Session] <PSSession[]> [[-AdapterName] <string>] [-IPAddress] <string> [-PrefixLength] <byte> [-DefaultGateway] <string> [[-DnsAddresses] <string[]>] [[-NetworkCategory] <string>] [<CommonParameters>]

Sets TCP/IP configuration for a VM.

Get-VirtioImage

Get-VirtioImage.ps1 [[-OutputPath] <string>] [<CommonParameters>]

Downloads latest stable ISO image of Windows VirtIO Drivers.

Use -OutputPath parameter to set download location. If not informed, the current folder will be used.

Returns the path for downloaded file.

Add-VirtioDrivers

Add-VirtioDrivers.ps1 [-VirtioIsoPath] <string> [-ImagePath] <string> [[-ImageIndex] <int>] [<CommonParameters>]

Adds Windows VirtIO Drivers into a WIM or VHDX file.

You must inform the path of VirtIO ISO with -VirtioIsoPath. You can download the latest image from here. Or just use Get-VirtioImage.ps1.

You must use -ImagePath to inform the path of file. For WIM files you must also use -ImageIndex to inform the image index inside of WIM. For VHDX files the image index must be always 1 (the default).

Convert-VhdxToQcow2

Convert-VhdxToQcow2.ps1 [-SourceVhdx] <string> [[-TargetQcow2] <string>] [<CommonParameters>]

Convert a vhdx file to qcow2 format (used by QEMU).

You must inform the path of source vhdx file with -SourceVhdx.

The target file name will be the same as the source with .qcow2 extension. You may use -TargetQcow2 to override this.

Returns the path of created file.

Windows: Example

$isoFile = '.\en_windows_server_2019_x64_dvd_4cb967d8.iso'
$vmName = 'TstWindows'
$pass = 'u531@rg3pa55w0rd$!'

.\New-VMFromWindowsImage.ps1 -SourcePath $isoFile -Edition 'Windows Server 2019 Standard' -VMName $vmName -VHDXSizeBytes 60GB -AdministratorPassword $pass -Version 'Server2019Standard' -MemoryStartupBytes 2GB -VMProcessorCount 2

$sess = .\New-VMSession.ps1 -VMName $vmName -AdministratorPassword $pass

.\Set-NetIPAddressViaSession.ps1 -Session $sess -IPAddress 10.10.1.195 -PrefixLength 16 -DefaultGateway 10.10.1.250 -DnsAddresses '8.8.8.8','8.8.4.4' -NetworkCategory 'Public'

.\Enable-RemoteManagementViaSession.ps1 -Session $sess

# You can run any commands on VM with Invoke-Command:
Invoke-Command -Session $sess { 
    echo "Hello, world! (from $env:COMPUTERNAME)"

    # Install chocolatey
    Set-ExecutionPolicy Bypass -Scope Process -Force
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
    iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

    # Install 7-zip
    choco install 7zip -y
}

Remove-PSSession -Session $sess

Windows: Prepare a VHDX for QEMU migration

$vmName = 'TstWindows'

# Shutdown VM
Stop-VM $vmName

# Get VirtIO ISO
$virtioIso = .\Get-VirtioImage.ps1 -OutputPath $env:TEMP

# Install VirtIO drivers to Windows VM (offline)
$vhdxFile = "C:\Hyper-V\Virtual Hard Disks\$vmName.vhdx"
.\Add-VirtioDrivers.ps1 -VirtioIsoPath $virtioIso -ImagePath $vhdxFile

# Convert vhdx to QCOW2 format
$qcow2File = .\Convert-VhdxToQcow2.ps1 -SourceVhdx $vhdxFile

# Copy QCOW2 file to QEMU host
scp $qcow2File "root@pve-host:/tmp/"

After copy, you may use import-vm-windows (on Proxmox) to create the Windows VM.

For Ubuntu VMs

Get-UbuntuImage

Get-UbuntuImage.ps1 [[-OutputPath] <string>] [-Previous] [<CommonParameters>]

Downloads latest Ubuntu 22.04 LTS cloud image and verify its integrity.

Use -OutputPath parameter to set download location. If not informed, the current folder will be used.

Use -Previous parameter to download Ubuntu 20.04 LTS image instead of 22.04 LTS.

Returns the path for downloaded file.

New-VMFromUbuntuImage (*)

New-VMFromUbuntuImage.ps1 -SourcePath <string> -VMName <string> -RootPassword <string> [-FQDN <string>] [-VHDXSizeBytes <uint64>] [-MemoryStartupBytes <long>] [-EnableDynamicMemory] [-ProcessorCount <long>] [-SwitchName <string>] [-MacAddress <string>] [-IPAddress <string>] [-Gateway <string>] [-DnsAddresses <string[]>] [-InterfaceName <string>] [-VlanId <string>] [-SecondarySwitchName <string>] [-SecondaryMacAddress <string>] [-SecondaryIPAddress <string>] [-SecondaryInterfaceName <string>] [-SecondaryVlanId <string>] [-InstallDocker] [<CommonParameters>]

New-VMFromUbuntuImage.ps1 -SourcePath <string> -VMName <string> -RootPublicKey <string> [-FQDN <string>] [-VHDXSizeBytes <uint64>] [-MemoryStartupBytes <long>] [-EnableDynamicMemory] [-ProcessorCount <long>] [-SwitchName <string>] [-MacAddress <string>] [-IPAddress <string>] [-Gateway <string>] [-DnsAddresses <string[]>] [-InterfaceName <string>] [-VlanId <string>] [-SecondarySwitchName <string>] [-SecondaryMacAddress <string>] [-SecondaryIPAddress <string>] [-SecondaryInterfaceName <string>] [-SecondaryVlanId <string>] [-InstallDocker] [<CommonParameters>]

Creates a Ubuntu VM from Ubuntu Cloud image.

You must have qemu-img installed. If you have chocolatey you can install it with:

choco install qemu-img -y

You can download Ubuntu cloud images from here (get the amd64.img version). Or just use Get-UbuntuImage.ps1.

You must use -RootPassword to set a password or -RootPublicKey to set a public key for default ubuntu user.

You may configure network using -VlanId, -IPAddress, -Gateway and -DnsAddresses options. -IPAddress must be in address/prefix format. If not specified the network will be configured via DHCP.

You may rename interfaces with -InterfaceName and -SecondaryInterfaceName. This will set Hyper-V network adapter name and also set the interface name in Ubuntu.

You may add a second network using -SecondarySwitchName. You may configure it with -Secondary* options.

You may install Docker using -InstallDocker switch.

Returns the VirtualMachine created.

(*) Requires administrative privileges.

Ubuntu: Example

# Create a VM with static IP configuration and ssh public key access
$imgFile = .\Get-UbuntuImage.ps1 -Verbose
$vmName = 'TstUbuntu'
$fqdn = 'test.example.com'
$rootPublicKey = Get-Content "$env:USERPROFILE\.ssh\id_rsa.pub"

.\New-VMFromUbuntuImage.ps1 -SourcePath $imgFile -VMName $vmName -FQDN $fqdn -RootPublicKey $rootPublicKey -VHDXSizeBytes 60GB -MemoryStartupBytes 2GB -ProcessorCount 2 -IPAddress 10.10.1.196/16 -Gateway 10.10.1.250 -DnsAddresses '8.8.8.8','8.8.4.4' -Verbose

# Your public key is installed. This should not ask you for a password.
ssh ubuntu@10.10.1.196

For Debian VMs

Get-DebianImage

Get-DebianImage.ps1 [[-OutputPath] <string>] [<CommonParameters>]

Downloads latest Debian 11 cloud image.

Use -OutputPath parameter to set download location. If not informed, the current folder will be used.

Returns the path for downloaded file.

New-VMFromDebianImage (*)

New-VMFromDebianImage.ps1 -SourcePath <string> -VMName <string> -RootPassword <string> [-FQDN <string>] [-VHDXSizeBytes <uint64>] [-MemoryStartupBytes <long>] [-EnableDynamicMemory] [-ProcessorCount <long>] [-SwitchName <string>] [-MacAddress <string>] [-IPAddress <string>] [-Gateway <string>] [-DnsAddresses <string[]>] [-InterfaceName <string>] [-VlanId <string>] [-SecondarySwitchName <string>] [-SecondaryMacAddress <string>] [-SecondaryIPAddress <string>] [-SecondaryInterfaceName <string>] [-SecondaryVlanId <string>] [-InstallDocker] [<CommonParameters>]

New-VMFromDebianImage.ps1 -SourcePath <string> -VMName <string> -RootPublicKey <string> [-FQDN <string>] [-VHDXSizeBytes <uint64>] [-MemoryStartupBytes <long>] [-EnableDynamicMemory] [-ProcessorCount <long>] [-SwitchName <string>] [-MacAddress <string>] [-IPAddress <string>] [-Gateway <string>] [-DnsAddresses <string[]>] [-InterfaceName <string>] [-VlanId <string>] [-SecondarySwitchName <string>] [-SecondaryMacAddress <string>] [-SecondaryIPAddress <string>] [-SecondaryInterfaceName <string>] [-SecondaryVlanId <string>] [-InstallDocker] [<CommonParameters>]

Creates a Debian VM from Debian Cloud image. For Debian 11 only.

You must have qemu-img installed. If you have chocolatey you can install it with:

choco install qemu-img -y

You can download Debian cloud images from here (get the genericcloud-amd64 version). Or just use Get-DebianImage.ps1.

You must use -RootPassword to set a password or -RootPublicKey to set a public key for default debian user.

You may configure network using -VlanId, -IPAddress, -Gateway and -DnsAddresses options. -IPAddress must be in address/prefix format. If not specified the network will be configured via DHCP.

You may rename interfaces with -InterfaceName and -SecondaryInterfaceName. This will set Hyper-V network adapter name and also set the interface name in Debian.

You may add a second network using -SecondarySwitchName. You may configure it with -Secondary* options.

You may install Docker using -InstallDocker switch.

Returns the VirtualMachine created.

(*) Requires administrative privileges.

Debian: Example

# Create a VM with static IP configuration and ssh public key access
$imgFile = .\Get-DebianImage.ps1 -Verbose
$vmName = 'TstDebian'
$fqdn = 'test.example.com'
$rootPublicKey = Get-Content "$env:USERPROFILE\.ssh\id_rsa.pub"

.\New-VMFromDebianImage.ps1 -SourcePath $imgFile -VMName $vmName -FQDN $fqdn -RootPublicKey $rootPublicKey -VHDXSizeBytes 60GB -MemoryStartupBytes 2GB -ProcessorCount 2 -IPAddress 10.10.1.197/16 -Gateway 10.10.1.250 -DnsAddresses '8.8.8.8','8.8.4.4' -Verbose

# Your public key is installed. This should not ask you for a password.
ssh debian@10.10.1.197

Other commands

Move-VMOffline

Move-VMOffline.ps1 [-VMName] <string> [-DestinationHost] <string> [-CertificateThumbprint] <string> [<CommonParameters>]

Uses Hyper-V replica to move a VM between hosts not joined in a domain.