How Can I Retrieve a List of the Commands Typed Into the Run Dialog Box?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! Sometimes I type commands in the Run dialog box that I’d like to retrieve later on. I know the most recent commands I used are cached somewhere; that’s because they show up when I start typing in the Run dialog box. How can I use a script to retrieve these commands?

— KJ

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KJ. You know, our first thought upon reading your question was this: why didn’t we think of that? Needless to say, the Scripting Guys have been using the Run dialog box for years, and we, too are well aware that the most recent commands (the last 26, if you’re scoring at home) are cached somewhere on the computer. And yet, it never occurred to us to write a script that could retrieve this list. How could we have overlooked something so obvious?

Note. Actually, it’s not all that surprising we overlooked something so obvious. For example, the Scripting Guys have been in their current building for about a year now, yet it was only a few weeks ago that the Scripting Guy who writes this column found out that there was a stairway just down the hall from his office.

After poking around a bit we discovered that this information is stored in the registry; more specifically, it’s stored as individual registry values within the registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU. Is that good? You bet it is; after all, it allows us to write a script like this:

Const HKEY_CURRENT_USER = &H80000001

strComputer = “.”

Set objRegistry = GetObject(“winmgmts:\\” & strComputer & “\root\default:StdRegProv”)

strKeyPath = “Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU” objRegistry.EnumValues HKEY_CURRENT_USER, strKeyPath, arrValueNames, arrValueTypes

For Each strValue in arrValueNames If Len(strValue) = 1 Then objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValue,strRunCommand intLength = Len(strRunCommand) strRunCommand = Left(strRunCommand, intLength – 2) Wscript.Echo strRunCommand End If Next

This script connects to the RunMRU key and then enumerates the values of all the values found there. (And, yes, we know: values of values? Such is the joy of registry terminology.) To accomplish that feat, the script starts off by defining a constant named HKEY_CURRENT_USER and setting the value to &H80000001; this constant is used later on to tell the script which registry hive to work with. We then connect to the WMI service on the local computer, taking care to bind to the root\default namespace, home of the WMI registry provider.

Note. Can we use this same script to retrieve the most-recently used commands from a remote computer? Of course we can; just assign the name of the remote computer to the variable strComputer.

After connecting to the WMI service, we assign the value Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU to a variable named strKeyPath. We then use the EnumValues method to grab a collection of all the registry values found in the RunMRU key:

objRegistry.EnumValues HKEY_CURRENT_USER, strKeyPath, arrValueNames, arrValueTypes

As you can see, we pass EnumValues four parameters:

Parameter

Description

HKEY_CURRENT_USER

The registry hive where the information can be found.

strKeyPath

The path to the RunMRU key within the HKCU hive.

arrValueNames

“Out” parameter that serves as place to store all the registry value names. All we do is supply EnumValues with a variable name; EnumValues will then populate this variable with all the value names found in RunMRU.

arrValueTypes

Another out parameter, this one containing data types corresponding to each value found in RunMRU. This is a required parameter, but because the values found in RunMRU all have a data type of REG_SZ we don’t actually use it in the script.

As it turns out, each command typed into the Run dialog box is given its own value in the registry; these values are assigned names using the letters A through Z (which explains why only the 26 most-recently used commands are tracked in the registry). In the registry RunMRU looks something like this:

Hey, Scripting Guy!


After executing the EnumValues method we’ll get back a collection of all these value names; in other words, our collection will consist of the letters A through Z. That’s good, but what this collection doesn’t contain are any of the actual commands themselves. To get the commands (which is the whole idea in the first place) we need to connect to and read each of the 26 values in the registry.

Can we do that, can we easily connect to and read each of the 26 values in the registry? Of course we can; in fact, that’s what we do in this block of code:

For Each strValue in arrValueNames
    If Len(strValue) = 1 Then
        objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValue,strRunCommand
        intLength = Len(strRunCommand)
        strRunCommand = Left(strRunCommand, intLength – 2)
        Wscript.Echo strRunCommand
    End If   
Next

You’re right: at first glance that is a little forbidding, isn’t it? Tell you what, let’s show you a simplified version of this For Each loop, then we’ll explain why we added some additional code to the loop. Here’s the simplified loop:

For Each strValue in arrValueNames
    objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValue,strRunCommand
    Wscript.Echo strRunCommand
Next

What we’re doing here is setting up a loop that runs through all of the registry values. To read each of those values we simply call the GetStringValue method:

objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValue,strRunCommand

GetStringValue gets passed four parameters: the constant HKEY_CURRENT_USER; the variable strKeyPath; the variable strValue (which represents the individual value name, e.g., A, B, or C); and an out parameter named strRunCommand. With this out parameter we simply specify a variable name and the GetStringValue method assigns it the value of the registry value (that is, the appropriate Run command). After calling GetStringValue we echo back strRunCommand, loop around, and tackle the next value in the collection.

So much for the simplified For Each loop; now what about all that extra code in our real For Each loop? The extra code is there primarily to give us slightly-nicer output. For example, in the RunMRU key there’s a registry value named MRUList. This doesn’t represent an actual command; instead, it represents the order in which the most recently-used commands are presented. That’s not important to us (at least not today), so we’d just as soon skip the MRUList value altogether. That’s’ what we do here:

If Len(strValue) = 1 Then

In this line of code we use the Len function to check the number of characters in the value name. If the number of characters (length) is equal to 1 we go ahead and read the value. If the length is not equal to 1 (which, obviously, is the case with MRUList, which has 7 characters) then we simply skip that value and move on to the next item in the collection.

The other little touch we added was this:

intLength = Len(strRunCommand)
strRunCommand = Left(strRunCommand, intLength – 2)

If you look in the registry, you’ll see that our commands all have a \1 appended to the end. We could leave that if we wanted to, but it’s easy enough to get rid of. All we do is determine the length of the command, then use the Left function to return the first x characters in the string. And what is x equal to? It’s equal to the total number of characters minus 2. That simply means we’re going to grab all the characters except the last 2 (the \1) and echo those to the screen.

And there you have it: a script that returns the most-recently used commands typed into the Run dialog box. We still haven’t figured out where that mysterious stairway leads, but first things first.

0 comments

Discussion is closed.

Feedback usabilla icon