six demon bag

Wind, fire, all that kind of thing!

2013-01-28

Creating blank VMs for PXE boot

For a customer project I had to create a couple dozen virtual machines on our Hyper-V cluster. The machines were to be installed via a 3rd party software deployment system (the customer doesn't use SCCM), so I had to assign static MAC addresses and enable PXE boot. The respective reservations on the DHCP server had to be created from the MAC addresses in a second step, because the customer domain is separated from the infrastructure domain.


I used the following script for provisioning the VMs:

Import-Module virtualmachinemanager

$virtualnet = "VirtualAdapter"
$logicalnet = Get-SCLogicalNetwork "LogicalNetwork"
$macPool    = Get-SCMACAddressPool "Default MAC address pool"
$netsh_cmd  = "netsh dhcp server scope 192.168.23.0 " +
              "add reservedip {0} {1} {2}.example.com `"{3}`" DHCP"

function New-BlankVM {
  param (
    [string] $name,
    [string] $description,
    [int] $systemDiskSize,  # GB
    [int] $dataDiskSize,    # GB
    [string] $hwProfile,
    [string] $ip
  )

  $jobID        = [System.Guid]::NewGuid().ToString()
  $templateName = "Temporary Template $jobID"

  # add disks
  New-SCVirtualDiskDrive -JobGroup $jobID -IDE -Bus 0 -LUN 0 `
    -VirtualHardDiskSizeMB ($systemDiskSize * 1024) `
    -Dynamic -Filename "${name}_0" -VolumeType BootAndSystem
  New-SCVirtualDiskDrive -JobGroup $jobID -IDE -Bus 0 -LUN 1 `
    -VirtualHardDiskSizeMB ($dataDiskSize * 1024) `
    -Dynamic -Filename "${name}_1" -VolumeType None
  # create template from hardware profile
  $template = New-SCVMTemplate -JobGroup $jobID -Name $templateName `
    -HardwareProfile $hwProfile -NoCustomization
  # assign static mac address
  $mac = Grant-SCMACAddress -MACAddressPool $macPool `
    -VirtualNetworkAdapter $template.VirtualNetworkAdapters[0]
  $template.VirtualNetworkAdapters[0] `
    | Set-SCVirtualNetworkAdapter -PhysicalAddressType Static `
      -PhysicalAddress $mac -VirtualNetwork $virtualnet `
      -LogicalNetwork $logicalnet `
    | Out-Null

  # determine placement parameters
  $pref = Get-SCVMHost -VMHostGroup $hostgroup `
    | Get-SCVMHostRating -DiskSpaceGB ($systemDiskSize + $dataDiskSize) `
      -VMName $name -VMTemplate $template `
    | sort Rating -Desc | select -First 1
  $vmhost = Get-SCVMHost $pref.Name
  $path   = $pref.PreferredVolume

  # create VM
  $vm = New-SCVirtualMachine -JobGroup $jobID -Name $name -VMHost $vmhost `
    -Path $path -Template $template -Description $description

  # echo netsh command for creating the DHCP reservation
  $netsh_cmd -f ($ip, $mac.Address.Replace(":", ""), $name, $description)
}

New-BlankVM "foo" "Empty VM" 50 100 "PXE-Boot" 192.168.23.1
New-BlankVM "bar" "Empty VM" 50 100 "PXE-Boot" 192.168.23.2
# many more ...

The hardware profile for PXE boot already existed, so I simply used that. If required, a profile could also be created on the fly:

$hardwareProfile = New-SCHardwareProfile -Name "PXE-Boot" -HighlyAvailable $true `
  -BootOrder "PxeBoot", "CD", "IdeHardDrive", "Floppy"

New-BlankVM would then be called like this:

New-BlankVM "foo" "Empty VM" 50 100 $hardwareProfile.Name 192.168.23.1

In addition to creating the blank VMs the script prints netsh commands for creating the DHCP reservations to STDOUT. The output was redirected to a (batch-)file and copied to the customer's DHCP server, so that the reservations could be created in one go.

Posted 11:09 [permalink]