Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to search a certain directory for files with a size of 0 KB, then replace the non-existent text in those files with an error message like this one: "File did not save correctly." I have been searching for the answer myself and can't seem to grasp it. Can you help me on this one?

-- CE

SpacerHey, Scripting Guy! AnswerScript Center

Hey, CE. Have you ever heard the expression “One man’s meat is another man’s poison?” Well, the idea behind that saying is that what might be good for one person (meat) might not be good for another person (poison).

Note. Unless you’re a vegetarian, in which case meat isn’t good for you, either. We’re assuming that vegetarians won’t eat poison, although, come to think of it, many vegetarians will eat okra. As near as we can tell, there isn’t a whole heck of a lot of difference between poison and okra.

Other than the fact that the poison probably tastes better. (To be honest, it couldn’t taste much worse.)

So what does all this have to do with scripting? Well, to CE this was a bad question; he couldn’t find an answer to it anywhere. To the Scripting Guy who writes this column, however, this was a good question; still a bit bedraggled after the close of the 2008 Winter Scripting Games, he was hoping for a question he could answer with a minimal amount of effort. As the old saying goes, one man’s meat is another man’s way of doing his job without having to actually do much of anything.

So how much effort is required to carry out this task? Like we said, not much at all:

Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder("C:\Logs")

Set colItems = objFolder.Files

For Each objItem in colItems
    If objItem.Size = 0 Then
        Set objFile = objFSO.OpenTextFile(objItem.Path, ForWriting)
        objFile.WriteLine "File did not save correctly."
        objFile.Close
    End If
Next

See? We told you that there isn’t much meat here. Or, if you happen to be another man, there isn’t much poison here.

Note. You see, because one man’s meat is another man’s – well, never mind.

We start out by defining a constant named ForWriting and setting the value to 2; we’ll need this constant when we write the message File did not save correctly to each empty file. After defining the constant we create an instance of the Scripting.FileSystemObject object, then use the GetFolder method to bind to the folder C:\Logs:

Set objFolder = objFSO.GetFolder("C:\Logs")

As soon as we make the connection we can retrieve a collection of all the files found in C:\Logs. We do that by creating an object reference (colItems) to the folder’s Files property:

Set colItems = objFolder.Files

We now have a collection of all the files found in C:\Logs. That’s great. The only question is: what exactly are we going to do with this collection?

Well, to begin with, we’re going to set up a For Each loop to walk us through each and every file in the collection. Inside that loop, the first thing we’re going to do is check to see if the file Size is equal to 0 bytes:

If objItem.Size = 0 Then

If this line of code returns True that means that we have an empty file on our hands. With that in mind, we again turn to the FileSystemObject, this time using the object to open the file for writing:

Set objFile = objFSO.OpenTextFile(objItem.Path, ForWriting)

Note. How did the FileSystemObject know which file we wanted to open? Well, the FileSystemObject pretty much knows everything. But, just in case, we passed it the value of the file’s Path property. As the name implies, the Path property is going to be a value similar to this: C:\Logs\Test.txt. Given that information, how could the FileSystemObject not know which file to open?

After we open the file we then use the WriteLine method to replace the empty file with the message File did not save correctly:

objFile.WriteLine "File did not save correctly."

Once we’ve done that we close the file, then loop back to the top of the loop and repeat the process with the next item in the collection.

All in all, pretty darn easy.

Of course, there is one drawback to the script: it will work on only the local computer. What if you need to perform this task against a remote machine?

To tell you the truth, that’s a bit of a problem; that’s because the FileSystemObject isn’t designed to work against remote computers. Nevertheless, there is a workaround: we can use WMI to retrieve a collection of all the files in a remote folder, then use UNC paths and administrative shares to coerce the FileSystemObject into writing our message to any empty files in that folder. Is this a hack of some kind? Sort of. But it works, provided that you use administrative shares:

Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")

strComputer = "gizmonic"

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

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

For Each objItem In colItems
    If objItem.FileSize = 0 Then       
        strFilePath = "\\" & strComputer & "\C$\Temp\" & _
            objItem.FileName & "." & objItem.Extension
        Set objFile = objFSO.OpenTextFile(strFilePath, ForWriting)
        objFile.WriteLine "File did not save correctly."
        objFile.Close
    End If
Next

We aren’t going to explain this script in any detail today. For more information about working with text files on remote computers, see our column on, well, working with text files on remote computers. That will also explain what we mean by administrative shares.

That should do it, CE. And that should just about do it for the 2008 Winter Scripting Games as well. Remember, if you see a problem with your score or if you want to resubmit an entry please do it now. (Yes, we know: technically, the deadline for inquiries/resubmissions has passed. But, hey, when’s the last time the Scripting Guys cared about technicalities?) Let us know soon. On Monday. March 10th we’re going to start drawing for prizes, and we’ll start notifying both prize winners and/or people who qualified for a Certificate of Excellence. We don’t want anyone to be left out.

And no, not even all those people who wrote in to complain about Event 5 in the Beginners Division. One man’s solution to a Scripting Games event is another man’s okra.

Or something like that. As the Scripting Editor will attest, the Scripting Guy who writes this column doesn’t always pay much attention when other people say things.