Learn about Windows PowerShell
Summary: Guest Blogger Trevor Sullivan shows how to monitor and to respond to Windows Power events using Windows PowerShell.
Microsoft Scripting Guy Ed Wilson here. Today’s guest blogger is Trevor Sullivan, and he has a fascinating article about responding to power management events. First, a little bit about Trevor.
Trevor Sullivan is a passionate, experienced, and Microsoft-certified IT pro with more than seven years in the industry. Although he is interested in nearly all Microsoft technologies, his primary specialties include:
Trevor is a Microsoft-recognized Community Contributor (MCC) and is active in several online communities:
One of his major achievements is the development and public release of an open-source Windows PowerShell module called PowerEvents. During his personal time, he enjoys studying theology, spending time with his girlfriend, being outdoors, shooting photos, playing video games, testing software, and learning about all sorts of new things.
Take it away, Trevor!
Oftentimes, people want to be able to respond to events automatically on their computers: “When <X> happens, I want <Y> to happen in response.” An example of this might be: “If SomeProcess.exe exceeds 50 percent processor utilization for 60 seconds, kill it.” Usually this would require some custom systems monitoring software, but what if I told you that your computer had this functionality built into it already? That’s right, little known to most people is the WMI background service, which provides a robust eventing and event response model.
Although power management hasn’t always been a highlight of the Microsoft Windows operating system (OS), it’s certainly come a long way in Windows 7 and is now quite robust. Sleeping and hibernating in Windows 7 are both quite fast, and resuming from both states is likewise very quick. But what if you want to do something when your computer wakes up? Though this may not be a terribly common scenario, sometimes people have the need to subscribe to this event and perform an action in response to it.
In the remainder of this article, we will take a look at how to subscribe for system-level power management events, and how to respond to them. We will be working with the following technologies:
WMI Power Management events
Microsoft has built a robust power management provider into Windows 7, and thankfully for us, they have exposed its functionality via the WMI service. WMI provides a standards-based interface in the operating system and applications that extend it. Although WMI has suffered from reliability and performance problems in the past—primarily on Windows XP—modern-day hardware combined with the newest Windows 7 operating system is quite reliable. Microsoft has resolved a lot of WMI bugs such that it is a very dependable service.
Power Management WMI Provider
All WMI providers (extensions to WMI) are registered in a particular WMI namespace under the __Win32Provider class. We can ensure that the Windows Power Management provider is registered by running this WMI query from Windows PowerShell:
@(Get-WmiObject -Namespace root\cimv2 -Query "select * from __Win32Provider where Name = 'MS_Power_Management_Event_Provider'").Count
If this query returns a result of “1,” we know that the provider is registered.
The power management provider exposes a single WMI class called Win32_PowerManagementEvent, which is an extrinsic event class. Extrinsic event classes differ from intrinsic event classes in that the events they provide come from an external provider (the Power Management WMI provider), rather than them representing a change to a WMI object.
The Win32_PowerManagementEvent class only has one property that we really care about, which is the EventType property. The possible values for this property are:
Resume from suspend
Power status change
As you might gather, we are interested in events that have a value of "7," which represents a system resume.
In this example scenario, we are going to take a look at how to restart a Windows service when the system resumes. Specifically, I recently noticed that the PS3 Media Server software has an issue with power management in that it does not listen for connections upon system resume from Standby/Hibernate. This has reportedly been a problem with Windows 7 Ultimate Edition 64-bit.
To work around this issue, we’ll look at how to restart the PS3 Media Server service each time the computer resumes from a low power state.
The use of the PowerEvents model follows a three-step process:
We will cover these three steps individually below.
WQL event filter
First, we need to build an WMI event filter using the WMI Query Language (WQL). WQL is similar to Structured Query Language (SQL), but is much more limited in scope. WQL does not support INSERT, UPDATE, or DELETE statements; it only supports SELECT queries. We’re going to follow the event query template:
select * from <WmiClass> WITHIN <PollInterval> where <Criteria>
In this case, we’re going to use the following values for our event query:
Our resulting query will look like this:
select * from Win32_PowerManagementEvent WITHIN 5 where EventType = 7
The command we’ll use to create our WMI event filter using the PowerEvents module for Windows PowerShell looks like this:
$Filter = New-WmiEventFilter -Name SystemResumed -Query "select * from Win32_PowerManagementEvent where EventType = 7"
We store the filter object in a Windows PowerShell variable for later use in the event binding.
More information about WMI event queries can be found in the PowerEvents documentation. The PDF is located in the Documentation folder of the PowerEvents download. This document includes information about how to test your WMI event query using the wbemtest.exe utility, before creating the permanent event registration to reduce troubleshooting hassle.
Now that we have created (and tested, right?) the event filter, we need to create an event consumer. In this example, we’ll use a Windows PowerShell script to stop and start the PS3 Media Server service (short name: PS3 Media Server). The script itself contains this code:
$ServiceName = $args
Add-Content -Path 'c:\Restart Service.log' -Value "Service name is: $ServiceName"
$Service = @(Get-WmiObject -Namespace root\cimv2 -Class Win32_Service -Filter "Name = '$ServiceName'")
Add-Content -Path 'C:\Restart Service.log' -Value "Found $($Service.Count) instances of '$ServiceName' service"
$Result = $Service.StopService()
Add-Content -Path 'c:\Restart Service.log' -Value "Stopped service with result: $($Result.ReturnValue)"
$Result = $Service.StartService()
Add-Content -Path 'c:\Restart Service.log' -Value "Started service with result: $($Result.ReturnValue)"
Add-Content -Path 'c:\Restart Service.log' -Value "Exiting restart service script"
Save this code in a file called c:\windows\temp\Restart Windows Service.ps1.
To create the event consumer object in WMI, we’ll use the following command:
$Consumer = New-WmiEventConsumer -Verbose -Name SystemResumedRestartService -ConsumerType CommandLine -CommandLineTemplate "powershell.exe -command `". '$($env:WinDir)\temp\Restart Windows Service.ps1' 'PS3 Media Server'`""
This command creates a command-line consumer — that is to say, we want to call a command-line utility in response to the event that occurs. We give it a friendly name so that we know what it runs in response to, and what it does in response to the event: SystemResumedRestartService. Then we use the CommandLineTemplate parameter to specify the command line we want to execute in response to the event. In this case, we’re calling Windows PowerShell and passing it our script file via the -command switch along with an argument to the script file. We use script arguments to make our script dynamic. All we have to do to change the service that gets restarted is change the parameter that we’re passing to it. We don’t have to touch the script itself at all.
Important Make sure you have configured your Windows PowerShell execution policy to allow execution of script files; otherwise, the event consumer will fail. Run Windows PowerShell with your administrative token and use this command: Set-ExecutionPolicy Unrestricted.
WMI event binding
Finally, now that we have created our event filter and event consumer, all we have to do to initiate the flow of events is bind them together. We’ve got the filter and consumer stored in variables called $Filter and $Consumer, so all we have to do is call this command:
New-WmiFilterToConsumerBinding -Filter $Filter -Consumer $Consumer
And that’s it! We’re done. Now that all the WMI objects have been created, all we have to do is suspend and resume our workstation to test the process. After the system is restarted, we should see a c:\Restart Service.log file created. Check this log to ensure that the service you specified in the event consumer command-line was properly stopped and started.
This article has demonstrated the use of the PowerEvents module for Windows PowerShell to create an event listener (filter)/responder (consumer) for wake-from-low-power-state events. Although this particular example restarts a Windows service in response to such an event, you can use your creativity to come up with other tasks you might need to fire off at the same occurrence.
Note For more information about working with permanent and temporary WMI events, see this collection of Hey, Scripting Guy! Blog posts. This collection includes a post about using VBScript to create permanent WMI events. This post is important because it discusses the basics of permanent WMI events. Next, I talk about using Windows PowerShell to monitor and to respond to events on the server. This post continues the discussion about permanent WMI events. This is followed by the first of two articles from Trevor that talk about his Windows PowerShell module to work with WMI permanent events. The second Trevor article in the series talks about using the Windows PowerShell WMI event module to quickly monitor events.
Thanks Trevor for an interesting article, and for writing your Windows PowerShell module for working with WMI Permanent Events.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
thanks for this introduction into permanent WMI events and your PowerEvents module which makes working with them easier!
One question: Your module on CodePlex is still a 10 months old alpha 0.2 release as it is stated on the download page. Will you develop it further on or is it more or less the final version?
I'm just asking because I might use it in a productive environment ...
I don't currently have any plans on making major changes to the module. I hope you enjoy using it!
Can you provide an example on how I could monitor Active Directory events?
API correction. As of PowerEvents 0.2 Alpha, the New-WmiFilter API accepts the query string in parameter name -WQLQuery not -Query as documented above. The correction to above example is:
$Filter = New-WmiEventFilter -Name SystemResumed -WQLQuery "select * from Win32_PowerManagementEvent where EventType = 7"