Learn about Windows PowerShell
Hey, Scripting Guy! I need to be notified when a particular registry key value gets changed. The registry value is in the HKEY_LOCAL_MACHINE hive. What I am trying to accomplish is this: I am using a script to install software. After the first piece of software is successfully installed, I want to install a subsequent piece of software. And after this is done, I will reboot the computer. I have tested this technique in our lab, and I am able to postpone the reboot. I have tried pausing the execution of the install script by using the Start-Sleep cmdlet, and this works okay. The problem is that on fast computers the pause is too long, and on slow computers the pause is not long enough. It seems that I cannot figure out a really good way to do this.
I am thinking that if I cannot figure this out, I will need to just record the computers on which the install fails, and manually visit each machine; however, several of the computers are at remote locations and this is not a really practical solution. The idea for the registry key is that each software package creates its own registry key, and if I can detect when this occurs, I can then start the next install. Can you help me?
Microsoft Scripting Guy Ed Wilson here. I am listening to the The Kingston Trio on my Zune as I check the firstname.lastname@example.org e-mail inbox. I am sipping a cup of Constant Comment tea and munching on an ANZAC biscuit. The weather outside is frightful, but inside my office it is delightful. And since I’ve no place to go, let it snow!
By the way, Craig and I have been having several discussions about the 2010 Scripting Games. One thing we can tell you, they will not be held in the summer. They will be earlier! I have been busy working on events. If you have any ideas for the 2010 Scripting Games, e-mail us at email@example.com. What should you say? Just about anything. We are interested in ideas for events, ideas to make the Games go better, ideas to increase participation—just about anything.
LK, I wrote the MonitorRegistryKeyValueChangeEvent.ps1 for you. The MonitorRegistryKeyValueChangeEvent.ps1 script watches a registry key value, and when that value changes, it fires an event. To use the script, you must have Windows PowerShell 2.0 installed. You will need to modify the $keyPath variable and the $valueName variable to use it. The complete MonitorRegistryKeyValueChangeEvent.ps1 script is seen here.
#Requires –version 2.0
$hive = "HKEY_LOCAL_MACHINE"
$keyPath = "Software\\Microsoft\\WBEM\\Scripting"
$valueName = "Default NameSpace"
$gciPath = $keyPath -replace "\\","\"
$query = "Select * from RegistryValueChangeEvent where Hive='$hive' AND " +
"KeyPath='$keyPath' AND ValueName='$ValueName'"
Register-WmiEvent -Query $query -SourceIdentifier KeyChanged
Wait-Event -SourceIdentifier KeyChanged
"New value for $valueName is " + (Get-ItemProperty -Path HKLM:\$gciPath).$valueName
The MonitorRegistryKeyValueChangeEvent.ps1 actually begins with a comment that states the script requires version 2.0. This is not really a comment; it is a directive to Windows PowerShell that will prevent script execution on a Windows PowerShell 1.0 computer. Of course the script will not execute on Windows PowerShell 1.0, but this directive will save you time and generate a more readable error message. The #Requires statement is seen here:
#Requires -version 2.0
The $hive variable holds the registry hive that will be monitored. In this script, you monitor the HKEY_LOCAL_MACHINE hive. This is the only hive the RegistryKeyChangeEvent WMI class supports. Any of the WMI classes that are derived from the RegistryEvent abstract class only work on the HKEY_LOCAL_MACHINE hive. The WMI registry event classes are seen in Table 1.
Table 1 WMI Registry Event Classes
Base class for changes in the registry.
Monitors changes to a hierarchy of keys.
Monitors changes to a single key.
Monitors changes to a single value.
The value of the registry hive, HKEY_LOCAL_MACHINE, is normally listed as all capital letters, and in some instances, this is actually a requirement. However, with the RegsitryKeyChangeEvent WMI class as used in Windows PowerShell, this is not case-sensitive. You could easily use all lowercase letters for your hive name and it would work fine. Keep in mind that though it is not case sensitive, you must spell it correctly for the script to work:
The key path points to the registry key you wish to monitor. There are two things that you need to remember. The first is that you do not have a backward slash at the beginning of the string. The second thing to remember is that all of the backward slashes are escaped—you have double backward slashes between portions of the registry key name. The value assignment to the $keyPath variable is seen here:
The last portion of the path to the registry value you want to monitor is the value name itself. The variable $valueName stores the name of the value to monitor. This is shown here:
The path to the registry value that is being monitored is seen here:
After the path to the registry key value has been assigned via the three different variables, the replace operator is used to replace the double backward slashes with a single backward slash. This is only necessary for the value stored in the $keyPath variable because the hive and the value strings do not have any backward slashes in them. The resulting path is stored in the $gipPath variable. This path will be used with the Get-ItemProperty cmdlet to retrieve the new value that is assigned to the registry value—and the Get-ItemProperty cmdlet does not need to have the backward slashes escaped the way WMI does:
$gipPath = $keyPath -replace "\\","\"
The WMI query is the same as the WMI query that is used in VBScript. An example of monitoring the registry from VBScript can be seen in the Hey, Scripting Guy! article, How Can I Monitor Changes to a Registry Key?
When writing your VBScripts, if you keep your query separated from the WMI moniker, it makes it easier to reuse your WMI queries in a Windows PowerShell script.
Two cmdlets are used to provide access to the WMI event system. The first cmdlet is the Registry-WmiEvent cmdlet. The WMI query that is stored in the $query variable is used, and the SourceIdentifier KeyChanged is assigned to the event. Only one event query can be assigned the SourceIdentifier of KeyChanged because SourceIdentifiers must be unique. If you inadvertently run the script a second time, this error appears:
The Wait-Event cmdlet is used to pause the script execution until the event identified by the SourceIdentifier occurs. These two lines of code are seen here:
When the event triggers, the script continues to the next line. The Get-ItemProperty cmdlet is used to retrieve the new value that caused the event to trigger. This is seen here:
"New value for $valueName is " + (Get-ItemProperty -Path HKLM:\$gipPath).$valueName
After you run the script, the information seen in the following image appears in the Windows PowerShell ISE:
Well, LK, that is all there is to monitoring the registry for a key value change event. Join us tomorrow as we dive into the virtual mail bag and retrieve questions that require shorter answers. Yes, it is time for Quick-Hits Friday.
If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at firstname.lastname@example.org or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson and Craig Liebendorfer, Scripting Guys