Hyper-V ‘Quick Deploy’ VMs with Powershell & Differencing Disk

Creating VMs in Hyper-V the manual way is easy enough – lovely wizard, boot from ISO, install your OS, boot in, patch it up, be on your way. But it takes time I don’t have. It also takes tons of disk space, which I also don’t have (I’m running off a laptop’s SSD). How can we speed things up while slimming down? 

Hyper-V’s Shortcoming

I’ve been doing some work at home getting cozy with Hyper-V, and I’ve been wanting a quick way to deploy new VMs without having to install and patch up each OS before I can goof around. VMWare has Templates, but out of the box Hyper-V doesn’t quite have feature parity (unless you have System Center Virtual Machine Manager – and that’ll be a future lab project anyway).

Your best bet is to create a VM and export it, using the option built into Hyper-V Manager. This lets you save off a copy of the VHDX which you can make N copies of later, for more virtual machines. Yea, that does the job, but its slow to copy 9GB over and over, for several machines, like a sucker. It’s also wasteful — when you realize Hyper-V you can leverage a feature called differencing disks.

What’s a Differencing Disk?

Differencing disks are child objects that store changes from their parent, in the same way a snapshot (or Checkpoint, in Hyper-V speak) or differential backup would work. The differential disk starts small (~4MB), and grows dynamically as This also allows changes occurring within the child to be easily reversed. You can even chain multiple child disks together. Here’s the Microsoft documentation.

But the real win here is, I can base all of my VMs off the same read-only parent. This saves significant space, since I’m not duplicating 9GB of base Windows install over and over, and saves time since I’m not duplicat— you get it.

Getting Started

Step 1 – Create A Parent (The Template)

You’ll always have to do this at least once – go through the manual process described above for provisioning a new VM. You know the high-level steps:

  1. In Hyper-V Manager, create a New Virtual Machine, Gen 2, select your Windows ISO, create a new VHDX.
  2. Power on your new VM, boot from ISO.
  3. Install Windows, reboot into the OS.
  4. Edit Settings and remove the DVD device.
  5. Patch up Windows to your satisfaction using Windows Update.
  6. Run Sysprep and shut ‘er down
    1. Browse C:\Windows\System32\SysPrep – launch Sysprep.exe selecting Generalize, OOBE, Shutdown

Step 2 – Export the VM, Harvest its Disk

  1. In Hyper-V Manager, select your now powered-off VM. On the right Action menu, select Export, then choose a new location you’re going to store your templates in. (Probably a folder called Templates.) Click Export.
    1. 2017-02-18-15_52_57-hyper-v-manager
  2. When the Export completes, open up the folder you saved to. You will have a folder with the VM Name — within it you’ll have:
    1. Snapshots
    2. Virtual Hard Disks
    3. Virtual Machines
  3. Open the Virtual Hard Disks folder. Cut the VHDX out, browse up to the root of your Templates folder, and paste in that VHDX.
  4. Trash the rest of the VM-specific folder that was created inside Templates. You should be left with your folder called Templates with a VHDX inside, and nothing else.
  5. Rename your template something helpful – I’m calling mine “Windows Server 2016 Datacenter Full.vhdx”

Step 3 – VM Deploy Script

#2017-02-15 Matthew Fugel matthewfugel.wordpress.com
#Script to create a new VHDX differencing disk off a template (sysprepped) VHDX
#then create a new HYPERV VM using this new diff disk

$templatePath = "C:\Virtual Machines\Templates\Windows Server 2016 Datacenter Full.vhdx"
$VMFolderPath = "C:\Virtual Machines"
$vSwitch = "External"
$maxRAM = 2GB
$diffName = "Differencing Disk Initial Deployment"
$VMName = read-host "Please enter a VM Name to create"

#Set the parent VHDX as Read-Only
Set-ItemProperty -Path $templatePath -Name IsReadOnly -Value $true

#Create a folder for the new VM, check if exists.
If (Test-Path ($VMFolderPath + "\" + $VMName)){
 Write-host "FOLDER ALREADY EXISTS. EXITING."
 exit
 }
If ((Test-Path $templatePath) -eq $false){
 Write-host "COULDN'T FIND YOUR TEMPLATE. EXITING."
 exit
 }
$path = new-item $VMFolderPath\$VMName -ItemType Directory

#Create the Differencing Disk VHD
$VHD = New-VHD -Path ($path.FullName + "\" + $vmname + ".vhdx") -ParentPath $templatePath -Differencing

#Create the Virtual Machine; point to the Differential VHD
new-vm -Name $VMName -Path $VMFolderPath -VHDPath $VHD.Path -BootDevice VHD -Generation 2 -SwitchName $vSwitch | `
 Set-VMMemory -DynamicMemoryEnabled $true `
 -MaximumBytes $maxRAM -MinimumBytes 512MB -StartupBytes 1GB `

#Checkpoint the VM in case you want to roll it back to before its initial boot
Get-VM $VMName -ComputerName localhost | checkpoint-vm -SnapshotName $diffName

#Turn it up
Start-vm $VMName
#End.
  1. Copy the above script into the Powershell ISE, running as Administrator on your Hyper-V host.
  2. Update the variables at the top:
    1. $templatePath = where is your VHDX template we exported?
    2. $VMFolderPath = where will you keep all new VMs?
    3. $vSwitch = which vSwitch will you use? Create one if you haven’t already.
    4. $maxRAM = How much memory will you allocate to this VM?
    5. $diffName = If you want to modify the name of the checkpoint I create before I power on the new VM (just to have the option of rolling it back, though I could just as easily blow the VM away and redeploy with this script process. Options are cool.)
  3. Run it! Assuming everything checks out, you should end up with:
    1. Your VHDX template will be set Read-Only, for safety
    2. A new folder for VM, named accordingly
    3. A differential VHDX, named accordingly
    4. An AVHDX file, which is because of the checkpoint I create. Comment out that bit of the script if you don’t want this.
    5. A new VM in Hyper-V Manager, in Running status, completing its initial boot of Windows

2017-02-18-16_17_18-administrator_-windows-powershell-ise

Awesome! Let’s crank out some more…

The Results

2017-02-18-16_17_18-administrator_-windows-powershell-ise

I went on creating six of these Server 2016 Virtual Machines (four pictured); total disk space used: 20.8GB. Even better, each deploys in a couple of seconds.

Differencing disks are a great way to cut down on disk consumption in a Hyper-V deployment, and help get systems out the door very quickly. Next step will be to lay down some Desired State Configuration on top of these machines, for instance to have them rename themselves.

Advertisements

What would you like to say?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s