Working with the Registry

By The Microsoft Scripting Guys

Sesame Script

Welcome to Sesame Script, the column for beginning script writers. The goal of this column is to teach the very basics of Windows scripting for system administration automation. We’ll provide you with the information you’ll need to begin reading and understanding scripts and to start modifying those scripts to suit your own needs. If there’s anything in particular about scripting you’re finding confusing, let us know; you’re probably not alone.

Check the Sesame Script Archives to see past articles.

Download all the Sesame Script columns (from the very first column through the June, 2007 edition) in one easy-to-read, fully-searchable .chm file.

On This Page

Setting the Stage
Yes, We Have to Say This
A Little Background First
Local Registry Access
Remote Registry Access
Restarting
More Information
Open House

Setting the Stage

If you’ve sold a house in the past five or ten years you’re probably familiar with the concept of “staging.” The idea of staging is to set up your house in a way that will appeal to the most buyers. This will, in theory, result in a quicker sale and a higher sale price. (We say “in theory” because not everyone believes this. Those seem to be the same people who don’t want to go to the trouble of cleaning up their houses, but who are we to argue?)

There are many things you can do to stage your house. One simple thing is to paint. The right paint can brighten a room, make it seem bigger, or just give it some added interest. You can also get your carpets or floors cleaned or replaced - who wants to move into a house that looks dirty? Another idea - and this is the one people tend to find most difficult - is to un-clutter. All those treasured knick-knacks you’ve collected over the years - the snow globes from every airport you’ve ever been to, the collection of hubcaps you’ve lovingly polished to a bright shine, the 250 pictures of your kids that you’ve proudly displayed for all to admire - gone. Not forever, just until you sell the house; then you can put them all back up in your new house.

In the end you wind up with a clean, bright, open house that just about anyone would want to move into.

That’s the idea anyway.

And what, exactly, does all this have to do with this month’s Sesame Script? Well, we haven’t figured that out yet, but we’ll work it in somewhere.

Yes, We Have to Say This

Now that we have the preliminaries out of the way, we have to get into just a little bit of boring stuff.

(What do you mean you’re already bored? You didn’t want to know all about staging a house? Sorry, we just couldn’t imagine anyone who wouldn’t be fascinated by that subject. Obviously, we didn’t expect you to show up.)

This article, believe it or not, is all about working with the Windows system registry. Just about any documentation you read that deals with the registry - especially documentation from Microsoft - will have warnings all over the place telling you that you really shouldn’t have anything to do with the registry, but that if you do, you need to be really, really, careful because you could totally and completely mess up your computer. But given the fact that the Script Center doesn’t contain much in the way of typical Microsoft documentation, we won’t mention that.

What’s that? We should still warn people about the possible perils of messing with the Windows system registry? Yeah, okay, whatever. Everyone reading this, consider yourselves warned. (Especially you, the one who didn’t want to know about house staging.)

Now let’s get on with reality, which includes the fact that sometimes you just have to work directly with the registry.

A Little Background First

As you probably know, the registry is pretty much at the heart of Windows, storing information related to the operating system and the applications running on it. In a way, the registry does a lot of the staging for Windows. (See, we told you we’d work that in somehow.) For example, suppose you run an application and resize the window, then close that application and reopen it. If the window is the same size it was when you closed it that’s probably because the size information was stored in the registry. The desktop wallpaper you’ve chosen? In the registry. Screen saver? Yep, that’s there too.

But the registry holds a lot more than just looks. It also stores information about the types of hardware you’re running, your locale settings, application information (such as version numbers and install dates), and so on. All this is stored in a nice, convenient hierarchy that you can see by opening the Registry Editor, regedit.exe:

Registry Editor

However, it might not always be convenient to open up the Registry Editor to get at this information. For example, you might be in London and want to get at the registry information on a computer in Tokyo. You could fly to Tokyo, which we’re sure would be a nice trip, but not everyone can go jetting around the world on a regular basis. We’re going to assume you’re stuck in your own office and thus give you a more practical solution: assuming the computer is on your network and you’re an administrator on that computer, you can simply use a script.

Local Registry Access

Now that we’ve said you can work with the registry on remote computers, we’re going to pretend we didn’t and instead tell you how to do this on a local computer. (Don’t worry, we’ll get to the remote stuff in a few minutes.)

Windows Script Host (WSH) provides a class, the WshShell class (created by calling CreateObject on Wscript.Shell), that gives you local access to the registry. WshShell has three methods that allow you to work with the registry: RegRead, RegWrite, and RegDelete. You’ll probably never guess what these three methods do, so we’ll go ahead and tell you: They read from, write to, and delete from the registry. We’ll leave it to you to figure out which method does which.

Well, not entirely, since we’re also going to show you examples of each of them. Let’s start by seeing how we can read a value from the registry:

Set objShell = WScript.CreateObject("WScript.Shell")
iWordWrap = objShell.RegRead _
    ("HKCU\Software\Microsoft\Notepad\fWrap")
Wscript.Echo iWordWrap

This script starts by creating the WScript.Shell object we already mentioned:

Set objShell = WScript.CreateObject("WScript.Shell")

The next thing we do is call the RegRead method on that object, passing it the full registry path to the value we want to look at:

iWordWrap = objShell.RegRead _
    ("HKCU\Software\Microsoft\Notepad\fWrap")

We should probably take a closer look at that path, shouldn’t we? When you open the Registry Editor you’ll see five root keys:

  • HKEY_CLASSES_ROOT

  • HKEY_CURRENT_USER

  • HKEY_LOCAL_MACHINE

  • HKEY_USERS

  • HKEY_CURRENT _CONFIG

Notice, however, that we didn’t use any of these in the path we passed to our RegRead method:

HKCU\Software\Microsoft\Notepad\fWrap

Our path started with “HKCU.” As it turns out, HKCU stands for HKEY_CURRENT_USER. You can use the fully-spelled-out version, but WSH also allows you to use abbreviated versions of all the root keys:

Root Key

Abbreviation

HKEY_CLASSES_ROOT

HKCR

HKEY_CURRENT_USER

HKCU

HKEY_LOCAL_MACHINE

HKLM

HKEY_USERS

HKEY_USERS

HKEY_CURRENT _CONFIG

HKEY_CURRENT_CONFIG

Okay, so only three of the five actually have abbreviations. But that’s okay, because those are the three you’ll probably use most anyway.

Once we’ve read our registry value we end the script by echoing back that value:

Wscript.Echo iWordWrap

The value we’ve looked up corresponds to the Word Wrap option in Notepad:

Notepad Word Wrap Option

A value of 0 means word wrap is turned off; 1 means it’s turned on. We can add a little bit of logic to our script to make that more obvious:

Set objShell = WScript.CreateObject("WScript.Shell")
iWordWrap = objShell.RegRead _
    ("HKCU\Software\Microsoft\Notepad\fWrap")
If iWordWrap = 0 Then
    Wscript.Echo "Word wrap is turned off"
Else
    Wscript.Echo "Word wrap is turned on"
End If

This script starts out identical to the last one, creating a WshShell object and calling RegRead to read the value. This time, however, instead of echoing back the number returned from the registry, we put in an If statement to find out what the number is. If the value is 0, we echo back a message saying that word wrap is turned off. If the value is anything else (and the only other thing it can be is 1 - word wrap is either off or on), we echo back a message saying word wrap is turned on.

Suppose we now want to change that value - we want word wrap to always be turned on. Here’s a script that writes a value to the registry:

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.RegWrite "HKCU\Software\Microsoft\Notepad\fWrap", 1, "REG_DWORD"

Once again we create our WshShell object. This time, because we’re changing the registry value, we call the RegWrite method:

objShell.RegWrite "HKCU\Software\Microsoft\Notepad\fWrap", 1, "REG_DWORD"

