Wednesday, 5 November 2014

Powershell script to bring up Hyper-V VMs Slowly enough that they function

The below Powershell script is something I wrote out of frustration while on an Exchange Messaging course to try to improve my mood. The Hyper-V VMs we were starting for each lab took an absolute age to load up and become responsive after we reverted their state at the end of each lab. This script attempts to start machines one after another with a configurable gap in between, the idea being you could set the $vms array to the machines you want started then wander off for a bit of a break then hopefully when you return the VMs would have loaded and be responsive.

You may ask why wouldn't you just start them all together, well the machines that were running the VMs were not up to spec and each of the VMs seemed to be based off of a single VM using dereferenced disks which severely impacted performance. The VMs took so long to load that Services on each of them often failed to start because of timeouts.

I thought I would share in the hope it may save someone else pulling their hair out.

# Machines to start in order to start
$vms = "20342B-LON-DC1", "20342B-LON-CAS1", "20342B-LON-MBX1", "20342B-LON-CL1", "20342B-LON-CL2" , "20342B-LON-LY1"
# minimum uptime in seconds to check for before starting next machine
$delaytime = 45
Function StartVM
 {
     param ($Name)
     $vmquery = get-vm $Name
     if ($vmquery.state -eq "off")
     {
        Write-Host " not running, starting" -NoNewline
        start-vm $Name
        $vmquery = get-vm $Name
     }
     elseif ($vmquery.state -eq "Running")
     {
        Write-Host " already running" -NoNewline
     }
     While ($vmquery.uptime.TotalSeconds -lt  $delaytime) { $vmquery = get-vm $Name; sleep 2 ; Write-Host . -NoNewline }  
     write-host " uptime is "-nonewline
     write-host $vmquery.uptime.TotalSeconds -NoNewline
     write-host " seconds, over $delaytime so assumed to be up and running."
}
foreach ($vm in $vms) {
    write-host "Checking $vm... " -NoNewline
    StartVM $vm 
}
write-host "If $delaytime seconds was long enough your VMs should be functioning now."


I am still on the course studying for 70-341: Core solutions of Microsoft Exchange Server 2013 and 70-342: Advanced Solutions of Microsoft Exchange Server 2013, So I may well update the script as I run more labs. Ideally I would like to improve the script so it waits until the started VM is "responding" before starting the next one but this has proved difficult, if you have any suggestions please let me know.

Update: 06/02/2015, I have improved the script a little, it now copes better with machines being started from other sources or if the script is restarted and the times are in seconds as the latest tests I have endured have been on lab machines using SSDs which significantly improves performance.