Q. How can I stop virtual machines (VMs) in a set order, with VMs only stopped once the previous VM has completed shutdown?

A. There are several ways to achieve the ordered shutdown, start, and other actions of VMs, such as Opalis. However, I wanted something that focused on shutting down VMs in a set order, with the ability for certain VMs to shut down together, and only moving on to the next VMs once the complete group had shut down. This is useful when you have dependencies between VMs. For example, in my environment I need to shutdown the VMs in a set order:

Client VMs -> RDS servers (like connection broker, session host) -> System Center servers -> SQL server -> Exchange Server -> domain controllers

I created a simple program that takes a configuration file as input, and I'll also have a start program released by the time this FAQ is published that will be a separate FAQ. Because a shared configuration file is used and this is shutdown, my method works backwards through the file—so you should list the configuration file with the VM to start first at the top, working down. Basically, the VM you want to stop first needs to be at the bottom.

Below is my configuration file (vmlist.txt)












Notice I have some blank lines. A blank line means a new group—the utility can be told to handle VMs as groups, where it will stop all the VMs in a group at the same time. Only after all of the VMs in the group have stopped will it move onto the next group. In my example file, it would stop savdalclient2-4. Once they're all stopped, it would stop savdalclient. Once that's stopped, it will stop savdalsm01 and savdalsmdw01, and so on. It performs a shutdown using the integration services, and if the VM doesn't stop within the configured time limit (the first number), it sends a turn off.

The second number is the time to allow to start (this setting will be used in the start utility) and the third number tells it that if it's not stopped in the time limit, perform a turn off (a 1 indicates yes, turn off, and with a 0 it wouldn't do anything—just leave it and move on to the next VM or group)

The first part is the name of the VM, and it must exactly match the name of the VM in Hyper-V manager. The second is the Hyper-V server.

<VM Name>|<Hyper-V Server FQDN>|<stop time out>|<start time out>|<turn off on shutdown timeout>

You need to ensure that RemoteAdmin for WMI is enabled on the Hyper-V server and you that have WMI permissions. Run

netsh firewall set service RemoteAdmin enable

on the remote machine to enable remote WMI. Also, be sure the right WMI security permissions are set by using the Computer Management application. Navigate to Services and Applications then WMI Control. Under Root, Security make sure you have Remote Enable for users who'll be using the tool on remote Hyper-V servers.

To use this, just pass the name of the configuration file, 1 to use group logic or 0 to stop VMs one at a time, then the final number is the feedback—1 for silent, 2 for normal and 3 to also create a dump file of the amount of time it took to stop each VM to file savtechvminfo_<name of host you run command from>.log:

stopvms.exe <configuration file> <group logic use: 0 no, 1 yes> <feedback level: 1 silent, 2 normal, 3 also log file>, e.g.
Stopvms.exe vmlist.txt 1 2

You can download the EXE by clicking here. Here's a video of it in action:

Help and details of future updates and feedback are available on my site.

I'll be releasing a start utility in addition to a GUI to manage the configuration file and some basic workflows over the next few months.

To help create the list of VMs you can modify the script in FAQ "Q. How can I quickly create a list of all VMs on a list of Hyper-V servers from the command line?" and change the writeline section of code to not have state and instead just end with |60|60|1, e.g.

' listvms.vbs
' John Savill 5/19/2011
For count = 0 To (WScript.Arguments.Count-1)
strHVServer = WScript.Arguments.Item(count)
Set objWMIService = GetObject("winmgmts:\\" & strHVServer & "\root\virtualization")
Set arrVMs = objWMIService.ExecQuery("SELECT * FROM Msvm_ComputerSystem",,48)
For Each VM In arrVMs
WScript.StdOut.WriteLine VM.ElementName & "|" & strHVServer & "|60|60|1"

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.