How Can I Monitor Changes to a Registry Key?
Hey, Scripting Guy! Is it possible to use a script to monitor changes to a registry key? I’d like to be notified any time someone makes changes to the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run key.
Hey, SB. And by the way, thanks for wording the question the way you did: it’s actually pretty easy to receive notification any time someone makes a change to a specific registry key. Had you gone on to ask, “And then can you tell me who made the change and what change they made?” well, in that case we’d have a problem on our hands (and we’ll explain why in a moment). But you didn’t ask that, so for now we’ll just forget we even mentioned it.
Let’s take a look at a script that monitors the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run registry key and then echoes back a message any time that key is changed:
strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\default”)
Set colEvents = objWMIService.ExecNotificationQuery _ (“SELECT * FROM RegistryKeyChangeEvent WHERE Hive=’HKEY_LOCAL_MACHINE’ AND ” & _ “KeyPath=’SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run'”)
Do Set objLatestEvent = colEvents.NextEvent Wscript.Echo Now & “: The registry has been modified.” Loop
We begin by connecting to the WMI service; more specifically, we connect to the root\default namespace, which is where the registry event classes live. We then use the ExecNotificationQuery method to issue the following query:
(“SELECT * FROM RegistryKeyChangeEvent WHERE Hive=’HKEY_LOCAL_MACHINE’ AND ” & _ “KeyPath=’SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run'”)
All we’re doing here is requesting notification any time an instance of the RegistryKeyChangeEvent class is created; as you might have guessed, an instance of this class is created any time a specified registry key is changed (for example a new value is added or an existing value is modified or deleted).
Sounds good, but how do we specify the registry key? That’s easy; we just need to configure the following two properties of the RegistryKeyChangeEvent class:
Hive. This is the registry hive (location) where the key lives. We want to monitor a key that lives in HKEY_LOCAL_MACHINE, so we set the value of the Hive property to HKEY_LOCAL_MACHINE. If we wanted to monitor a registry key that lives in HKEY_CURRENT_USER, we’d set the value accordingly. Note that we do not have to define and use constants when configuring the Hive property; just type in the actual name of the registry hive.
KeyPath. This is the path within the hive that leads to our registry key. Because the \ is a reserved character in WMI, notice that we need to escape each \ with a second \. Thus, a key path like Software\Microsoft\Windows\CurrentVersion\Run must be written out as Software\\Microsoft\\Windows\\CurrentVersion\\Run.
After issuing the query we set up a Do Loop that will simply run forever, dutifully waiting for the next instance of the RegistryKeyChangeEvent class to appear. To make the script wait for such an appearance we use this line of code:
Set objLatestEvent = colEvents.NextEvent
This line of code causes the script to “block,” which means the script will just sit there and wait for the next event to occur (as you well know, the event we are monitoring for is new instances of the RegistryKeyChangeEvent class). When such an event does occur, we simply echo the current date and time and the fact that the registry has been modified in some way. We then loop around and wait for the next such occurrence. (Press Ctrl+C to get out of the loop and end the script.)
Why don’t we do something a bit more specific than merely note that the registry has been modified in some way? Well, mainly because we can’t do anything more specific: details such as what was changed and who changed it are not captured by the registry event provider. We could determine some of this information by grabbing the initial state of the registry key and then, when an event occurs, comparing the new state to the initial state. We’d then have to set up a procedure that allows us to continue comparing the latest state of the registry key to the most recent previous state. But that’s something we’ll have to let you work out for yourself. (Unless, of course, we hear otherwise. After all, we live to serve!)