Hey, Scripting Guy! Question

Hey, Scripting Guy! I need a little help. I have one top folder with many subfolders ; the subfolders are all top-level subfolders like C:\Scripts\Folder1 and C:\Scripts\Folder2. In each subfolder I have a text file with the same name. I need to open that text file in each folder and change a couple of characters. Is there any way that you could help me with this?

-- DJ

SpacerHey, Scripting Guy! AnswerScript Center

Hey, DJ. Well, this is it: today is the last official day of the 2008 Winter Scripting Games. By the time most of you read this the remaining two “main” events (Events 9 and 10) will have already closed; the last event in the Sudden Death Challenge closes at 3:00 PM (Redmond time) this afternoon. Does that mean you’re out of luck for this year? Heck no. Hustle on over to the Sudden Death Challenge home page and enter Event 10; do that, and you’ll be eligible for all the great prizes we’re giving away as part of the 2008 Scripting Games, including the Dr.Scripto Bobblehead dolls and the 50 copies of Windows Vista Ultimate.

Note. Isn’t that a little unfair for someone to enter the Games at the very last minute, complete an event that doesn’t even require very much effort, then walk away with one of the big prizes, all at the expense of someone who spent the last two weeks writing scripts for each event in each division? Well, we admit that it sounds a little unreasonable. However, it can’t possibly be unfair; after all, as near as we can tell that’s the way Microsoft doles out annual performance bonuses.

At any rate, we hope everyone enjoyed the Scripting Games this year; we can tell you that the Scripting Guys thoroughly enjoyed the Games, aside from an occasional lack of sleep. And we’re already looking forward to next year, when we hope to bring you a really cool competition. We haven’t picked out the dates for the 2009 Games just yet, but February 13, 2009 is also a Friday the 13th. It would be pretty hard for us to pass up the symbolism of starting the Scripting Games on Friday the 13th. Mark your calendar now; you won’t want to miss it.

Of course, as the Games wind down that means the Scripting Guys have to get back to their real jobs. To tell you the truth, we can’t even remember what those real jobs were; like we said, we haven’t gotten much sleep in the past couple weeks. As best we can recall, however, those jobs involved showing people how to write scripts that can modify a specific text file found in a folder and the top-level subfolders of that folder. At least we hope that’s what our job involves. Otherwise there might not be a lot of use for the following:

Const ForReading = 1
Const ForWriting = 2

strFileName = "Test.txt"
strParentFolder = "C:\Scripts\"

Set objFSO = CreateObject("Scripting.FileSystemObject")

strTextFile = strParentFolder & strFileName

Set objFile = objFSO.OpenTextFile(strTextFile, ForReading)
strContents = objFile.ReadAll
objFile.Close

strContents = Replace(strContents, "Contoso.com", "Fabrikam.com")

Set objFile = objFSO.OpenTextFile(strTextFile, ForWriting)
objFile.Write strContents
objFile.Close

Set objFolder = objFSO.GetFolder(strParentFolder)
Set colSubfolders = objFolder.Subfolders

For Each objSubfolder in colSubfolders
    strFolderName = objSubfolder.Path
    strTextFile = strFolderName & "\" & strFileName

    Set objFile = objFSO.OpenTextFile(strTextFile, ForReading)
    strContents = objFile.ReadAll
    objFile.Close

    strContents = Replace(strContents, "Contoso.com", "Fabrikam.com")
    Set objFile = objFSO.OpenTextFile(strTextFile, ForWriting)
    objFile.Write strContents
    objFile.Close
Next

Let’s see if we can figure out how this script works, and if we can figure it out before we fall asleep.

Note. As you might have guessed, it’s been another long night here in Scriptingville; it’s already past midnight, and the Scripting Guy who writes this column still has several things to do before he can go to bed. But is he complaining? You bet he is. But the Scripting Editor, who can’t go to bed until the Scripting Guy who writes this column finishes writing this column, isn’t offering much sympathy.

In other words, we have the power to keep the Scripting Editor awake all night, waiting for us to finish this column. Hmm … you know, that reminds us of several hundred stories we’d like to tell you before we explain how today’s script works….

