Automating new VM's in Hyper-V or "How I saved a bunch of time by switching to powershell automation"

When studying for certifications while also trying to maintain a healthy home and work life, time is often a limiting factor. When you only have a very small fraction of your week to construct and configure your lab environment, automation can be a life-saver. Enter automating Hyper-V virtual machine creation.

My end goal was to have a web app that would take inputs of some parameters and then create a VM based on those. Realizing I was way in over my head with web dev skills lacking, I settled on a powershell GUI script instead.

I started with a small script that would create a VM from a powershell console:

$DCName = read-host "Server Name"
$VHDPath = "C:\VM\$DCName\$DCName.vhdx"
new-vm -MemoryStartupBytes 2GB -Generation 2 -NoVHD -Name $DCName
Set-VM -name $DCName -ProcessorCount 2
New-VHD -Path $VHDPath -Parentpath "C:\VM\WinSrv2012R2\WinSrv2012Temp\WinSrv2012R2.vhdx" -Differencing
Add-VMNetworkAdapter -VMname $DCName
Get-vm $DCname | Add-VMHardDiskDrive -controllertype SCSI -controllernumber 0 -Path $VHDPath
$vmharddiskdrive = Get-VMHardDiskDrive -VMName "$DCName"
Set-VMFirmware "$DCName" -FirstBootDevice $vmharddiskdrive



This script would prompt for a name, then create a new VM with the name input in the first line, attach a new VHDX hard drive as a differencing based on my vanilla Windows Server 2012 R2 install I created previously. Every so often, I'll boot that disk up and run updates and patches. Using the differencing disk like this really reduces the time it takes to deploy a VM since most of the admin work is already complete. You could take this one step further and create sysprepped parent disks with server roles pre-installed and just set a variable for that.

Unsatisfied that I would have to run a separate script for each OS configuration for Windows 7, Windows 10, Windows Server 2012 and Windows Server 2016, I scoured Microsoft blogs for info about creating XAML GUI in powershell. I landed on a nice tool called POSHGUI. It was perfect for quickly throwing together a workable UI without too much fuss with trying to extract the code from a project in Visual Studio. I ended up writing several scripts. One for each OS, for each of my 2 Hyper-V hosts (I hope to someday consolidate this all into one script running from a single server instance with a service account). I ended up with a gui that looks something like the following.


Each box is saved to a variable of the respective name. When clicking "build", the code parses the value of $Subnet_Value and determines which hyper-v host to build on. It looks something like the following (tacked on to the end of the GUI tool):

function BUILD_VM {
if ($Subnet_Value.Text -like "*Internal*") {
$VMNAME_Value.text,$CPU_Value.text,$RAM_Value.text,$Subnet_value.Text,$OS_Value.Text | Out-file -filepath "\\contoso.com\share\Primary\it\VMConfig\Host1VMConfig.txt"
}
else {
$VMNAME_Value.text,$CPU_Value.text,$RAM_Value.text,$Subnet_value.Text,$OS_Value.Text | Out-file -filepath "\\contoso.com\share\Primary\it\VMConfig\Host2vmconfig.txt"
}
}


The build tool generates a text formated config file and places it on the DFS share in a spot where the Hyper-V hosts (running a filewatcher script) are looking for their respective build files by name. Once the filewatcher picks up. Based on which network is picked, the file is named accordingly and the VM is placed on the correct VSwitch. Then the value in $OS_value determines which template disk to use as a differencing disk.

So after all is said and done, using this tool to build up VM's has drastically reduced the time it takes to create my environment. I hope to go a step further later on and have entire "packs" of VMs generated based on what services I want running. For instance, if I want a new Site, I can define the site name, the subnet IP values, and have the scripts create a new VSwitch, a new DC, a new DHCP server, a new FS server and a couple workstations with all the correct services up and running within a few minutes. For now, this current setup saves me quite a bit of time over having to install the OS manually each time.


Comments

Popular posts from this blog

Creating Ubuntu Bedrock Minecraft image with Docker

Automating VM creation with DSC in Azure.

Intro to Kubernetes Series - Part 2 - Stepping it up to Kubernetes