
| Reading from the Registry | |
| Reading from the Registry in VBScript | |
| Reading from the Registry in Windows PowerShell | |
| Reading from the Registry in Perl |
In past Scripting Games, the events didn’t seem to have a lot to do with real life. Playing jacks with a script? Figuring out which animal of the Chinese year corresponds to any given year? Really, what does that have to do with the real world of a system administrator?
On the surface, not much. Then again, the Scripting Guys know very little about reality, so this isn’t surprising. But we’ll let you in on a little secret: we can also be pretty sneaky sometimes. We try to make sure you’re having so much fun you don’t realize you’re learning something. Well, that ends with this year’s Games.
Okay, not entirely. We’re still going to make sure the Games are fun, but we may not always be so subtle in the “lessons learned” category. For example, it just might come up that you’ll need to do something moderately practical, such as read from the Windows system registry, in order to successfully complete at least one of the events. And just how do you read from the registry? Well, you’ll just have to keep reading.
Let’s say we want to find out what type of information about Windows Media Player is stored in the registry. We can do that by checking the values in the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MediaPlayer. We do that like this:
Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
strKeyPath = "Software\Microsoft\MediaPlayer"
objReg.EnumValues HKEY_LOCAL_MACHINE, _
strKeyPath,arrEntryNames
We start by defining a constant named HKEY_LOCAL_MACHINE and setting its value to a hexadecimal number, namely H80000002. Different hex numbers represent different hives in the registry. (Check here for the full list, along with a very detailed discussion of registry access with VBScript.) After setting the strComputer variable to the local computer (that’s what the dot represents) we call the GetObject method to connect to WMI on the local computer. If you’ve done a lot of WMI programming in VBScript you’ll know that we typically connect to the root\cimv2 namespace. When we work with the registry, though, we don’t use root\cimv2. That’s because none of the objects, methods, and properties we need in order to work with the registry are in the root\cimv2 namespace, they’re in the root\default:StdRegProv namespace. That’s why we connected to root\default:StdRegProv.
Next we set the variable strKeyPath to the registry path that contains the values we’re looking for, in this case Software\Microsoft\MediaPlayer. We’re now ready to read the values from the registry. We do that by calling the EnumValues method, like this:
objReg.EnumValues HKEY_LOCAL_MACHINE, _
strKeyPath, arrEntryNames
We pass three parameters to EnumValues. The first is the constant we defined at the beginning of the script that represents the registry hive we’re searching (HKEY_LOCAL_MACHINE). Next comes the path to the key containing the values we’re looking for (strKeyPath). After that we have a parameter we’ve named arrEntryNames. What’s this one for? Well, this is an “out” parameter. When EnumValues reads all the values in HKEY_LOCAL_MACHINE\Software\Microsoft\MediaPlayer, it needs to put those values somewhere so we can get to them. So we give EnumValues an array, and EnumValues populates that array with the values it retrieves.
Now all we have to do is set up a For Each loop to loop through the elements in the array and echo them back:
For Each strValue in arrEntryNames
Wscript.Echo strValue
Next
Like many tasks in Windows PowerShell, reading from the registry can be done in one simple line of code:
$a = Get-ItemProperty "hklm:\\Software\Microsoft\MediaPlayer" | Get-Member -membertype noteproperty
Okay, maybe at first glance “simple” doesn’t seem the right word, but once we explore what’s going on here you’ll see there really isn’t much to this.
In the first part of this command we call the Get-ItemProperty cmdlet, passing it the full registry path to the values we want to retrieve:
Get-ItemProperty "hklm:\\ Software\Microsoft\MediaPlayer"
Notice that we used “hklm” to represent the HKEY_LOCAL_MACHINE hive. This is the provider name PowerShell uses to represent this hive. (Type Get-Help about_provider at the Windows PowerShell command prompt for more information on accessing registry hives and other providers.) If we run only this command, we’ll get a list of names and values for each value within the MediaPlayer key. If we want to return only the names, we need to pipe the output of Get-ItemProperty to the Get-Member cmdlet:
Get-Member -membertype noteproperty
We’ve added the –membertype parameter to our call to Get-Member, followed by the value noteproperty. If we were to leave this off, Get-Member would return all possible values of the object returned by Get-ItemProperty. The problem with this is that these values include things like methods and properties, and all we want are registry values. To get at the registry values we specify a membertype of noteproperty. At this point all we need to do is set up a for loop to display all the value names:
foreach ($i in $a)
{
$i.name
}
And yes, we could have put this for loop at the end of our pipeline and the entire script would consist of only one line.
There are several different ways of accessing the registry in Perl. It’s possible to use the Win32:OLE module and use WMI to retrieve the values, much like we did with VBScript. But it actually seemed a little cleaner to go with Win32:TieRegistry instead:
use Win32::TieRegistry;
$Registry->Delimiter("/");
for my $val ($Registry->{"LMachine/Software/Microsoft/MediaPlayer"}->ValueNames)
{
print "$val\n";
}
We start by adding our use statement, which we need in order to include the functionality of the Win32:TieRegistry module in our script. The next line is optional, but it makes our script a little easier to understand. We’ve used the $Registry object, a built-in reference to a hash tied to the system registry, to set a Delimiter to “/”. Why did we set a delimiter? We did this because normally when we specify a registry path we use the backslash (\). We run into problems with that though because the backslash is a special character in Perl. If we want to use an actual backslash, we need to “escape” it with another backslash. That means our path would look like this:
LMachine\\Software\\Microsoft\\MediaPlayer
This doesn’t look too bad here, but with longer paths, and paths that need a double backslash (meaning you’d need four backslashes in a row) thing can get a little ugly. That’s why we specified a delimiter. When we set Delimiter to a forward slash (/), we’re telling our script that rather than using the backslash to separate keys in a path, we’re going to use the forward slash. Keeps things a little cleaner.
Now let’s take a look at the next line:
for my $val ($Registry->{"LMachine/Software/Microsoft/MediaPlayer"}->ValueNames)
We’re doing several things in this one line. First, we’re once again using $Registry, this time to access a particular path in the registry. We’re also calling the ValueNames method on our $Registry object. If we want all the values and subkeys within the key we would leave this off. But in this case we want to return only value names, which, coincidentally (or not) is what the ValueNames method does.
We’ve put the whole thing right into a for loop, so we can loop through the names returned by the ValueNames method and print them to the command window:
{
print "$val\n";
}
And that’s it. That wasn’t too bad, was it?