Never mind; we’re too tired for that ourselves. Instead, we’ll just point out that we start our script by defining a pair of constants, ForReading and ForWriting; we’ll need these two constants when we open the text files in question. We then assign values to two variables. The variable strFileName is assigned the name of the file that we need to modify; in our case, that’s Test.txt. Meanwhile, the variable strParentFolder is assigned the name of the, well, parent folder. For this sample script, that’s C:\Scripts\.

After taking care of those setup chores we next create an instance of the Scripting.FileSystemObject object; we’re going to use this multi-purpose COM object both to read from and write to text files as well as to retrieve a collection of all the top-level subfolders in C:\Scripts. We then construct a path to the text file in the parent folder (C:\Scripts\Test.txt) by combining the folder name and the file name:

strTextFile = strParentFolder & strFileName

Why do we need that path? That’s easy; in the next line of code we’re going to use the OpenTextFile method to open that text file for reading:

Set objFile = objFSO.OpenTextFile(strTextFile, ForReading)

As soon as the file is open we use the ReadAll method to read in the entire contents of the file, storing that information in a variable named strContents. We then use the Close method to close the file.

But not for long; we’ll be revisiting this file in a few seconds.

DJ didn’t tell us exactly what characters he needed to replace in these files, so we’ll use a simple example. Suppose each of these files lists the domain Contoso.com, and that domain has recently been changed to Fabrikam.com. How can we replace all instances of Contoso.com with Fabrikam.com? Why, like this, of course:

strContents = Replace(strContents, "Contoso.com", "Fabrikam.com")

All we’re doing here is using the Replace method to search through the variable strContents (a “virtual” copy of the text file) and replace any instances of Contoso.com with Fabrikam.com. Believe it or not, it’s that easy.

Of course, that only modified the virtual copy of the file; we now need to make these changes to the actual text file itself. To do that, we first re-open Test.txt, this time for writing:

Set objFile = objFSO.OpenTextFile(strTextFile, ForWriting)

Once that’s done we can call the Write method to overwrite the existing contents of the file with the value of strContents:

objFile.Write strContents

From there we call the Close method and we’re done.

Well, done with the file in the parent folder, at least; now we have to do something about the version of Test.txt that appears in each top-level subfolder. To that end, we use the following two lines of code to bind to the parent folder (C:\Scripts) and then return a collection of all the top-level subfolders of that folder:

Set objFolder = objFSO.GetFolder(strParentFolder)
Set colSubfolders = objFolder.Subfolders

Now we’re simply going to follow the same process as when we changed the copy of Test.txt found in the parent folder. To begin with, we construct a path to the copy of Test.txt in the first subfolder by using these two lines of code:

strFolderName = objSubfolder.Path
strTextFile = strFolderName & "\" & strFileName

Once we’ve constructed that path we use the FileSystemObject to open the file and read the contents into memory. We do our little search-and-replace operation, then write the modified contents back to the file. And then we loop around and repeat the process with the next subfolder in the collection.

Child’s play.

Well, assuming your children write system administration scripts, that is. And, apparently, some people’s children do.

And that’s it, DJ. Problem solved!

Before we call it a night we’d like to once more thank everyone who took part in the 2008 Winter Scripting Games; we are very excited about the number of people who entered this time around. (And a tip of the hat to all you Perl people; thank you for your support.) Remember, too, that while you can no longer submit a new entry for an event we have extended the deadline for resubmitting an existing entry; that deadline is now Thursday, March 6, 2008 at 8:00 AM Redmond time. In other words, if you got a 0 for one of your events, well, there’s no need to worry; you have until Thursday morning to fix the problem with your script and resubmit it. Assuming the new script works, you’ll get the points for that event.

Oh, and don’t forget to send us feedback regarding the Games. Let us know what you liked and what you didn’t like, and let us know what sorts of things you’d like to see included in the 2009 Games. And that includes ideas for events; if you have an idea for an event (for either the Beginners or the Advanced division), well, we’d love to hear about it.

And just think: if enough people submit event ideas, we might not have to do any thinking when it comes time to plan the 2009 Winter Scripting Games. Needless to say, not thinking about things is what the Scripting Guys do best.

Well, that and not sleeping.