We’ve passed three parameters to the RegWrite method:

  • "HKCU\Software\Microsoft\Notepad\fWrap" - The path to the registry value we want to change. (Notice we again use the abbreviated version of the root key, HKCU.)

  • 1 - The new value we’re writing to the key value.

  • "REG_DWORD" - The data type of the value we’re changing.

Pretty straightforward, right? What? The data type? Well, yes, that’s a little unusual when it comes to scripting, isn’t it? Most of the time, especially when working with VBScript, we can ignore data types. That’s not the case when we’re working with the registry, however. Sure, we were able to read a value without worrying about the data type. In the case of reading, WSH was able to simply ask the registry for a value, then it was returned and stored in a VBScript variant. However, the registry doesn’t work with variants, it requires specific data types. That means that, when we write to the registry, we need to tell it exactly what type of data we’re putting in there. In this case we’re putting in an integer, known to the registry as a DWord.

There are several data types used by the registry. Here’s a list of the types you’ll be working with most often:

Registry Data Type

VBScript Data Type

REG_SZ

String

REG_DWORD

Integer

REG_BINARY

Array of Integers (Binary Number)

REG_EXPAND_SZ

String (Expandable String)

REG_MULTI_SZ

Array of Strings

Just to make things interesting, here’s another script that changes the value of the Word Wrap option in Notepad. In this case, however, we toggle the value:

strPath = "HKCU\Software\Microsoft\Notepad\fWrap"

Set objShell = WScript.CreateObject("WScript.Shell")
iWordWrap = objShell.RegRead(strPath)
If iWordWrap = 0 Then
    objShell.RegWrite strPath, 1, "REG_DWORD"
Else
    objShell.RegWrite strPath, 0, "REG_DWORD"
End If

To keep things a little simpler, this time we stored our path in the strPath variable:

strPath = "HKCU\Software\Microsoft\Notepad\fWrap"

Next we create our WshShell object and read the value from the registry, passing the strPath variable to the RegRead method:

Set objShell = WScript.CreateObject("WScript.Shell")
iWordWrap = objShell.RegRead(strPath)

Because we’re going to toggle the value, we need to know what the value currently is, which is why we called RegRead. Now that we have the current value stored in the iWordWrap variable, we can check that value and use the RegWrite method to change it appropriately:

If iWordWrap = 0 Then
    objShell.RegWrite strPath, 1, "REG_DWORD"
Else
    objShell.RegWrite strPath, 0, "REG_DWORD"
End If

We start by checking to see if iWordWrap is equal to 0. If it is, we want to change the value to 1, which we do by passing the path to the registry key, the value 1, and the data type (REG_DWORD) to RegWrite:

objShell.RegWrite strPath, 1, "REG_DWORD"

If iWordWrap is not equal to 0, we change the value to 0:

objShell.RegWrite strPath, 0, "REG_DWORD"

So now we know we can change an existing value. But how would we go about creating a brand new value? Believe it or not that’s pretty simple. As it turns out, if we pass a non-existent path to the RegWrite method, RegWrite will create the required keys for that path. For example, let’s add the value NewKey under Notepad:

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.RegWrite "HKCU\Software\Microsoft\Notepad\NewKey", 1, "REG_DWORD"

Notice that when we wrote a new value to the fWrap value we passed in this path:

HKCU\Software\Microsoft\Notepad\fWrap

This time we’re writing a new value to the NewKey value; however, the NewKey value doesn’t exist. WSH recognizes this and simply creates that value for us. After running the preceding script we’ll have a new value in the registry under Notepad:

New Registry Value

This works with an entire path, not just the value. For example, to add a key under Notepad named NewKey and a value under that key named NewValue, simply pass this path to RegWrite:

HKCU\Software\Microsoft\Notepad\NewKey\NewValue

If you’ve written the DWord value 1 to NewValue your registry will now look like this:

New Registry Key

This works all the way back to the root keys, but you can’t create a new root key like this. In other words, you can create a full path such as HKCU\Key1\Key2\Value, but you can’t simply pass a path of Key1\Key2\Value; you need to specify one of the existing roots (HKCU, HKLM, etc.).

