How Can I Copy the Folder Structure of a Folder?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I copy the folder structure of a folder (that is, a folder and all its subfolders) without copying the files as well?

— AS

SpacerHey, Scripting Guy! AnswerScript Center

Hey, AS. If you’re one of the many people who simply can’t get through the day without knowing what the Scripting Guy who writes this column is up to as he traipses through Italy, well, here’s the latest update: today the Scripting Family hops on a plane and heads for Venice. And what if you’re one of the many people who can (and would actually prefer to) get through the day without knowing what the Scripting Guy who writes this column is up to as he traipses through Italy? Well, we have good news for you, too: the Scripting Money is beginning to run out, so it’s just a matter of time before the Scripting Guy who writes this column comes home and stops bothering you with details about his trip to Europe.

At which point he resumes bothering you with details about the Scripting Son’s baseball games.

But what if you’re one of those people who just wants to know how to copy the folder structure of a folder without copying all the files as well? Well, guess what? There’s good news for you, too: we just happen to have a script that does that very thing.

Hey, Scripting Guy!, the daily column with a little something for everyone!

Including the following script:

On Error Resume Next

Dim arrFolders() intSize = 0

strComputer = “.”

Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)

strFolderName = “c:\scripts”

GetSubFolders strFolderName

Sub GetSubFolders(strFolderName) Set colSubfolders = objWMIService.ExecQuery _ (“Associators of {Win32_Directory.Name='” & strFolderName & “‘} ” _ & “Where AssocClass = Win32_Subdirectory ” _ & “ResultRole = PartComponent”)

For Each objFolder in colSubfolders strFolderName = objFolder.Name ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1 GetSubFolders strFolderName Next End Sub

Set objFSO = CreateObject(“Scripting.FileSystemObject”)

For Each strFolder in arrFolders strFolderName = strFolder strNewFolder = Replace(strFolderName, “c:\scripts”, “c:\test”) Set objFolder = objFSO.CreateFolder(strNewFolder) Next

Yes, we know: this is a scary-looking script, isn’t it? That’s because there’s no simple, straightforward method for getting at nested subfolders; that is, folders inside of folders inside of folders. (Or at least not in VBScript; in Windows PowerShell there is a simple, straightforward method for getting at nested subfolders.) Therefore, we need to use a recursive subroutine: a subroutine that can call itself, and as many times as it needs to. Recursive subroutines aren’t exactly intuitive, which explains why the code looks as scary as it does.

Our advice? If you’d like to know more about recursion, check out this section of the Microsoft Windows 2000 Scripting Guide. Otherwise, don’t worry too much about it: just use today’s script as-is, changing the names of the folders as needed.

What we’re going to do today is grab the name (or, more properly, the path) of every subfolder in C:\Scripts and stash that information in an array; after that, we’ll loop through the values in the array in order to copy that folder structure to C:\Test. With that in mind, the first thing we do is initialize a dynamic array named arrFolders, then assign the value 0 to a counter variable named intSize. That’s what’s going on here:

Dim arrFolders()
intSize = 0

After we connect to the WMI service on the local computer we assign the path of the parent folder (C:\Scripts) to a variable named strFolderName. What we’re going to do (in a minute) is execute a chunk of code that returns a collection of all the topmost subfolders for our parent folder. What do we mean by “topmost” subfolders? Well, suppose we have a folder structure that looks like this:

C:\Scripts

C:\Scripts\Folder 1

C:\Scripts\Folder 1\Folder A

C:\Scripts\Folder 2

C:\Scripts\Folder 2\Folder B

If C:\Scripts is our parent folder (and it is), then the topmost subfolders are Folder 1 and Folder 2; these are the subfolders that are one level “down” from the parent folder. What about Folder A and Folder B, folders nested two levels from the parent? Well, that’s the problem: deeply-nested subfolders like this are difficult to get at. In turn, that’s why we need the recursive subroutine.

Got all that? Good. Now let’s have some fun:

GetSubFolders strFolderName

OK, so maybe “fun” wasn’t the right word; how about “Now let’s get to work retrieving all the folder and subfolder names”? What we’re doing here is calling our recursive subroutine (a subroutine named GetSubFolders), passing the path to the parent folder as the sole subroutine parameter. In case you’ve forgotten, the GetSubFolders subroutine looks like this:

Sub GetSubFolders(strFolderName)
    Set colSubfolders = objWMIService.ExecQuery _
        (“Associators of {Win32_Directory.Name='” & strFolderName & “‘} ” _
            & “Where AssocClass = Win32_Subdirectory ” _
                & “ResultRole = PartComponent”)

For Each objFolder in colSubfolders strFolderName = objFolder.Name ReDim Preserve arrFolders(intSize) arrFolders(intSize) = strFolderName intSize = intSize + 1 GetSubFolders strFolderName Next End Sub

Yes, this is where things start to get a little weird. Inside the subroutine the first thing we do is execute an Associators Of query that returns a collection of all the topmost subfolders of C:\Scripts. How do we know this query returns the subfolders of the folder C:\Scripts? Well, for one thing, we’re getting back instances of the Win32_Subdirectory class; instances of that class just happen to be subfolders. For another, we know that the parent folder must be C:\Scripts because that’s the value of the variable strFolderName.

That’s how we know that this query returns the subfolders of the folder C:\Scripts.

As we noted, the Associators Of query returns a collection of all the topmost subfolders in the folder C:\Scripts (for example, C:\Scripts\Folder 1 and C:\Scripts\Folder 2). Our next step is to set up a For Each loop that walks through this collection of subfolders. Inside that loop, we use this line of code to grab the folder Name (that is, the folder path) and assign that value to the variable strFolderName:

strFolderName = objFolder.Name

After that, we use the following block of code to resize the array arrFolders, taking care to maintain any existing data in that array. We assign the path to the first subfolder (e.g., C:\Scripts\Folder 1) to the first item (item 0) in the array, then increment the value of our counter variable intSize by 1:

ReDim Preserve arrFolders(intSize)
arrFolders(intSize) = strFolderName
intSize = intSize + 1

Why do we increment the value of the counter variable? That’s easy. So far we’ve added one folder to the array, making that single item array item 0. When the time comes to add another folder to the array, that subfolder needs to be added as item 1 in the array; that means that the value of our counter variable intSize also needs to be equal to 1.

That brings us to this line of code:

GetSubFolders strFolderName

Yes, you have seen that line of code before: once again we’re calling the subroutine GetSubFolders, this time passing the value C:\Scripts\Folder 1 as the subroutine parameter. And yes, we’re doing that even though we’re already inside the subroutine GetSubFolders; such is the nature of a recursive function. What this is going to do is run the subroutine against the folder C:\Scripts\Folder 1, pulling out the topmost subfolders of that folder. And then the subroutine will run against those folders, looking for their subfolders. This recursive process will continue until we run out of folders in the folder tree, by which time the paths to all of these folders will have been added to the array arrFolders.

We know: we get a headache just thinking about that, too. Fortunately, however, we don’t have to think about it too much; instead, VBScript does all the hard work (like keeping track of where it is in the folder structure and what it needs to do next) for us.

So what happens when we do finish adding all the folder paths to the array arrFolders? Well, for starters, we create an instance of the Scripting.FileSystemObject object, the object used to create new folders. We then set up a For Each loop to walk us through each of the folder paths in arrFolders, folder paths similar to this:

C:\Scripts\Folder 1

C:\Scripts\Folder 1\Folder A

C:\Scripts\Folder 2

C:\Scripts\Folder 2\Folder B

Needless to say, those are the paths to the existing folders; what we need to do now is copy all those folders to C:\Test. Admittedly, there are several different ways we can do this; we decided the easiest approach was to start out by using the Replace function to replace each instance of C:\Scripts with C:\Test. For the first item in the array that’s going to give us the following folder path:

C:\Test\Folder 1

And guess what? That just happens to be one of the paths we need in order to copy the folder structure of C:\Scripts to C:\Test. That means that all we have to do now is call the CreateFolder method (passing along this new folder name as the method parameter). Just like that, we’ve copied part of the folder structure to C:\Test, but without copying any files. And then we simply loop around and repeat the process with the next folder in the array.

When all is said and done C:\Test will contain the following subfolders:

C:\Test\Folder 1

C:\Test\Folder 1\Folder A

C:\Test\Folder 2

C:\Test\Folder 2\Folder B

Which are the very subfolders C:\Test should contain.

As we noted earlier, today the Scripting Family heads to Venice. No doubt all of you are familiar with Venice, the city built smack-dab in the middle of the Venetian Lagoon. (Most of the buildings actually rest on wood pilings driven into the sea floor.) For much of the 20th century Venice was slowly sinking into the lagoon; this was due to artesian wells that were sunk along the outskirts of the town. A ban on artesian wells enacted in the 1960s has slowed the sinking process; however, experts remain divided on whether this has stopped the sinking process.

All of this, of course, is one reason why the Scripting Guy who writes this column has such an affinity for the city of Venice. Something that is slowly sinking away into nothingness? If that isn’t a perfect description of his career path at Microsoft, well, we don’t know what is.

0 comments

Discussion is closed.

Feedback usabilla icon