PowerShell Management Library for Hyper-V
I am always looking for tools to allow me to do more by doing less. Administering Hyper-V with PowerShell can be tedious. James O’Neill’s PowerShell Management Library for Hyper-V is a great tool to improve automation of Hyper-V management using PowerShell.
As a tester, I am constantly creating new environments, installing our product, taking snapshots, ect. Doing this by hand is a waste of time in my opinion. Doing this with a script makes life easier and frees up my time.
Typically, I prefer to create is to create one VM and to have other VMs inherit from that base image. My second VM (the first child to inherit from the base), I will install daily builds of our product. I will then create a third child, which I use a sandbox. I can easily delete it and recreate as needed without having to install our product over again. I have not consistently found success with using snapshots, so I prefer to use differencing disks. The examples below use differencing disks.
This first code block shows how I am using the PowerShell management library to simply the creation of a base VM. There is nothing magic about it. It’s pretty strait-forward. I create a VM, give it a name, set the CPU count, memory size, network adapters, hard drive, and DVD drive.
$server = "my-dev-server" $vmName = "TestParentVM" $vmVirtualSwitch = "My Virtual Network" # create a new virtual machine $vm = New-VM $vmName -server $server # set cpu count Set-VMCPUCount $vm 2 -server $server # set memory size Set-VMMemory $vm 2 -memory 4GB -server $server # add a legacy network adapter Add-VMNIC -vm $vm -VirtualSwitch $vmVirtualSwitch -legacy # add a default VMBus (non-legacy) network adapter Add-VMNIC -vm $vm -VirtualSwitch $vmVirtualSwitch # add the hard drive to the VM Add-VMNewHardDisk –vm $vm -controllerID 0 -lun 0 -vhdpath "$(get-VHDdefaultPath)\$vmName.vhd" -size 20GB # add the DVD with bootup ISO Add-VMDRIVE –vm $vm 1 1 -server $server -DVD Write-Host "Operation complete."
The next code block will create a differencing disk pointing to the parent created in the previous example. I create the usual, VM, CPU count, ect. What makes this a differencing disk is how the VHD is created by specifying the parent. I do some cleanup in this routine by deleting any previously created VMs or VHDs, and I loop through the creation a failure preventative.
$server = "my-dev-server" $vmName = "TestChildVM" $vmParent = "TestParentVM" $vmVirtualSwitch = "My Virtual Network" #region functions - feel free to move to a separate file Function DeleteVhd { Param ($pathToVhd) # delete the disk that was added if it exists if (test-path -path $pathToVhd) { Remove-Item -Path $pathToVhd -Force } } #endregion # delete the VHD if it already exists DeleteVhd "$(get-VHDdefaultPath)\$vmName.vhd" # delete the VM if it already exists Remove-VM -vm $vmName -server $server # create a new virtual machine $vm = New-VM $vmName -server $server # get the vm $vm = Get-VM $vmName # set cpu count Set-VMCPUCount $vm 2 -server $server # set memory size Set-VMMemory $vm 2 -memory 4GB -server $server # get VM Nics available $vmNics = Get-VMNic -server $server -vmbus -legacy $vmNicSwitchList = New-Object System.Collections.ArrayList # get VM Nic Switch available for each VM Nic and add it to our list foreach ($vmNic in $vmNics) { $vmSwitchElementName = (Get-VMNicSwitch $vmNic).ElementName if ($vmNicSwitchList.Contains($vmSwitchElementName) -ne $true) { $vmNicSwitchList.Add($vmSwitchElementName) } } # Use the first available VM Nic Switch - this assumes # I do not create more than on per each environment. if ($vmNicSwitchList.Count -gt 0) { $vmVirtualSwitch = $vmNicSwitchList[0] } # add a legacy network adapter Add-VMNIC -vm $vm -VirtualSwitch $vmVirtualSwitch -legacy # add a default VMBus (non-legacy) network adapter Add-VMNIC -vm $vm -VirtualSwitch $vmVirtualSwitch # add the hard drive to the VM $parent = "$(get-VHDdefaultPath)\$vmParent.vhd" $vhdPath = "$(get-VHDdefaultPath)\$vmName.vhd" Add-VMNewHardDisk –vm $vm -controllerID 0 -lun 0 -vhdpath $vhdPath -parent $parent # get the VM to see if a disk is attached to it, if it is not, then it failed $disks = Get-VMDisk -vm $vm $count = 1 # if the disk was not successfully added, try and add it again while ($disks -eq $null -and $count -le 5) { Write-Host "RETRY $count - The disk was not properly added. Attempting to retry." # delete the disk that was added DeleteVhd "$(get-VHDdefaultPath)\$vmName.vhd" Add-VMNewHardDisk –vm $vm -controllerID 0 -lun 0 -vhdpath $vhdPath -parent $parent $disks = Get-VMDisk -vm $vm $count++ } if ($disks -eq $null) { Write-Host "Operation failed to create this virtual machine. Contact an admin." } else { Write-Host "Operation completed successfully. Attempting to start the VM." Start-VM -vm $vm -wait }
I have found that the VM creation is not consistently successful on the first pass, so I have added the while loop. Since adding that, I have not had any issues.
I hope these help. They should be easy to change if you prefer snapshots versus differencing disks. Thanks to James O’Neill for creating this library. It makes administering Hyper-V much easier. It is available via CodePlex, where the latest release, updates, and forum support can be found.


