Hey, Scripting Guy!
How Can I Delete a Key and its Subkeys from the Registry?
The Microsoft Scripting Guys
A few years ago, Aaron, a neighbor kid who lived a couple of houses away, would come by every day to play with one of the Scripting Sons (come to think of it, the only Scripting Son). Aaron was a nice enough kid, but he had one very annoying habit: he was always munching away on treats. The treats themselves weren’t a problem, but whatever he was eating—Popsicles, Hostess cupcakes, or what-have-you—Aaron would simply drop his wrappers where he stood, which was invariably in the Scripting Guy’s yard. At first the Scripting Guy simply picked up the wrappers and threw them away. As time went on, however, and as the wrappers started to pile up, the Scripting Guy suggested to Aaron that maybe he ought to throw his wrappers in the garbage can. As time continued to go on, these suggestions became a bit stronger. Eventually the Scripting Guy reached the breaking point. "Aaron," he said, "I’m tired of picking up your garbage every single day. From now on you are banished from our yard. Scripting Son can go over to your house to play, but you are not allowed to set foot in our yard. Ever."
The next day, when the Scripting Guy arrived home from work, he found Aaron standing in the yard, eating a Popsicle. "Hey, Aaron," said the Scripting Guy, "didn’t I tell you yesterday that you were never allowed to come in our yard again?"
Aaron was nonplussed by such a silly question. "Yes," he said, and he went back to eating his Popsicle.
If you’re on the edge of your seat, dying to know how the Scripting Guy reacted, you might be disappointed: he simply stood there for a moment and then walked into the house without saying a word. It wasn’t that the Scripting Guy wasn’t upset, it’s just that he had had a sudden epiphany: there are some things in this world that you simply can’t get rid of—Aaron was one of those things. The Scripting Guy might have considered himself an irresistible force, but he suddenly realized that, like dandelions and registry keys, Aaron (and his Popsicle wrappers) was an unremovable object.
And yes, you read that correctly: in addition to Aaron and his Popsicle wrappers, two other things you can’t get rid of are dandelions and registry keys. We know what you’re thinking: "OK, dandelions I agree with; after all, one of the Scripting Guys once found a dandelion growing in a storage room in which his son had tossed his muddy shoes. But registry keys? Registry keys are easy to get rid of; heck I can even write a script that deletes registry keys."
To tell you the truth, you’re right—sort of. Suppose you have a single registry key in the registry, something along the lines of Figure 1.
Figure 1 Dandelion? No, Registry Key
Can you delete this single registry key using a script? You bet you can; in fact, this script right here will do that for you:
Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
Set objReg = GetObject("winmgmts:\\" & _
strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Test"
objReg.DeleteKey HKEY_CURRENT_USER, strKeyPath
"Wait a second," you say. "First you tell us that registry keys are unremovable, then you show us a script that removes registry keys. What’s the deal here?"
Well, the deal is that we showed you a script that removes a registry key; unfortunately, it won’t remove registry keys. Suppose the Test key has a couple of subkeys underneath it, as in Figure 2.
That’s a problem. The Windows Management Instrumentation (WMI) DeleteKey method can delete a single registry key, but it can’t delete multiple registry keys. If the Test key has any subkeys, the script we just showed you won’t remove a thing—try it and you’ll see what we mean.
Figure 2 Ah, They Multiply
You might not realize it, but we’re in a spot of trouble here—after all, we can’t delete the Test key without deleting Subkey 1 and Subkey 2. Even worse, we can’t delete Subkey 1 until we first delete Subkey A. And if Subkey A happens to have any subkeys, well.... Is this one of those situations where we have to just walk quietly into the house, recognizing that some things can’t be removed?
Fortunately, no. Our Scripting Guy never did figure out what to do about Aaron (other than hope that he’d eventually grow up and move away). As it turns out, though, it is possible to remove registry keys with a script, even registry keys that have subkeys. All you have to do is act recursively.
We don’t have time to explain recursion in detail today; for more information you might want to take a look at the "Microsoft Windows 2000 Scripting Guide
". For now we’ll just note that a recursive subroutine is simply a subroutine that can call itself. How does that help us? Take a look at the accompanying script and then we’ll try to explain how it all works.
On Error Resume Next
Const HKEY_CURRENT_USER = &H80000001
strComputer = "."
strKeyPath = "Software\Test"
Set objRegistry = GetObject("winmgmts:\\" & _
strComputer & "\root\default:StdRegProv")
DeleteSubkeys HKEY_CURRENT_USER, strKeypath
Sub DeleteSubkeys(HKEY_CURRENT_USER, strKeyPath)
objRegistry.EnumKey HKEY_CURRENT_USER, strKeyPath, arrSubkeys
If IsArray(arrSubkeys) Then
For Each strSubkey In arrSubkeys
DeleteSubkeys HKEY_CURRENT_USER, strKeyPath & "\" & strSubkey
objRegistry.DeleteKey HKEY_CURRENT_USER, strKeyPath
Our script starts off simply enough, defining a constant named HKEY_CURRENT_USER and setting the value to &H80000001. This tells the script which registry hive to work with. For more information on writing WMI scripts that deal with the registry, take a peek at this chapter
in the "Scripting Guide".
We then assign the name of the computer (using a dot to represent the local computer) to a variable named strComputer, and we assign the path to the registry key we want deleted (Software\Test) to a variable named strKeyPath.
After that we connect to the WMI service, taking care to bind to the root\default namespace. (Although you typically find WMI classes in root\cimv2, you won’t find the System Registry provider there.)
Now it gets interesting. Notice that we don’t try to delete the registry key at this point. Why not? Well, as we’ve already learned, if this registry key has any subkeys we can’t delete it. Therefore, we call a subroutine named DeleteSubkeys, passing as parameters the constant HKEY_CURRENT_USER and the variable strKeyPath.
Once we’re inside the subroutine, we delete the registry key, right? Nope, sorry; remember that operation will fail if the key has any subkeys. Instead, the first thing we do is call the EnumKey method, a method that returns a list of all the subkeys (if any) found in the registry key Test. As you can see, we pass EnumKey three parameters: HKEY_CURRENT_USER, strKeyPath, and an "out" parameter named arrSubkeys. If you’re thinking, "Hey, we didn’t even assign a value to arrSubkeys," well, you’re right, we didn’t. That’s because with an out parameter, all we do is supply a variable name and the method assigns it a value. In this case, that value will be a list of all the subkeys found in Test.
EnumKey will end up telling us that the Test key has two subkeys: Subkey 1 and Subkey 2. And, no, we still can’t start deleting registry keys. Why not? Well, suppose either Subkey 1 or Subkey 2 has subkeys of their own. (And one of them does: Subkey 1 has a subkey named Subkey A.) Because we can’t delete registry keys that have subkeys, the presence of Subkey A will cause the script to fail. (And, yes, everything seems to cause this script to fail doesn’t it? But don’t lose hope.)
So what do we do now? Well, brace yourself, because this is where it really gets confusing. The first thing we do is use the IsArray function to determine whether the variable arrSubkeys is an array. If it is, the Test key does have at least one subkey (otherwise arrSubkeys would have no value at all). Because IsArray comes back True, we set up a For Each loop, one that loops through all the subkeys stored in the variable arrSubkeys (which, just to remind you, contains the values Subkey 1 and Subkey 2).
Note that, even though we’re already in the DeleteSubkeys subroutine, we go ahead and call that subroutine again. (That’s what recursion is all about.) This time we call the subroutine using the current registry path (stored in the variable strKeyPath) plus a \ and the name of the subkey we’re looking at. In other words, the first time through this loop we’ll be looking at the subkey Subkey 1. Therefore, we call DeleteSubkeys a second time using strKeyPath (Software\Test) plus \Subkey 1; in other words, Software\Test\Subkey 1. As you know, this happens to be the path to the first subkey found in the Test key.
So now what happens? Well, the DeleteSubkeys subroutine will call the EnumKey method to determine whether Subkey 1 has any subkeys of its own. As it turns out, it does. Because of that we call DeleteSubkeys a third time, this time passing the value Software\Test\Subkey 1\Subkey A.
We told you it would get confusing.
Fortunately (for the sake of our sanity), Subkey A has no subkeys of its own; that means the IsArray function comes back False. That also means that we’ll be able to skip the line of code that calls the DeleteSubkeys subroutine and, instead, call objRegistry.DeleteKey to delete Subkey A—and only Subkey A. Still with us? What we’ve done so far is follow the path down to Software\Test\Subkey 1\Subkey A and finally found a registry key with no subkeys. Because of that, we go ahead and delete Subkey A.
Good point. That’s nice, but it still leaves us with a bunch of other subkeys to delete (not to mention the Test key that we started with). How the heck do we get rid of those other registry keys?
To be honest, this is where it helps to have a little blind faith in VBScript. Each time VBScript calls the recursive subroutine, it makes a note to itself as to what’s going on. In other words, when DeleteSubkeys checks the subkey Software\Test\Subkey 1\Subkey A VBScript is well aware that the other keys exist, too.
After deleting Subkey A, VBScript automatically goes back to Subkey 1 to see if it has any other subkeys. Because it doesn’t, the script then deletes Subkey 1. The script then runs this check on Subkey 2, the other subkey found in Test. Because Subkey 2 has no subkeys, it gets deleted as well. (This will continue based on how many subkeys and sub-subkeys you might have.)
After deleting Subkey 2 VBScript goes back and checks the Test key. Because this key no longer has any subkeys, Test gets deleted, and our work is done. Try it and see.
If you feel like your head is about to explode, don’t worry (well, not unless your head actually does explode). If you’d rather not delve into the intricacies of recursion, then just use the script as is and don’t give it a second thought. Of course, having said that we recommend that you try walking through this scenario a few times until it begins to make sense. Why? Well, if you ever can get a grasp on how this script works then you’ll be able to write recursive scripts of your own. And that means being able to write scripts that, for example, enumerate all the values in all the subkeys of a registry key or list all the files in all the subfolders of a folder.
The main thing is that this scenario has a happy ending: we figured out a way to remove hitherto unremovable registry keys. That doesn’t mean this approach will work for everything: dandelions, to name one, seem immune to recursive subroutines. As for Aaron, well, as he and the Scripting Son grew older their interests began to diverge, and the two don’t spend much time together anymore. Nevertheless, the other day, when our Scripting Guy returned home, he found an empty Big Gulp cup lying in the front yard. Like we said, there are some things you just can’t get rid of.
The Microsoft Scripting Guys work for—well, are employed by—Microsoft. When not playing/coaching/watching baseball (and various other activities) they run the TechNet Script Center. Check it out at www.scriptingguys.com.
© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited