An open API service indexing awesome lists of open source software.

https://github.com/fdcastel/Hyper-V-Automation

Collection of Powershell scripts to create Windows and Ubuntu VMs in Hyper-V.
https://github.com/fdcastel/Hyper-V-Automation

Last synced: 4 months ago
JSON representation

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

Awesome Lists containing this project

README

        

# 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 [Prepare a VHDX for QEMU migration](#prepare-a-vhdx-for-qemu-migration).

## How to install

To download all scripts into your `$env:TEMP` folder:

```powershell
iex (iwr 'bit.ly/h-v-a' -UseBasicParsing)
```

# Examples

## Create a new VM for Hyper-V

```powershell
$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
```

## Prepare a VHDX for QEMU migration

```powershell
$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

# Copy VHDX file to QEMU host
scp $vhdxFile "root@pve-host:/tmp/"
```

After the copy is complete, you may use [`new-vm-windows`](https://github.com/fdcastel/Proxmox-Automation#new-vm-windows) on Proxmox to import the `vhdx` file and create the Windows VM.

Once the VM is running, ensure that the [QEMU Guest Agent](https://pve.proxmox.com/wiki/Qemu-guest-agent) is installed within the guest environment.

## Create a Windows `vhdx` template for QEMU

```powershell
$isoFile = '.\en-us_windows_server_2025_x64_dvd_ccbcec44.iso'
$targetVhdx = '.\Server2025Standard-template.vhdx'

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

# Get Cloudbase-Init installer
$cloudbaseInitMsi = .\Get-CloudBaseInit.ps1 -OutputPath $env:TEMP

# Create VHDX
New-VHDXFromWindowsImage.ps1 `
-SourcePath $isoFile `
-Edition 'Windows Server 2025 Standard' `
-VHDXPath $targetVhdx `
-VHDXSizeBytes 60GB `
-Version 'Server2025Standard' `
-AddVirtioDrivers $virtioIso `
-AddCloudBaseInit $cloudbaseInitMsi

# Copy VHDX file to QEMU host
scp $vhdxFile "root@pve-host:/tmp/"
```

After the copy is complete, you may use [`new-vm-windows`](https://github.com/fdcastel/Proxmox-Automation#new-vm-windows) on Proxmox to import the `vhdx` file and create the Windows VM.

The guest VM will come pre-installed with the following software:
- [Windows VirtIO Drivers](https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers)
- [QEMU Guest Agent](https://pve.proxmox.com/wiki/Qemu-guest-agent)
- [Cloudbase-Init](https://cloudbase.it/cloudbase-init/)

# Command summary
- For Windows VMs
- [New-VMFromWindowsImage](#new-vmfromwindowsimage-) (*)
- [New-VHDXFromWindowsImage](#new-vhdxfromwindowsimage-) (*)
- [New-VMSession](#new-vmsession)
- [Set-NetIPAddressViaSession](#set-netipaddressviasession)
- [Set-NetIPv6AddressViaSession](#set-netipv6addressviasession)
- [Get-CloudBaseInit](#get-cloudbaseinit)
- [Get-VirtioImage](#get-virtioimage)
- [Add-VirtioDrivers](#add-virtiodrivers)
- [Enable-RemoteManagementViaSession](#enable-remotemanagementviasession)
- For Ubuntu VMs
- [Get-UbuntuImage](#get-ubuntuimage)
- [New-VMFromUbuntuImage](#new-vmfromubuntuimage-) (*)
- For Debian VMs
- [Get-DebianImage](#get-debianimage)
- [New-VMFromDebianImage](#new-vmfromdebianimage-) (*)
- For images with no `cloud-init` support
- [Get-OPNsenseImage](#get-opnsenseimage)
- [New-VMFromIsoImage](#new-vmfromisoimage-) (*)
- Other commands
- [Move-VMOffline](#move-vmoffline)

**(*) Requires administrative privileges**.

# For Windows VMs

## New-VMFromWindowsImage (*)

```powershell
New-VMFromWindowsImage.ps1 [-SourcePath] [-Edition] [-VMName] [-VHDXSizeBytes] [-AdministratorPassword] [-Version] [-MemoryStartupBytes] [[-VMProcessorCount] ] [[-VMSwitchName] ] [[-VMMacAddress] ] [[-Locale] ] [-EnableDynamicMemory] []
```

Creates a Windows VM from an ISO image.

For the `-Edition` parameter use `Get-WindowsImage -ImagePath ` 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 (*)

```powershell
New-VHDXFromWindowsImage.ps1 [-SourcePath] [-Edition] [[-ComputerName] ] [[-VHDXPath] ] [[-VHDXSizeBytes] ] [[-AdministratorPassword] ] [-Version] [[-Locale] ] [[-AddVirtioDrivers] ] [[-AddCloudBaseInit] ] []
```

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

You can add [Windows VirtIO Drivers](https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers) and the [QEMU Guest Agent](https://pve.proxmox.com/wiki/Qemu-guest-agent) with `-AddVirtioDrivers`. In this case you must provide the path of VirtIO ISO (see [`Get-VirtioImage`](#Get-VirtioImage)) to this parameter. 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

```powershell
New-VMSession.ps1 [-VMName] [-AdministratorPassword] [[-DomainName] ] []
```

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.

## Set-NetIPAddressViaSession

```powershell
Set-NetIPAddressViaSession.ps1 [-Session] [[-AdapterName] ] [-IPAddress] [-PrefixLength] [-DefaultGateway] [[-DnsAddresses] ] [[-NetworkCategory] ] []
```

Sets IPv4 configuration for a Windows VM.

## Set-NetIPv6AddressViaSession

```powershell
Set-NetIPv6AddressViaSession.ps1 [-Session] [[-AdapterName] ] [-IPAddress] [-PrefixLength] [[-DnsAddresses] ] []
```

Sets IPv6 configuration for a Windows VM.

## Get-CloudBaseInit

```powershell
Get-CloudBaseInit.ps1 [[-OutputPath] ] []
```

Downloads latest stable MSI installer of [Cloudbase-Init](https://cloudbase.it/cloudbase-init/).

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

Returns the path for downloaded file.

## Get-VirtioImage

```powershell
Get-VirtioImage.ps1 [[-OutputPath] ] []
```

Downloads latest stable ISO image of [Windows VirtIO Drivers](https://pve.proxmox.com/wiki/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

```powershell
Add-VirtioDrivers.ps1 [-VirtioIsoPath] [-ImagePath] [-Version] [[-ImageIndex] ] []
```

Adds [Windows VirtIO Drivers](https://pve.proxmox.com/wiki/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](https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers#Using_the_ISO). Or just use [`Get-VirtioImage.ps1`](#Get-VirtioImage).

You must use `-ImagePath` to inform the path of file.

You may use `-Version` to specify the Windows version of the image (recommended). This ensures that all appropriate drivers for the system are installed correctly.

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).

Please note that -- unlike the `-AddVirtioDrivers` option from `New-VHDXFromWindowsImage` -- this script cannot install the [QEMU Guest Agent](https://pve.proxmox.com/wiki/Qemu-guest-agent) in an existing `vhdx`, as its operations are limited to the offline image (cannot run the installer).

## Enable-RemoteManagementViaSession

```powershell
Enable-RemoteManagementViaSession.ps1 [-Session] []
```

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

# For Ubuntu VMs

## Get-UbuntuImage

```powershell
Get-UbuntuImage.ps1 [[-OutputPath] ] [-Previous] []
```

Downloads latest Ubuntu 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 the previous LTS image instead of the current LTS.

Returns the path for downloaded file.

## New-VMFromUbuntuImage (*)

```powershell
New-VMFromUbuntuImage.ps1 -SourcePath -VMName -RootPassword [-FQDN ] [-VHDXSizeBytes ] [-MemoryStartupBytes ] [-EnableDynamicMemory] [-ProcessorCount ] [-SwitchName ] [-MacAddress ] [-IPAddress ] [-Gateway ] [-DnsAddresses ] [-InterfaceName ] [-VlanId ] [-SecondarySwitchName ] [-SecondaryMacAddress ] [-SecondaryIPAddress ] [-SecondaryInterfaceName ] [-SecondaryVlanId ] [-InstallDocker] []

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

Creates a Ubuntu VM from Ubuntu Cloud image.

You must have [qemu-img](https://cloudbase.it/qemu-img-windows/) installed. If you have [chocolatey](https://chocolatey.org/) you can install it with:

```
choco install qemu-img -y
```

You can download Ubuntu cloud images from [here](https://cloud-images.ubuntu.com/releases/focal/release/) (get the `amd64.img` version). Or just use [`Get-UbuntuImage.ps1`](#Get-UbuntuImage).

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

```powershell
# 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 [email protected]
```

# For Debian VMs

## Get-DebianImage

```powershell
Get-DebianImage.ps1 [[-OutputPath] ] []
```

Downloads latest Debian 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 (*)

```powershell
New-VMFromDebianImage.ps1 -SourcePath -VMName -RootPassword [-FQDN ] [-VHDXSizeBytes ] [-MemoryStartupBytes ] [-EnableDynamicMemory] [-ProcessorCount ] [-SwitchName ] [-MacAddress ] [-IPAddress ] [-Gateway ] [-DnsAddresses ] [-InterfaceName ] [-VlanId ] [-SecondarySwitchName ] [-SecondaryMacAddress ] [-SecondaryIPAddress ] [-SecondaryInterfaceName ] [-SecondaryVlanId ] [-InstallDocker] []

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

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

You must have [qemu-img](https://cloudbase.it/qemu-img-windows/) installed. If you have [chocolatey](https://chocolatey.org/) you can install it with:

```
choco install qemu-img -y
```

You can download Debian cloud images from [here](https://cloud.debian.org/images/cloud/bullseye/daily) (get the `genericcloud-amd64 version`). Or just use [`Get-DebianImage.ps1`](#Get-DebianImage).

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

```powershell
# 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 [email protected]
```

# For images with no `cloud-init` support

## Get-OPNsenseImage

```powershell
Get-OPNsenseImage.ps1 [[-OutputPath] ] []
```

Downloads latest OPNsense ISO image.

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

Returns the path for downloaded file.

## New-VMFromIsoImage (*)

```powershell
New-VMFromIsoImage.ps1 [-IsoPath] [-VMName] [[-VHDXSizeBytes] ] [[-MemoryStartupBytes] ] [[-ProcessorCount] ] [[-SwitchName] ] [[-MacAddress] ] [[-InterfaceName] ] [[-VlanId] ] [[-SecondarySwitchName] ] [[-SecondaryMacAddress] ] [[-SecondaryInterfaceName] ] [[-SecondaryVlanId] ] [-EnableDynamicMemory] [-EnableSecureBoot] []
```

Creates a VM and boot it from a ISO image.

Returns the `VirtualMachine` created.

After installation, remember to remove the ISO mounted drive with:

```powershell
Get-VMDvdDrive -VMName 'vm-name' | Remove-VMDvdDrive
```

**(*) Requires administrative privileges**.

## OPNsense: Example

The following example will create a OPNsense router and a Windows VM in a private network which will have internet access through OPNsense.

It requires two Hyper-V Virtual Switches:

- `SWITCH` (type: External), connected to a network with internet access and DHCP; and
- `ISWITCH` (type: Internal), for the private netork.

From OPNsense convention, the first network interface will be assigned as LAN.
> **Note**: The default network address will be `192.168.1.1/24` with DHCP enabled.

```powershell
$isoFile = .\Get-OPNsenseImage.ps1 -Verbose
$vmName = 'TstOpnRouter'

.\New-VMFromIsoImage.ps1 `
-IsoPath $isoFile `
-VMName $vmName `
-VHDXSizeBytes 60GB `
-MemoryStartupBytes 2GB `
-ProcessorCount 2 `
-SwitchName 'ISWITCH' `
-InterfaceName 'lan' `
-SecondarySwitchName 'SWITCH' `
-SecondaryInterfaceName 'wan' `
-Verbose

# Windows Server 2022 image
$isoFile = 'C:\Adm\SW_DVD9_Win_Server_STD_CORE_2022__64Bit_English_DC_STD_MLF_X22-74290.ISO'
$vmName = 'TstOpnClient'
$pass = 'u531@rg3pa55w0rd$!'

.\New-VMFromWindowsImage.ps1 `
-SourcePath $isoFile `
-Edition 'Windows Server 2022 Standard (Desktop Experience)' `
-VMName $vmName `
-VHDXSizeBytes 60GB `
-AdministratorPassword $pass `
-Version 'Server2022Standard' `
-MemoryStartupBytes 4GB `
-VMProcessorCount 2 `
-VMSwitchName 'ISWITCH'
```

The Windows VM should get an internal IP address (from `192.168.1.x/24` range) via DHCP from OPNsense and it should have working internet access.

Remember that OPNsense will be running in _live_ mode from ISO image. To install it logon via console with `installer` user and `opnsense` password.

After the installation, remove the installation media with:

```powershell
Get-VMDvdDrive -VMName 'TstOpnRouter' | Remove-VMDvdDrive
```

# Other commands

## Move-VMOffline

```powershell
Move-VMOffline.ps1 [-VMName] [-DestinationHost] [-CertificateThumbprint] []
```

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