Summary: Microsoft Scripting Guy, Ed Wilson, talks about using a Windows PowerShell workflow to ensure that virtual machines start in order and stabilize.
Microsoft Scripting Guy, Ed Wilson, is here. Last month, I wrote the following blog post: Use PowerShell to Start or Stop Virtual Machines in Order. The workflow worked great. The problem is that some of the virtual machines take a while to stabilize after they are running. This means that when I start virtual machines in a specific order, there needs to be a bit of a delay from the time the virtual machine is running to the time that I can sign in or connect to it from a remote machine.
I spent a lot of time working on a modification to the script. After I finished my script, I sent it to some people on the Windows PowerShell team to see if I was on the right track. Although my script worked great, it was…well…somewhat of a FrankenScript. I thought the code was confusing and downright ugly.
In a few minutes, Lee Holmes had cleaned up the script by simplifying it dramatically.
The main problem with my previous script is that when a virtual machine starts, it takes a while (depending on the machine) before it is actually usable. However, as far as Start-VM and the Windows PowerShell workflow are concerned, when the virtual machine is started, the particular activity is completed.
In my playing around, I noticed that there is a property called Heartbeat from the virtual machine object. If it has a value of OkApplicationsHealthy, the virtual machine is perfectly usable.
Note This value is not present on a virtual machine running Windows 7 unless Virtual Machine Integration Services is updated to the latest bits.
To check for changes to the Heartbeat property, I need to do a bit of polling. However, directly inside a Windows PowerShell workflow, I cannot use a While loop. So I solved the problem by using an InlineScript activity.
This creates a new problem due to variable scoping. I had to solve that problem by using the $Using directive., and then things really get ugly. Here is the code I wrote:
InlineScript { while (
(Get-VM -Name $using:dc1).Heartbeat -ne 'OkApplicationsHealthy')
{ "$using:dc1 not ready…"; sleep 1}}
Like I said, it worked, but it was pretty ugly. What Lee did instead, was create a function inside the Windows PowerShell workflow. It is nice and elegant.
The other thing I had done in my workflow was use Sequence because I wanted the virtual machines to start in a specific order. Lee suggested that it would be simpler to create an array and iterate over the array. Again, the code is cleaner.
That represents the changes to my script, and here is the complete current script:
workflow Start-ScenarioVM
{
function Wait-VM
{
param($Name)
while((Get-VM -Name $Name).HeartBeat -ne 'OkApplicationsHealthy')
{
Start-Sleep -Seconds 1
Write-Verbose "$name not ready. Waiting"
}
}
foreach($vm in 'dc1_nwt', 's1_nwt', 's2_nwt', 'c1_nwt')
{
Start-VM -Name $vm
Wait-VM -Name $vm
}
}
Start-ScenarioVM
When I run the workflow, I see that the script pauses on the Wait-VM function in my status bar. This indicates that I am polling for a specific virtual machine. After the virtual machine starts, the script starts the next virtual machine, and once again, it will wait.
That is all there is to using Windows PowerShell workflow to start virtual machines in order. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
Why the Heartbeat propery of my VMs never become OkApplicationsHealthy but only OkApplicationsUnknown?