The last thing we’re going to do with WSH on the local machine is to delete a key. (This is the part where you need to be careful. Delete the wrong key or value and you could have some problems you don’t really want.)

Here’s a script that deletes the new key value we created:

Set objShell = WScript.CreateObject("WScript.Shell")
objShell.RegDelete "HKCU\Software\Microsoft\Notepad\NewKey"

Once again we create a WshShell object, then we simply call the RegDelete method. We need to pass RegDelete only one parameter, the path to the key we want to delete.

Remote Registry Access

Yes, we know, that’s all fascinating, but where’s the really good stuff? You know, the scripts that will do all this on remote machines?

Hey, come on, have a little bit of patience. After all, we’re keeping you from having to fly around the world to change registry settings, you can wait just a minute while we throw a few more of these treasured possessions into this big cardboard box.

Okay, we’re ready now.

We were able to use WSH to work with the local registry, which, as you saw, was pretty simple. To work remotely we need to use Windows Management Instrumentation (WMI). Keep in mind that you don’t need separate scripts for local and remote access, you can use WMI for both. WMI is a little more complicated, but it’s not too bad. Let’s take a look at a script that reads a value from the registry and you’ll see what we mean:

Const HKEY_CURRENT_USER = &H80000001

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "fWrap"

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

objReg.GetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue
Wscript.Echo strValue

The very first thing we do in this script is define a constant, HKEY_CURRENT_USER:

Const HKEY_CURRENT_USER = &H80000001

Unlike WSH, when you call methods in WMI to work with the registry you can’t simply pass in an abbreviation for the root name, or even the full name of the root. Instead you have to specify a hexadecimal value that represents that root key. Here’s a list of the root keys and their corresponding hex values:

Root Key

Hex Value

HKEY_CLASSES_ROOT

&H80000000

HKEY_CURRENT_USER

&H80000001

HKEY_LOCAL_COMPUTER

&H80000002

HKEY_USERS

&H80000003

HKEY_CURRENT_CONFIG

&H80000005

We’ll use the constant HKEY_CURRENT_USER in a minute, when we actually read the value from the registry. But first we need to set a few variables:

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "fWrap"

Here we’ve set the strComputer variable to a dot (.), which represents the local computer. To run this script against a remote computer, simply replace the dot with the computer name. For example, if you want to work with the registry on a computer named atl-fs-01, set the strComputer variable like this:

strComputer = "atl-fs-01"

We also set a variable (strKeyPath) to the path to the key we want to work with, and another (strEntryName) to the key value we want to retrieve. And yes, we need separate variables for these, we can’t simply specify a full path like this:

strKeyPath = "Software\Microsoft\Notepad\fWrap"

Why not? You’ll find out in just a minute. Before we worry about that, however, we need to connect to WMI:

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

We’re not going to go into any details of working with WMI in this column. If you want to know more about how this works, check out the WMI Scripting Primer. For now the only thing we’re going to make note of is this part:

"\root\default:StdRegProv"

If you’ve done much scripting with WMI, chances are you usually connect to WMI with the \root\cimv2 namespace. However, that’s not where you’ll find the class you need to work with the registry. All the registry information is available through the StdRegProv class, which happens to be in the \root\default namespace.

Now that we’re connected to the appropriate part of WMI, we can call the method, GetDWordValue, that reads the value from the registry:

objReg.GetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue

Unlike WSH, there are several different methods available to read values from the registry. Remember in our WSH discussion how we needed to specify a data type when we wrote to the registry? Well, with WMI we need to be specific about the data type when we read from the registry. In this case we’re reading a value that contains a number (a DWord), so we need to call the GetDWordValue method. Here are all the methods available for reading from the registry:

  • GetBinaryValue

  • GetDWordValue

  • GetExpandedStringValue

  • GetMultiStringValue

  • GetStringValue

Okay, back to our method call:

objReg.GetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue

