Hyper-V PowerShell Template Script

,

In my lab environment, I am constantly deploying different Virtual Machines. I’ve built up a number of template vhdx files which are either sysprep’d installs of Windows Server or custom images ready to go. Manually setting up VMs via the User interface can be a little time consuming, so I’ve written up a small PowerShell script that helps with building and configuring a Virtual Machine.

The script is quite basic and, uses BITS to copy so you get a progress bar and most things are hard-coded. It’s worked for a number of years without fail, but could probably do with some modernisation. I’m posting it since it works for me, and it’s what I use for the lab. Feel free to re-use and cannibalise as you want (or trash).

Import-Module BitsTransfer

#Defining Variables. Change these patch to your own!
$2019STD = "C:\Templates\Server 2019 Standard Template.vhdx"
$2022STD = "C:\Templates\Server 2022 Standard Template.vhdx"
$2025STD = "C:\Templates\Server 2025 Standard Template.vhdx"
$WIN11 = "C:\Templates\Windows 11 Enterprise Template.vhdx"

#Cleaning screen
cls

# Offer choice in which OS to deploy
Do {
Write-host
Write-host "Which operating system would you like to deploy?" -foregroundcolor Green
Write-host
Write-host "1. Server 2019 Standard" -foregroundcolor Red
Write-host "2. Server 2022 Standard" -foregroundcolor Red
Write-host "3. Server 2025 Standard" -foregroundcolor Green
Write-host "4. Windows 11 Enterprise" -foregroundcolor Blue

$deploy = Read-host "Please select an operating system image to continue..."
if ($deploy -eq "") {write-host "Error: Please select and operating system image"  -foregroundcolor Red}; if ($deploy -eq $NULL) {write-host "Error: Please select an operating system image" -foregroundcolor Red}
write-host
} while ($deploy -eq "" -or $deploy -eq $NULL)

# What should the VM be called
Do {
$Name = Read-Host "Enter the Virtual Machine name (Press [Enter] to choose Server01)"
if ($Name -eq ""){$Name="Server01"} ; if ($Name -eq $NULL){$Name="Server01"}
$VMName = Get-VM -name $Name -ErrorAction SilentlyContinue
if (!$VMname) { Write-Host "No VM named $Name exists" }
else
{ Write-Host "Error: A VM with the name $Name already exists" -foregroundcolor Red; $Name = $null }
} while ($Name -eq $null)

#how much memory needs to be assigned (static only at this point)
$Memory = Read-Host "Enter the size of the Virtual Machine Memory (Press [Enter] to choose 4096MB)"
if ($Memory -eq ""){$Memory=4096MB} ; if ($Memory -eq $NULL){$Memory=4096MB}

# How many CPU cores do you want assigned
$Cores = Read-Host "Enter how many Virtual Processors to assign the Virtual Machine (Press [Enter] to have 2 Cores)"
if ($Cores -eq ""){$Cores=2} ; if ($Cores -eq $NULL){$Cores=2}

#Where should the VM be stored
$Location = Read-Host "Enter the location of the Virtual Machine file (Press [Enter] to choose E:\Hyper-V)"
if ($Location -eq ""){$Location="E:\Hyper-V"} ; if ($Location -eq $NULL){$Location="E:\Hyper-V"}

#Listing networks on the host
Write-host
get-vmswitch
write-host

#Which network should be used

$Network = Read-Host "Enter the name of the Virtual Machine Network (Press [Enter] to choose External)"
if ($Network -eq ""){$Network="External"} ; if ($Network -eq $NULL){$Network="External"}

#VM creation starts here

Switch ($deploy)
{
1 {new-vm $Name -Generation 2 -path $Location ;New-Item $Location\$Name\"Virtual Hard Disks" -type directory; Start-BitsTransfer -Source $2019STD -Destination $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" -Description "Windows Server 2019.vhdx" -DisplayName "Copying template VHDX" ; add-vmharddiskdrive -vmname $Name -path $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" }
2 {new-vm $Name -Generation 2 -path $Location ;New-Item $Location\$Name\"Virtual Hard Disks" -type directory; Start-BitsTransfer -Source $2022STD -Destination $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" -Description "Windows Server 2022.vhdx" -DisplayName "Copying template VHDX" ; add-vmharddiskdrive -vmname $Name -path $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" }
3 {new-vm $Name -Generation 2 -path $Location ;New-Item $Location\$Name\"Virtual Hard Disks" -type directory; Start-BitsTransfer -Source $2025STD -Destination $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" -Description "Windows Server 2025.vhdx" -DisplayName "Copying template VHDX" ; add-vmharddiskdrive -vmname $Name -path $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" }
4 {new-vm $Name -Generation 2 -path $Location ;New-Item $Location\$Name\"Virtual Hard Disks" -type directory; Start-BitsTransfer -Source $WIN11 -Destination $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" -Description "Windows 11 Enterprise.vhdx" -DisplayName "Copying template VHDX" ; add-vmharddiskdrive -vmname $Name -path $Location\$Name\"Virtual Hard Disks\"$Name".vhdx" }
}

get-vm $Name | Add-VMDvdDrive -ControllerNumber 0
get-vm $Name | Set-VMProcessor -Count $Cores
get-vm $Name | Set-VMMemory -StartupBytes $Memory -DynamicMemoryEnabled 1
Get-VMSwitch $Network | Connect-VMNetworkAdapter -VMName $Name

#Success message.
Switch ($deploy)
{
1 {Write-host "A Windows 2019 Standard VM called '$Name' Deployed Successfully!" -foregroundcolor Green}
2 {Write-host "Windows 2022 Standard VM called '$Name' Deployed Successfully!" -foregroundcolor Green}
3 {Write-host "Windows 2025 Standard VM called '$Name' Deployed Successfully!" -foregroundcolor Green}
4 {Write-Host "Windows 11 Enterprise VM called '$Name' Deployed Successfully!" -foregroundcolor Green}
}

By default, it’ll give 4GB of Memory, 2 CPU Cores and assign an Ethernet Adapter called “External” and create VMs under the E drive in a Hyper-V folder, creating a sub-folder for each VM you create.

All this can be customised within the code to do what you want.

Hope that helps.


Leave a Reply

More Posts

Exchange Management with AD Users when using RSAT for Windows 7

One of the little things with the have annoyed me since I’ve started using the RSAT tools in Windows is the fact that there is no easy way to manage Exchange. Sure I can install the Exchange Management Pack and use that, but like most admin’s AD Users and Computers is open just about all […]

How to Rename a SharePoint 2013 Content database name hosted on SQL Server

So I’ve been toying with SharePoint 2013 in my lab at home, doing the install and configuration at the moment, setting up my first Site after the initial configuration but noticed that I made a typo in the Database name.  So how do I go about fixing or renaming that database in SharePoint and in SQL […]

Getting a machine product name and serial number using WMIC for use with MDT or SCCM

Quick post today, I organise my driver folders into manufacturer and model and then use a task sequence to pick machine specific drivers. Getting the exact model name helps and one day to do that is via a WMI query. It’s a command I try to use quite a bit (and tend to forget the […]