Programmatically Detecting when a VM Changes State

Every now and then I get asked how to detect whenever a virtual machine changes state.  Usually, people who ask about this have written some code that periodically queries Hyper-V to see what state different virtual machines are in (stopped, running, etc.).  What they find is that this is not efficient – and it sometimes misses a virtual machine that has quickly changed state (e.g. stopped and started again).

Luckily, there is a way to be notified of virtual machine state changes without polling for information.

To do this – you want to use WMI instance modification events:

 # WMI Query that specifies what events we will watch for
 $Query = "Select * from __InstanceModificationEvent within 3 where TargetInstance ISA 'MSVM_ComputerSystem' `
           and TargetInstance.EnabledState <> PreviousInstance.EnabledState"
 # Script block that will run whenever the event fires
 [ScriptBlock]$Action = {
    $VMName = $Event.SourceEventArgs.NewEvent.TargetInstance.ElementName
    switch ($Event.SourceEventArgs.NewEvent.TargetInstance.EnabledState)
         2 {$vmState = "running"}
         3 {$vmState = "turned off"}
         9 {$vmState = "paused"}
         6 {$vmState = "in a saved state"}
         10 {$vmState = "starting"}
         4 {$vmState = "stopping"}
         default {$vmState = "in an unknown state..."}
    if ($Event.SourceEventArgs.NewEvent.TargetInstance.EnabledState -eq 1)
       {$vmState = $Event.SourceEventArgs.NewEvent.TargetInstance.OtherEnabledState}
    write-host "The virtual machine '$($vmName)' is now $($vmState)."}
 # Register for the events
 Register-WMIEvent -Query $Query -Action $Action -Namespace root\virtualization\v2
 # To clean up - run "Get-EventSubscriber | Unregister-Event"

This code will print out a message whenever a virtual machine changes state.