Let’s take a look at the four parameters we passed to GetDWordValue:

  • HKEY_CURRENT_USER - This is the constant we defined earlier, which represents the root key of the path.

  • strKeyPath - The path to the value we want to read.

  • strEntryName - The name of the value we want to read. This is why we had to use two different variables for the path and the value - GetDWordValue requires that these be passed as separate parameters.

  • strValue - This is what’s called an “out” parameter. We didn’t assign anything to strValue because GetDWordValue is going to do that for us. GetDWordValue will put the value it reads into the strValue variable.

Now all that’s left is to echo back the value:

Wscript.Echo strValue

That wasn’t too bad now, was it? And really, once you get a handle on that the rest is pretty easy. Just to prove it, let’s take a look at writing a value to the registry:

Const HKEY_CURRENT_USER = &H80000001

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "fWrap"
strValue = 1

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

objReg.SetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue

If you compare this to our reading script you’ll notice there isn’t much difference between the two. We once again declare a constant for the root key we’re going to use:

Const HKEY_CURRENT_USER = &H80000001

Then we declare the variables that specify the computer name, the path, and the value name:

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "fWrap"

So far it’s identical. But now, because we’re writing a value and not reading it, we need to assign that new value to a variable ourselves:

strValue = 1

We then connect to WMI (and the root\default namespace), but this time instead of GetDWordValue we’re going to call SetDWordValue:

objReg.SetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue

We pass the same four parameters to the Set version of the method as we did to the Get version, only in this case we don’t need the function to pass a value to us; instead we pass a value to the function, that value being the one we stored in the strValue variable.

Now that we’ve changed an existing value, can we create a new value? We were able to do that with WSH, and it was actually really easy. Well, it turns out it’s almost as easy in WMI:

Const HKEY_CURRENT_USER = &H80000001

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "NewKey"
strValue = 10

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

objReg.SetDWordValue HKEY_CURRENT_USER, strKeyPath, strEntryName, strValue

We set up all the same variables as in the preceding scripts, connect to WMI, and call SetDWordValue (or whichever method is appropriate for the data type of the value you’re creating). The only thing we need to do to create a new key, set of keys, or value is to specify it in the path (in this case stored in the strEntryName variable):

strEntryName = "NewKey"

Just like with RegWrite, any part of the path that doesn’t exist will be created.

And finally, now that we’ve gone to all the trouble of adding a new value in the registry, let’s delete it:

Const HKEY_CURRENT_USER = &H80000001

strComputer = "."

strKeyPath = "Software\Microsoft\Notepad"
strEntryName = "NewKey"

Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

objReg.DeleteValue HKEY_CURRENT_USER, strKeyPath, strEntryName

Deleting is the one place where we don’t need to know what the data type is. Because data type doesn’t matter there’s only one method for deleting: DeleteValue. We pass three parameters to DeleteValue. The first is the hex value of the root key, stored in the constant HKEY_CURRENT_USER. Next is, in this case, the variable strKeyPath. Finally, we pass in the key value we want to delete (strEntryName), and we’re done.

Restarting

One thing to note before we leave is that some changes to the registry won’t take place until you restart your computer. For example, you can change the wallpaper on a computer by changing the registry value HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper. (See this Hey, Scripting Guy! article for an example.) However, simply running the script won’t automatically display the wallpaper, you’ll need to restart the computer before you see the new wallpaper.

More Information

We’ve barely scratched the surface on working with the registry. We might do a little more in a future Sesame Script, but in the meantime take a look at some of these resources to get more information:

Open House

Well, we’re done with all our staging. It seemed kind of painful at first - the picture of little Billy eating ice cream in first grade has been put in a box; the chipped bowl he ate it out of has been removed from the mantel; the tooth he knocked out when his sister threw the bowl at him (causing the chip) has been safely stored away…. The house is ready to show to potential buyers.

And, hopefully, you’re ready to start playing around with the registry. (Sorry, we tried really hard to tie “staging the house” in with “working with the registry,” but we finally gave up - they really don’t have much to do with each other, do they?)