- New Group Policy settings in Windows 11 23H2 - Mon, Nov 20 2023
- Windows Server 2025 will support SMB over QUIC in all editions - Fri, Nov 17 2023
- Switch between Windows Terminal and the legacy console - Thu, Nov 16 2023
The requirement to create several identical VMs arises, for example, when you want to combine virtual instances of Windows Server to form a cluster. A typical application for this is setting up a lab environment. The following instructions show the procedure using the example of Azure Stack HCI to evaluate it on a single machine.
In principle, you could simply configure a VM manually in such a case and then clone it. The Hyper-V Manager does not have an explicit function for this task, but for some time now, the Windows Admin Center has been able to do this. New VMs, automatically created by PowerShell, are probably the cleaner solution, though.
Creating and customizing a VM
The first step is to create the virtual machine. The command depends on whether the VHD for it already exists. If it does, then you tell New-VM the path to the virtual drive using the VHDPath parameter.
We are assuming that no VHD exists yet and that we will only install it afterwards:
New-VM -Name ASHCI03 -NoVHD -Path "F:\\Hyper-V\\" -Generation 2
After the VM ASHCI03 has been created, you can configure it using Set-VM. The following command sets the number of vCPUs and the available vRAM. It also disables snapshots, including the automatic checkpoints common in Windows 10. Since Azure Stack HCI uses nested virtualization, we don't activate Dynamic Memory.
Set-VM -Name ASHCI03 -ProcessorCount 4 -StaticMemory \` -MemoryStartupBytes 8GB -CheckpointType Disabled
Now it is time to configure the vNICs. When the VM is created, it automatically receives a network adapter. Its name can be saved in the variable $NicName, using
$NicName = (Get-VMNetworkAdapter -VMName ASHCI03).Name
We need the adapter's default name because we want to name all NICs according to a consistent convention. This command gives it the new name vNIC01:
Rename-VMNetworkAdapter -Name $NicName -VMName ASHCI03 -NewName vNIC01
Creating and connecting network adapters
Microsoft's recommendation for Azure Stack HCI includes four vNICs for the virtual machine. The missing three can be created as follows:
2 .. 4 | foreach {Add-VMNetworkAdapter -VMName ASHCI03 -Name vNIC0$\_}
These should be bound to an external-type vSwitch.
The following command connects all four vNICs to a virtual switch, which in our example is called External:
1 .. 4 | foreach {Connect-VMNetworkAdapter -Name vNIC0$\_ \` -SwitchName "Extern" -VMName ASHCI03}
Since we need to enable the hypervisor in Azure Stack HCI, you need to allow spoofing of Mac addresses for nested virtualization:
1 .. 4 | foreach {Set-VMNetworkAdapter -VMName ASHCI03 -Name vNIC0$\_ \` -MacAddressSpoofing On}
At this point, you can create another necessary prerequisite, namely, to make the virtualization extensions of the CPU visible in the VM:
Set-VMProcessor -VMName ASHCI03 -ExposeVirtualizationExtensions $true
Creating and attaching drives
In addition to the system volume, Azure Stack HCI requires at least two more drives for Storage Spaces Direct. They are created with the New-VHD cmdlet, named ASHCI03-0[1,2,3].vhdx:
1 .. 3 | foreach {New-VHD -Path "F:\\Hyper-V\\ASHCI03\\Virtual Hard Disks\\ASHCI03-0$\_.vhdx" \` -Dynamic -SizeBytes 20GB}
You then link the three VHDX to the virtual machine with this command:
1 .. 3 | foreach {Add-VMHardDiskDrive -Path "F:\\Hyper-V\\ASHCI03\\Virtual Hard Disks\\ASHCI03-0$\_.vhdx" -VMName "ASHCI03"}

Assigning new VHDs to the virtual machine inserting ISO into the virtual DVD drive and enabling nested virtualization
Finally, assign the installation media to the VM using a virtual DVD drive:
Add-VMDvdDrive -VMName ASHCI03 -Path F:\\AzureStackHCI\_17784.1408\_EN-US.iso
For the VM to boot from the DVD drive, the boot order must be changed accordingly:
$dvd = Get-VMDvdDrive -VMName ASHCI03 Set-VMFirmware ASHCI03 -FirstBootDevice $dvd
The new VM is now ready for the installation of the operating system. If Hyper-V cannot be enabled in Azure Stack HCI, you can enable the feature offline in VHDX.
Consolidating all commands in a function
For more efficient use, you can combine the above instructions into one function, specifying the name of the new VM as a parameter.
If necessary, you can also set a variable for the paths used. Specify the paths as additional parameters when you execute the function.
Subscribe to 4sysops newsletter!
function generateVM{ Param( [parameter(Mandatory=$true)] [String] $vmname ) #create new VM New-VM -Name $vmname -NoVHD -Path "F:\Hyper-V\" -Generation 2 #configure vCPUs, vRAM, Checkpoints Set-VM -Name $vmname -ProcessorCount 4 -StaticMemory ` -MemoryStartupBytes 8GB -CheckpointType Disabled #query default vNIC name $NicName = (Get-VMNetworkAdapter -VMName $vmname).Name #rename network adapter Rename-VMNetworkAdapter -Name $NicName -VMName $vmname -NewName vNIC01 #add 3 additional vNICs to VM 2 .. 4 | foreach {Add-VMNetworkAdapter -VMName $vmname -Name vNIC0$_} #activate MAC address spoofing 1 .. 4 | foreach {Set-VMNetworkAdapter -VMName $vmname -Name vNIC0$_ ` -MacAddressSpoofing On} #bind adapters to vSwitch 1 .. 4 | foreach {Connect-VMNetworkAdapter -Name vNIC0$_ ` -SwitchName "Extern" -VMName $vmname} #enable nested virtualization Set-VMProcessor -VMName $vmname -ExposeVirtualizationExtensions $true #create dynamic VHDs 1 .. 3 | foreach {New-VHD -Path "F:\Hyper-V\$vmname\Virtual Hard Disks\$vmname-0$_.vhdx" ` -Dynamic -SizeBytes 20GB} #add VHDs to VM 1 .. 3 | foreach {Add-VMHardDiskDrive -Path "F:\Hyper-V\$vmname\Virtual Hard Disks\$vmname-0$_.vhdx" ` -VMName $vmname} #add ISO as new DVD drive to VM Add-VMDvdDrive -VMName $vmname -Path C:\Users\wolf.WINDOWSPRO\Downloads\AzureStackHCI_17784.1408_EN-US.iso #rearrange boot order $dvd = Get-VMDvdDrive -VMName $vmname Set-VMFirmware $vmname -FirstBootDevice $dvd }