I do a reasonable amount of demo’ing, mostly of SharePoint (!) and grew tired of either (a) starting and stopping VMs manually (b) using VM auto-start functionality in Hyper-V and having to stop VMs when I don’t need them.
I have used a PowerShell script for a while now that I knocked up that lets me start and stop my virtual machine guests but it was flawed as it relied on a ‘sleep’ statement to simply pause the script for a (longer than actually reasonably necessary to allow for anomalies) period of time.
With this approach I would, on occasion, have issues caused by VMs tripping up during VM startup if other machines on which they had a dependancy took longer than expected to start.
Using the Virtualization namespace in WMI we can determine if a virtual machine guest is running, but we can’t actually test if the running machine is actually spun up (i.e. Windows is loaded, services running, etc.) or simply in a “switched on” state. Which is kind of annoying, especially if a VM takes a long time (such as DC’s sometimes do) to spin up into a fully operational state.
I figured there would be a better way to determine if a VM was started and running and I ended up with two options:
- Use a Get-Service call to look for running services (such as SQL Server or SharePoint timer service)
- Look deeper into the namespace for additional information I could use
The Get-Service option is viable, but requires authentication (VMs run within their own domain context to which the host is not joined) and relies on other Windows bits (such as RPC) that I have very little control over so was relegated to plan-b status.
Sniffing around in WMI let me find some deeper information available within the Virtualization namespace contained within “KVPExchangeComponent”. Which at first glance seemed to offer some possibility.
A little google-binging led to me to understand that these ExchangeComponent objects pertain to information that is exchanged between the host server and the guest VMs allowing the host to ascertain information about the guest VMs from within the VMs themselves – exactly what I wanted to do.
Although basic, the information available within ExchangeComponent provided means to retreive the IP address of the guest – something we can reasonably utilise as a test of running state for a VM, but more importantly provided access to the RDP IP address which would relate to a service that would be starting relatively late in the spin-up process, an ideal test of VM readiness in the context of demo/development machine.
How does the startup script work? Pretty simple actually:
- collect the list of guests to start as $args
- get the VM details from WMI
- call a state change of the current VM from Stopped (3) to Running (2)
- wait until we can query the RDP IP address of the machine
- move onto the next VM
I have used a nice filter (single purpose script block) that is from Ben Armstrong (@virtualpcguy) to parse the XML provided by the WMI query – handy for other things so worth taking the time to look over it and understand what it does.
And the shutdown script? Again, pretty simple:
- collect the list of guests to stop as $args
- get the vm details from WMI
- call a shutdown on the current VM
- wait until the state of the machine is changed to Stopped (3)
- move onto the next VM
I’ve not put lots of best practice error handling in, I may do this in the future.
I’ve tested this 100+ times with different combinations of VMs on my hosts and it never fails, but we do, every now and then, get an error thrown with regards to the WMI query that looks for the IP address as if this query is running prior to the VM actually being in a started state then the ExchangeComponent objects are not available. I should probably put something in to handle this a little better, but the error is non-fatal and just slightly annoying if it happens 🙂
As always, the usual caveats apply, no warranty etc. and don’t forget to test, test, test!
The script can be found here.
more to follow…