Entries in PowerShell (2)

Friday
Jun032011

Download all of the TechEd videos via PowerShell - and even play them on iOS!

As I mentioned last week, I own a variety of devices on both the PC and Mac/iOS sides of the fence. When travelling, my preferred content consumption device far and away above all other devices is the iPad. That's why I was excicted to see that this awesome script by PowerShell MVP Marco Shaw could be modified with a simple find and replace to swap out all of the "WMV" references with "MP4", and it flawlessly downloaded the whole TechEd repository to be drug over to my iPad right before I leave for vacation!

Many thanks to the folks at TechEd, the PowerShell team, and Marco for setting me up with my in-flight entertainment on this trip!

One gotcha for the those less seasoned in PowerShell - on the line:

  try {Import-Module -Name OData -ErrorAction "Stop"}

You will likely need to point PowerShell to the path of the OData provider referenced in the post, or you'll get an error.

For example:

Import-Module .\MyModule\OData.psm1

or

Import-Module c:\users\myuser\MyModule\OData.psm1

Good luck, and happy viewing!

Monday
May302011

Rapid Provisioning with System Center Virtual Machine Manager

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!