2008 Winter Scripting Games

Solution to Beginner VBScript Event 3: Let’s Get Together

Event 3 Solution


VBScript solution to Event 3 in the 2008 Winter Scripting Games.

Solutions are also available for Windows PowerShell and Perl.

*

Event 3 – Let’s Get Together

This event was all about finding files within folders, reading from those files, and even creating new files. Whew, that’s a lot. Let’s get started and see how we solved this one:

Const ForReading = 1
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")

strComputer = "."

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

Set colFiles = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='C:\scripts'} Where " _
        & "ResultClass = CIM_DataFile")

For Each objFile in colFiles

    If objFile.Extension = "txt" Then
        strFilePath = objFile.Name

        Set objFile = objFSo.OpenTextFile(strFilePath, ForReading)
        strLine = objFile.ReadLine
        objFile.Close
    
        strContents = strContents & strLine & vbcrlf
    end if
Next

Set objFileNew = objFSo.CreateTextFile("C:\temp\newtext.txt", ForWriting)

objFileNew.Write strContents
objFileNew.Close

The first thing we do is define a couple of constants:

Const ForReading = 1
Const ForWriting = 2

When you use the FileSystemObject to work with files, you can either read from a file or write to it, but you can’t do both at the same time. Since we want to do both we define these constants; that way we’ll be able to tell the FileSystemObject when we’re reading and when we’re writing.

That will make more sense in a moment.

Next we actually create the FileSystemObject:

Set objFSO = CreateObject("Scripting.FileSystemObject")

At this point we set the FileSystemObject aside for a moment and prepare to work with WMI. Don’t worry, we’ll get back to the FileSystemObject. But first we set the variable strComputer to a dot:

strComputer = "."

The dot represents the local computer. We defined this variable so we can connect to WMI on the local computer:

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

And sure, we could just as easily have done this:

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

But it’s pretty standard practice to define a variable and assign it the name of the computer; that way if you want to work against a different computer it’s clear what needs to change. (Although, it doesn’t really matter in this case because we’ll always be working against the local computer. It’s not impossible to read text files from a remote computer using VBScript, but it’s not all that easy, either. Therefore, we stuck with the local machine for these beginner events.)

All right, we’ve connected to WMI, now we’re going to use WMI to find all the files in the C:\scripts folder:

Set colFiles = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_Directory.Name='C:\scripts'} Where " _
        & "ResultClass = CIM_DataFile")

In this line we’re running the ExecQuery method against the WMI service. The ExecQuery method does exactly what it sounds like it does: it executes a query. What query? Well, the query we passed to it as a parameter. In particular, this query:

ASSOCIATORS OF {Win32_Directory.Name='C:\scripts'} Where ResultClass = CIM_DataFile

All we’re doing here is querying the Win32_Directory class for all files (all CIM_DataFile objects) in the directory with the Name C:\Scripts.

And what are we going to do with all those files? Well, the first thing we need to do is read through each of those files and find out which ones are text files. We set up a For Each loop to read through the list of files, then use an If statement to figure out whether the file is a text file:

For Each objFile in colFiles

    If objFile.Extension = "txt" Then

In the If statement we check the Extension property of the file object. If the extension is equal to txt we know the file is a text file. This is why we used WMI to find the files. If we had used the FileSystemObject, we would have had to retrieve the Name property of the File object, then parse the name to find the extension. That isn’t a particularly difficult thing to do, but we that thought as long as WMI files have an Extension property we might as well use it.

If the Extension isn’t equal to txt, meaning the file is not a text file, we simply ignore it, loop back around, and check the next file. If the file is a text file we need to retrieve the first line of that file. We start by retrieving the full path to the file:

strFilePath = objFile.Name

Yes, we know, we’re using the Name property so you might be expecting just the filename, but that’s not what you’ll get; the Name property returns the entire name and file path. But that’s a good thing, because that’s exactly what we want. That’s because we’re going to use that file path to open the file:

Set objFile = objFSo.OpenTextFile(strFilePath, ForReading)

To open the file we use the OpenTextFile method of our FileSystemObject (see, we told you we’d get back to that). We pass OpenTextFile two parameters: the full path to the file we’re opening (strFilePath) and the constant ForReading, which will open the file so we can read from it. Remember we want to read only the first line of each file. The way to retrieve a single line from a text file is by calling the ReadLine method:

strLine = objFile.ReadLine

At this point we’ve read the line from the file and stored it in the variable strLine, so we don’t need this file anymore; we can go ahead and close it:

objFile.Close

Our ultimate goal is to put the first line from each text file into a new file. Conversely, that means the new file will consist of the first line of each file. So what we need to do is build contents of the new file. We do that by storing each line in a variable:

strContents = strContents & strLine & vbCrLf

What we’re doing here is combining the contents of the variable strContents with the line we just read, and putting a carriage return linefeed character on the end (that’s what the VBScript constant vbCrLf is for). When we loop around and do this for each text file, strContents will eventually contain each line from each text file, with each line ending with a carriage-return linefeed.

After we’ve looped through all the files, it’s time to create the new file. We do that by calling the FileSystemObject’s CreateTextFile method:

Set objFileNew = objFSo.CreateTextFile("C:\temp\newtext.txt", ForWriting)

We pass two parameters to CreateTextFile: the full path and filename of the new file, and the constant ForWriting, which specifies that we’re going to write to this file. And speaking of writing to the file, let’s do that:

objFileNew.Write strContents

All we had to do was call the Write method, passing it the contents we had stored in the strContents variable.

Now we can close the new file:

objFileNew.Close

We now have a file named newtext.txt in the C:\Temp folder that contains the first line from every text file in the C:\Scripts folder. And that just happens to be exactly what we needed to do to successfully complete this event.


Top of pageTop of page