Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I list all the files on a user’s desktop?

-- BT

SpacerHey, Scripting Guy! AnswerScript Center

Hey, BT. So you thought you could fool the Scripting Guys, did you? Well, you did, at least for awhile. As is so often the case with the Scripting Guys we took one look at your question and thought, “Let’s answer this one; this one is easy!” Three tries - and another false start or two - later, we finally came up with an answer for you. So maybe it wasn’t that easy after all (although, for the Scripting Guys, it was fairly typical).

Why did we struggle with this particular question? Well, setting aside the fact that there are days (many of them) in which we struggle with just about everything, we made a couple of misguided assumptions early on. For one, we assumed that connecting to the user’s desktop folder would return us all the information we needed. With that in mind we wrote a script similar to this:

Const DESKTOP = &H10&

Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(DESKTOP)
Set objFolderItem = objFolder.Self

Set colItems = objFolder.Items
For Each objItem in colItems
    Wscript.Echo objItem.Name
Next

Did this script work? Pretty much, although it also shows you the folders on the desktop as well as the files (we never got around to filtering out folders). Unfortunately, though, it didn’t show us all the files in the user’s desktop. Why not? Well, as you probably know, the items that appear on the desktop are actually drawn from two places: the user’s Desktop folder and the All Users Desktop folder. Our initial try at solving this problem retrieved the files from only the user’s desktop folder.

Well, if at first you don’t succeed, right? And so we added this code to the original script:

Const ALL_USERS_DESKTOP = &H19&

Set objFolder = objShell.Namespace(ALL_USERS_DESKTOP)
Set objFolderItem = objFolder.Self

Set colItems = objFolder.Items
For Each objItem in colItems
    Wscript.Echo objItem.Name
Next

Did that script work? You bet it did: now we could get back a list of all the files that appear on the user’s desktop.

Well, check that: all the files that appear on the local user’s desktop. What if we needed to get this information for a remote machine? That was a problem: we used the Shell object in our script, and the Shell object doesn’t do us much good when working with remote computers.

At that point we were ready to give up and tell you that we could list the desktop files only for the local user, when it occurred to us that you can find the paths to the Desktop and All Users Desktop folders in the registry. That implied that we could read these values from the registry on a remote computer, and then use WMI to return the list of files. Will that really work? Well, it seems to:

Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_CURRENT_USER = &H80000001

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set objRegistry=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
 
strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
strValueName = "Common Desktop"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strAllUsers

Set colFileList = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='" & strAllUsers & "'} Where " _
        & "ResultClass = CIM_DataFile")

For Each objFile In colFileList
    Wscript.Echo objFile.Name
Next

Wscript.Echo

strKeyPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
strValueName = "Desktop"
objRegistry.GetStringValue HKEY_CURRENT_USER,strKeyPath,strValueName,strUser

Set colFileList = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='" & strUser & "'} Where " _
        & "ResultClass = CIM_DataFile")

For Each objFile In colFileList
    Wscript.Echo objFile.Name
Next

Don’t be intimidated by the length of this script: it’s a little longer than most Hey, Scripting Guy! scripts simply because we need to access two different registry keys and then retrieve the list of files from two different folders. As you’re about to see, there’s nothing the least bit complicated about the script.

We start off by defining a pair of constants: HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. We’ll use these constants to connect to the appropriate registry hives: we use HKEY_LOCAL_MACHINE to get information about the All Users Desktop folder and HKEY_CURRENT_USER to get information about the current user’s Desktop folder. We then use the following two lines of code to connect to the WMI service on the local computer (or, more correctly, whichever computer we assign to the variable strComputer):

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Our next step is to retrieve the path to the All Users Desktop folder. To do that we make a second WMI connection, this time to the System Registry provider. (Could we have written this script using just one WMI connection? Sure, but it seemed a little easier to follow if we made one connection for retrieving the list of files and a second connection for reading information from the registry). After making the second connection we then assign values to a pair of variables:

strKeyPath is assigned the path to the appropriate registry key. In this case, that’s Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders.

strValueName is assigned the name of the actual registry value we want to read (Common Desktop).

That brings us to this line of code:

objRegistry.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strAllUsers

Here we’re using the GetStringValue method to read the Common Desktop registry value. We pass GetStringValue four parameters: the constant HKEY_LOCAL_MACHINE; the variables strKeyPath and strValueName; and an “out” parameter named strAllUsers. Notice that we’ve never assigned a value to strAllUsers. That’s because we don’t have to: with an out parameter the method will assign a value to the variable. And, in this case, that value will be the path to the All Users Desktop folder.

Once we have the path to the All Users Desktop folder we can then use the following WMI query to retrieve a collection of all the files found in that folder:

Set colFileList = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='" & strAllUsers & "'} Where " _
        & "ResultClass = CIM_DataFile")

And once we have that collection we can set up a For Each loop to walk through the list of files, echoing back the local path for each one:

For Each objFile In colFileList
    Wscript.Echo objFile.Name
Next

The net result looks something like this:

c:\documents and settings\all users\desktop\desktop.ini
c:\documents and settings\all users\desktop\security configuration wizard.lnk

All that’s left now is to repeat the process, this time getting the path to and echoing the files in the current user’s Desktop folder. After that, we’re done.

Which means, of course, that we were right all along: this was an easy question to answer. Or at least it was once we finally figured out how to answer it.