Hey, Scripting Guy! How can I get a list of all the subfolders in a folder and then put that list into an array?
— PW
Hey, PW. We know how anxious you’ve all been, waiting to hear whether the Scripting Guys were successfully moved from Building 43 to Building 42 (yes, directly across from their old building). Well, about the best we can say is that we were moved; whether we were moved successfully is another story. For example, prior to the big move they had us fill out a “Move Map” which included these two questions:
• |
How many rolling filing cabinets do you want? |
• |
How many bookshelves do you want? |
The Scripting Guy who writes this column requested one bookshelf and no filing cabinets. So what did he get? Ah, you must have been moved by Microsoft before: that’s right, no bookshelves and one filing cabinet, exactly the opposite of what he requested. There was also a note on his desk that read “Your computer equipment and/or peripherals were not connected in your old office, therefore they were not reconnected.” Not that hooking up a couple computers is a particularly big deal (especially for a Scripting Guy!) but, technically, his computer equipment and/or peripherals were connected in his old office; he’s learned, the hard way, that computer equipment works best when it’s hooked up and running.
Unless, of course, he just doesn’t know what it means to have connected computer equipment.
Oh, and his phone doesn’t work, either. Or so he thought. However, the guy going around working on phones checked his list and said, “It’s not on the list, so it must be working.” Oh, OK. Sorry to bother you.
Oh, well. At any rate, the Scripting Guys are back in business. And if you don’t believe us, here’s a script that grabs a list of all the subfolders in a folder and then stashes that list into an array:
On Error Resume Next Dim arrFolders() intSize = 0 strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") strFolderName = "c:\scripts" Set colSubfolders = objWMIService.ExecQuery _ ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _ & "Where AssocClass = Win32_Subdirectory " _ & "ResultRole = PartComponent") ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1 For Each objFolder in colSubfolders GetSubFolders strFolderName Next Sub GetSubFolders(strFolderName) Set colSubfolders2 = objWMIService.ExecQuery _ ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _ & "Where AssocClass = Win32_Subdirectory " _ & "ResultRole = PartComponent") For Each objFolder2 in colSubfolders2 strFolderName = objFolder2.Name ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1 GetSubFolders strFolderName Next End Sub For Each strFolder in arrFolders Wscript.Echo strFolder NextYou’re right: this is a complicated script. That’s because we need to use a recursive subroutine in order to get at all the subfolders in a folder. We won’t you kid you: a recursive subroutine (a subroutine that can call itself) is a difficult concept to grasp, and we won’t take the time to explain all the ins and outs today. For more information, take a look at this portion of the Microsoft Windows 2000 Scripting Guide.
In the meantime, though, we’ll at least try to explain the principle behind this script. We start out by using the following line of code to declare a dynamic array named arrFolders; as you might expect, this is the array where we’ll store the list of folders:
Dim arrFolders()We then assign the value 0 to a variable named intSize; this is a “counter variable” we’ll use to keep track (and periodically increase the size) of our dynamic array.
After connecting to the WMI service on the local computer (although this script works equally well against remote computers) we then use this block of code to bind to the folder C:\Scripts:
strFolderName = "c:\scripts" Set colSubfolders = objWMIService.ExecQuery _ ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _ & "Where AssocClass = Win32_Subdirectory " _ & "ResultRole = PartComponent")And now we’re ready for action. At the moment we have a dynamic array named arrFolders; however, that array is empty. Consequently, the first thing we need to do is get our root folder – C:\Scripts – into the array. That’s what we do here:
ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1As you can see, we use Redim Preserve to redimension the size of our array. And what size do we make the array? Why, we make it size 0, using the variable intSize. (Yes, we know. But remember, an array of size 0 means that the array can hold 1 item. Likewise, an array of size 1 means that the array can hold 2 items, and so forth.) We next add the folder path (stored in the variable strFolderName) to the array, then increment the variable intSize by 1. None of that should be too terribly complicated.
That brings us to these three lines of code:
For Each objFolder in colSubfolders GetSubFolders strFolderName NextWhat we’re doing here is calling our recursive subroutine, GetSubFolders. We need to do this because WMI, by itself, returns only the “top-level” subfolders in a folder; for example, it returns C:\Scripts\ADSI but not C:\Scripts\ADSI\Users or C:\Scripts\ADSI\Groups. Because of that we need to connect to each top-level subfolder and then repeat the process for each of those sub-subfolders; in other words, get a collection of subfolders and then check to see if those subfolders have any sub-subfolders. Without going into excruciating detail, that’s what the recursive subroutine is for. It will dutifully check each subfolder, and each subfolder of those subfolders, and each subfolder of those sub-subfolders and – well, you get the idea. The net result? We’ll get back the complete folder tree: all of the folders and subfolders found in C:\Scripts.
This, by the way, is the actual recursive subroutine:
Sub GetSubFolders(strFolderName) Set colSubfolders2 = objWMIService.ExecQuery _ ("Associators of {Win32_Directory.Name='" & strFolderName & "'} " _ & "Where AssocClass = Win32_Subdirectory " _ & "ResultRole = PartComponent") For Each objFolder2 in colSubfolders2 strFolderName = objFolder2.Name ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1 GetSubFolders strFolderName Next End SubLike we said, we won’t discuss how this works. However, notice that we’re using the same Associators Of query we used to get the collection of top-level subfolders found in C:\Scripts. Assuming this query returns data we then set up a For Each loop to loop through the collection. Inside the loop we add the folder paths to the array (for example, there’s the Redim Preserve command again) and we then call the GetSubFolders subroutine. Why? To determine whether or not the subfolder has any sub-subfolders.
Yes, it’s very confusing, at least for us. Fortunately, though, VBScript has no problem keeping track of everything. In that respect, this might be one time that you simply let VBScript handle matters and not worry too much about it.
When all is said and done we then use this block of code to echo back all the folder paths added to the array arrFolders:
For Each strFolder in arrFolders Wscript.Echo strFolder NextGive it a try and see what happens.
We hope that helps, PW. Incidentally, the Scripting Guy who writes this column may have discovered the real reason his computer equipment and/or peripherals were not reconnected: his computer (or at least his desktop machine) is currently in four pieces, and one of those pieces might very well be bent beyond repair. The Scripting Guy who writes this column doesn’t know a lot about hardware, but past experience suggests that computers work best when all the pieces are there and they all actually fit together. Maybe the movers should have just carried the computer over instead of dribbling it.
Or maybe not. After all, they are the experts.
Editor’s Note: Someone must have tipped off the movers as to who they were moving. All of the Scripting Editor’s equipment made it to the new office unscathed and in perfect working condition, with the correct number of book shelves and filing cabinets (two of each), and a working telephone. The Scripting Editor has no idea how everything went wrong for the Scripting Guy who writes this column. Really.
0 comments