During my presentations at TechEd this year, I spoke about a somewhat rarely used and somewhat unknown feature of System Center Virtual Machine Manager known as Rapid Provisioning. The feature isn't well known for a couple of reasons:
- It’s not available in the GUI – you can only access it from PowerShell.
- It’s not referred to as Rapid Provisioning from within PowerShell.
As such, generally the only people using Rapid Provisioning are those who had the feature demo’d to them by someone else, or who stumbled upon the feature while reading a blog post or doing some thorough documentation reading.
So what is it?
In short, Rapid Provisioning allows you to deploy a virtual machine using Virtual Machine Manager with all of the goodness that VMM provides (Hardware Profile, Guest OS Profile, templates), without the need of waiting for Virtual Machine Manager to do a BITS copy of the Virtual Machine from the VMM Library to the Hyper-V host, which can take awhile, and put unnecessary IO loads on your storage and network.
So how does it work?
Basically, you'd do everything identically to the way you normally do when you create a new VM, except you add one cmdlet: Move-VirtualHardDisk. This cmdlet tells VMM to not actually do the file copy, but to instead use the existing destination VHD already on the Hyper-V host. You might be asking, "Why is the cmdlet called Move-VirtualHardDisk, when it's not moving anything?" That's a good question, and one that I can't actually answer. Not everyone names their cmdlets intuitively. A better answer would probably be that it's meant to signify that you're moving a new Virtual Hard Disk into your deployment job in place of the blank VHD which was specified in the template. So you aren't actually moving a VHD across storage, but within the VMM job space.
So how does the VHD actually get to the destination?
That's up to you. There are a few ways you can accomplish the task. You can:
- Use a SAN snapshot or similar hardware solutoin to present the VHD to Hyper-V
- Use something like Virsto to present the VHD to Hyper-V.
- Manually copy the VHD from local storage to your destination location on Hyper-V (this still has the added benefit of keeping traffic off of the network).
Here's an example of a deployment script end to end.
function create-newdemoVM
{
param($vmname, $csv, $vmnumber, $CPU, $RAM)
$VMMServer = Get-VMMServer "MYVMMSERVER"
$JobGroupID = [Guid]::NewGuid().ToString()
$Template = Get-Template | where {$_.Name -eq "2K8R2_SP1_GOLD"}
$VMHost = Get-VMHost | where {$_.ComputerName -eq "MY_HYPER-V_SERVER"}
Move-VirtualHardDisk -IDE -BUS 0 -LUN 0 -Path "c:\clusterstorage\$CSV\$vmnumber\AIT_R2_SP1_ENT.vhd" -JobGroup $JobGroupID
New-VirtualNetworkAdapter -VirtualNetwork "Guest" -VLanEnabled $false -Synthetic -JobGroup $JobGroupID
$VM = New-VM -Name $VMName -Path "c:\clusterstorage\$CSV\$vmnumber" -CPUCount $CPU -MemoryMB $RAM -Template $Template -VMHost $VMHost -ComputerName $VMName -JobGroup $JobGroupID -UseLocalVirtualHardDisks -RunAsynchronously -JobVariable "NewVMJob" -SkipInstallVirtualizationGuestServices -FullName "Joe User" -OrgName "Acme"
}
Let's walk this little function one line at a time. First:
param($vmname, $csv, $vmnumber, $CPU, $RAM)
Here, we're simply telling the function that we'll be calling five parameters:
* VMname - the name of the VM, both at the Hyper-V/VMM level, and inside the guest OS
* CSV - in this case, we're using a Cluster Shared Volume, and parameters specifies the name of the CSV from the C:\ClusterStorage path
* VMNumber - in this example, we have a numbered folder within the CSV - for example C:\ClusterStorage\MYCSV1\3\
* CPU - Simply passing the number of CPUs we'd like the VM to have (overriding the template setting)
* RAM - Passing the number of RAM we'd like the VM to have (overriding the temlpate setting)
Next, we set the Virtual Machine Manager server:
$VMMServer = Get-VMMServer "MYVMMSERVER"
Here, we create a new randomly generated GUID with which we can group all of the tasks together.
$JobGroupID = [Guid]::NewGuid().ToString()
The job grabs our existing template from the library where we store our W2K8R2SP1 gold image settings, inluding the Unattend file for the Sysprepped image.
$Template = Get-Template | where {$_.Name -eq "2K8R2_SP1_GOLD"}
In this step, I'm calling a specific server where I want to place the VM. Theoretically, I could use VMM Intelligent Placement here, but for simplicity's sake, I'm hard coding the destination server.
$VMHost = Get-VMHost | where {$_.ComputerName -eq "MY_HYPER-V_SERVER"}
This line is where the magic happens:
Move-VirtualHardDisk -IDE -BUS 0 -LUN 0 -Path "c:\clusterstorage\$CSV\$vmnumber\AIT_R2_SP1_ENT.vhd" -JobGroup $JobGroupID
I'm specifying that the VHD located on BUS 0 LUN 0 should be mapped the path on the destination server instead of the VHD from the VMM Library.
One last housekeeping item - I need to attach a NIC from my Guest network:
New-VirtualNetworkAdapter -VirtualNetwork "Guest" -VLanEnabled $false -Synthetic -JobGroup $JobGroupID
And finally, the one line to create the VM itself:
$VM = New-VM -Name $VMName -Path "c:\clusterstorage\$CSV\$vmnumber" -CPUCount $CPU -MemoryMB $RAM -Template $Template -VMHost $VMHost -ComputerName $VMName -JobGroup $JobGroupID -UseLocalVirtualHardDisks -RunAsynchronously -JobVariable "NewVMJob" -SkipInstallVirtualizationGuestServices -FullName "Joe User" -OrgName "Acme"
So that's rapid provisioning in a nutshell. If you're interested in learning more, here's some more information from TechNet.
Feel free to leave a comment below or hit me via Twitter if you have any questions.
Good luck, and happy virtualizing!