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…
I appreciate, result in I discovered just what I was taking a look for.
You’ve ended my 4 day long hunt! God Bless you man. Have a great day. Bye
Here is my webpage :: Annette
Very nice! Thanks for this! I modded it slightly to import a txt file for the vm name list rather than supplying them as arguments to the function. However I am getting an odd file in the same folder where I run the script to start VM’s that is called OUT-NULL (no extension) and the contents are:
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 2
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
Job : MyServerNamerootvirtualization:Msvm_ConcreteJob.InstanceID=”04C
D4C43-F748-4509-ACB1-74866F4E777E”
ReturnValue : 4096
PSComputerName :
Both the shutdown and startup scripts work flawlessly however.
Hi, your script fails to work on a Version 2 Hyper-v aka Windows 8.1 or Windows Server 2012 R2. The wmi namespace is changed. I found this using the Powershell scripomatic http://technet.microsoft.com/en-us/library/ff730935. It can be fixed by search & replace “rootvirtualization” to “rootvirtualizationv2“.
Regards, Bart
Hey Bart
Agreed that the namespace is new but don’t forget there are a bunch of new cmdlets which support the start and stop of Hyper-V in Windows 8/2012 natively.
Thanks for stopping by!
Seb
Hi,
I work on PowerShell V2.I have been trying to start a VM from Start-VM command commonly found code on technet and blogs, the command executes from my active directory server but fails to complete without displaying any error and with no result in change in state of the VM. I am not able to access your code due to some access issues in our environment. Can u pls send me a code snppet for the same or provide some solution for the problem I am facing.
Thanks,
Akansha
Hi Akansha
Thanks for stopping by.
If I am understanding you correctly the issue you are seeing with Start-VM is that it is not provided for PowerShell v2, it only became available in PowerShell v3.
The link to the code snippet I have here should provide you what you need for V2.
Thanks
Seb
Hi there! I’m at work browsing your blog from my new iphone 3gs!
Just wanted to say I love reading your blog and look forward to all
your posts! Keep up the superb work!
Hey I know this is off topic bbut I was wondering if you knew of any
widgets I could addd to my blog that automatically
tweet my newest twitter updates. I’ve been looking for
a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this.
Please let me know if you run into anything.
I truly enjoy reading your blog and I look forward to your new updates.
Hello Seb,
first of all: great post, thank you so much!
This will save me MUCH time in the morning… 🙂
There only two tiny remarks from a noobie like me. 🙂
1) Bart had a little typo, he meant:
“… It can be fixed by search & replace
“rootvirtualization” to “rootvirtualizationv2“. ”
2) I wasn’t able to pass the parameters of the function “Start-HyperVGuests”. I tried everything like
Start-HyperVGuests @(‘machine1’, ‘machine2’, ‘machine3’)
I didn’t work ($args was empty). So I use an additional variable. Simply change the last two lines to:
# to start guests, simply change the list of guest names IN THE ORDER YOU WANT THEM TO STARTUP:
$args2 = @(‘machine1’, ‘machine2’, ‘machine3’)
Start-HyperVGuests
And change line 25 to
foreach ($machine2start in $args2) {
Seb, please correct me about no #2 if I am wrong.
Greets
Thomas