Skip to main content

Create a batch of VMs with PowerShell script

Author: Michael Niehaus, Director, Windows Commercial Product Marketing

When I first started in IT, I worked with a team of people to do very repetitive tasks as a DBA. Fortunately, a few of those people had the right idea – with enough automation, we can eliminate the need for our jobs. Now that might sound like a career mistake, but what you quickly realize is that if you get rid of the mundane, you can move on to something more interesting – and there’s always something more interesting. After a few years, we were to that point, and then we started bringing order to PCs.

Fast forward a few years and the same idea was applied to MDT – there’s no such thing as too much automation. And even now, I still have to remind myself of that.

Case in point: I needed to do some larger-scale testing, which is great with virtual machines. And because it’s very simple to create fully-functional VMs from a ready-to-go, patched VHDX file using PowerShell, I created those VMs in just a few minutes and let them churn for a while after they started out. But it seemed like “too much work” to also automate the configuration of those VMs – all I needed to do after all was rename and join a domain. But instead of a little more PowerShell to inject a configured unattend.xml into each VM, I thought, “No, I’ll do it manually later.” Well, that was a bad idea – I spent hours configuring the VMs, connecting to each one, completing OOBE, logging in with a local account, opening up the computer settings, changing the computer name, joining the domain, and rebooting. All because I didn’t want to spend an hour or so on a little more scripting.

In any case, I thought someone might be interested in the PowerShell script to create a batch of VMs, which I cobbled together from various other samples on the web:

$parentpath = "E:\VMs\10240.x64.ClientBase.vhdx"
$path = "E:\VMs\"

foreach ($i in 1..20)
$suffix = $i.ToString("000")
$vmname = "CLONE-$suffix"

#create a VHDX – differencing format
$vhdpath = "$path\$vmname Disk 0.vhdx"
New-VHD -ParentPath $parentpath -Differencing -Path $vhdpath

#Create the VM
New-VM -VHDPath "$vhdpath" -Name $vmname -Path "$path" -SwitchName "Lab" -Generation 2

#Configure Dynamic Memory
Set-VMMemory -VMName $vmname -DynamicMemoryEnabled $True -MaximumBytes 2GB -MinimumBytes 1GB -StartupBytes 1GB

#Start the VM
Start-VM $vmname

You might need to tweak it (with proper paths, the name of your Hyper-V network switch, and so on). But that’s the easy part. Next time, I’ll add the logic to inject an unattend.xml to automate OOBE, name the computer, and join the AD domain...

Michael NiehausMichael Niehaus is a Director of Product Marketing with the Windows Commercial team at Microsoft, responsible for helping enterprise IT pros with Windows deployment and manageability needs. Prior to joining the Windows Commercial team, Michael was a longtime program manager and developer for the Microsoft Deployment Toolkit, having joined Microsoft in 2004 after spending 14 years working in enterprise IT.