Hey, Scripting Guy! Question

Hey, Scripting Guy! On my file servers I periodically want to check a folder to see if that folder or any of its subfolders have files that are no longer being updated. What I’d like to do is check each file in each folder to see if they’ve been modified in the past 90 days. If I find a folder in which none of the files have been modified recently I’d like the script to echo back the folder path. How can I write a script that will do that?

-- MM

SpacerHey, Scripting Guy! AnswerScript Center

Hey, MM. Well, as we noted yesterday, today marks the last Hey, Scripting Guy! for 2007; after today we’ll take a break, then resume posting new columns on January 2, 2008. Seeing as how this is the last column of the year, we also thought we’d start out by recalling some of the Scripting Guys more memorable achievements of the past 12 months:

 

 

OK, maybe “achievements” was the wrong word. Let’s just see if we can recall some of the more memorable events which happened over the past 12 months. Here’s one: Scripting Guy Dean Tsaltas received is Master’s degree in Computer Science from Oxford University. Way to go, Dean!

What’s that? He hasn’t gotten his degree yet because he still has written his Master’s thesis? Gee, that doesn’t sound like Dean. Well, OK then, what else happened this year? Let’s, see Scripting Peter Costantini went to Nicaragua, where he was harassed by monkeys.

You know, now that you mention it, that really wasn’t all that big of a deal, was it? After all, Peter gets harassed by monkeys pretty much everywhere he goes. Nicaragua, Salt Lake City, 7-11, you name it. There just seems to be something about Peter and monkeys.

What else? Here’s a good thing: Scripting Guy Jean Ross finally made it to Paris! Of course, in all fairness she did have mixed emotions about that. On the one hand she got to go to Paris. On the other hand, she missed her 75-year high school reunion. But don’t worry, Jean; your 100th reunion is just around the corner.

As for Scripting Guy Greg Stemp, well, the less said about Scripting Guy Greg Stemp the better.

Anyway, that pretty much sums up the year. Not particularly memorable but, on the bright side, we expect 2008 to be a way better year. After all, it pretty much would have to be a way better year.

Now that that’s taken care of let’s see if we can help MM with her problem. MM needs a script that can look at all the files in a folder (and all its subfolders) and report back any folders that have nothing but old files; that is, a folder where none of the files have been modified in the past 90 days. How can she do that? Here’s one way:

Set objFSO = CreateObject("Scripting.FileSystemObject")

Set objStartFolder = objFSO.GetFolder("C:\Scripts")
Set colFiles = objStartFolder.Files

i = 0

For Each objFile in colFiles
    dtmDate = objFile.DateLastModified
    intAge = DateDiff("d", dtmDate, Date)
    If intAge < 90 Then
        i = 1
        Exit For
    End If
Next

If i = 0 Then
    Wscript.Echo objStartFolder.Path
End If

ShowSubfolders(objStartFolder) 

Sub ShowSubFolders(Folder)
    For Each objSubfolder in Folder.SubFolders
        Set objFolder = objFSO.GetFolder(objSubFolder.Path)
        Set colFiles = objFolder.Files

        i = 0

        For Each objFile in colFiles
            dtmDate = objFile.DateLastModified
            intAge = DateDiff("d", dtmDate, Date)

            If intAge < 90 Then
                i = 1
                Exit For
            End If
        Next

        If i = 0 Then
            Wscript.Echo objSubfolder.Path
        End If
 
        ShowSubFolders objSubfolder
    Next
End Sub

OK, yes, we know: this script does look awfully big, at least for a Hey, Scripting Guy! script. But don’t panic; that’s because – in order to make things easier to follow – we’ve duplicated a large hunk of the code. As you’re about to see, it’s nowhere near as intimidating as it might look. For example, there’s nothing very scary about the way the script kicks off. We start out by creating an instance of the Scripting.FileSystemObject, then use these two lines of code to bind to the folder C:\Scripts and return a collection of all the files found in that folder:

Set objStartFolder = objFSO.GetFolder("C:\Scripts")
Set colFiles = objStartFolder.Files

Note. What about all the subfolders of C:\Scripts? Don’t worry; we’ll get to those in a minute.

After we retrieve our collection of files, we set the value of a counter variable named i to 0; we’ll use this variable to keep track of any files that have been modified in the past 90 days. That brings us to this block of code:

For Each objFile in colFiles
    dtmDate = objFile.DateLastModified
    intAge = DateDiff("d", dtmDate, Date)
    If intAge > 90 Then
        i = 1
        Exit For
    End If
Next

What we’re doing here is cycling through all the files in the folder C:\Scripts to see if we can find any files that have been modified in the past 90 days. (What about all the subfolders of C:\Scripts? Don’t worry; we’ll get to those in a minute. Promise!) For each file in the collection we grab the value of the DateLastModified property and assign it to a variable named dtmDate:

dtmDate = objFile.DateLastModified

From there, we use VBScript’s DateDiff function to determine the number of days ("d”) that have elapsed between the date the file was last modified (dtmDate) and the current date (the VBScript Date function). We then check to see if this value is less than 90:

If intAge < 90 Then

Let’s assume that intAge isn’t less than 90, indicating that the file hasn’t been modified in the past 90 days. What does that mean? Well, it means we have yet to find a “new” file in this folder; therefore, we zip back to the top of the loop and perform this same check with the next file in the collection.

Now, suppose that intAge is less than 90; that means that we’ve found a new file. Therefore, we do two things. First, we set the value of our counter variable to 1; after that, we call the Exit For statement to exit our For Each loop.

Note. Why do we exit the loop? Well, remember, we’re looking for folders that don’t have a single file that has been modified in the past 90 days. All we have to do is find one such file; now that we have, there’s no need to loop through all the other files in the collection.

Our next step is to determine whether or not the counter variable i is equal to 0. If it is, that means this particular folder doesn’t have even one file that has been accessed in the past 90 days. That’s exactly what we were looking for, so we echo back the folder path. That’s what this block of code does:

If i = 0 Then
    Wscript.Echo objStartFolder.Path
End If

So much for C:\Scripts. But what about all the subfolders of C:\Scripts?

You know, we’re glad you asked that question. After we dispose of C:\Scripts, we then use this line of code to call a recursive subroutine named ShowSubfolders, passing this subroutine the path to our starting folder (C:\Scripts):

ShowSubfolders(objStartFolder)

We aren’t going to discuss recursive functions and subroutines today; that’s more than we can handle in a single Hey, Scripting Guy! column. (Especially one written the day before we start an 18-day break.) If you’d like to know a little bit more about recursion, take a peek at this section of the Microsoft Windows 2000 Scripting Guide.

For now, we’ll just note that a recursive subroutine is a subroutine that can call itself. What does that mean? Well, notice that the first thing we do inside this subroutine is set up a For Each loop to loop through all the top-level subfolders in C:\Scripts:

For Each objSubfolder in Folder.SubFolders

What are we going to do with each of these subfolders? The very same thing we just finished doing with the parent folder C:\Scripts: we’re going to check all the files to see if any of them have been modified in the past 90 days. We’ll go through the first subfolder (e.g., C:\Scripts\Subfolder1) and check all the files. If appropriate, we then echo back the folder path, indicating that folder doesn’t have a single file that has been modified in the past 90 days.

That takes care of Subfolder1. However, before we go on to Subfolder2 we execute this line of code:

ShowSubFolders objSubfolder

That’s right: even though we’re already in the subroutine ShowSubFolders we go ahead and call ShowSubFolders again. (Weird, but that’s what recursion is all about.) What that’s going to do is cause the script to repeat this process with any subfolders of C:\Scripts\Subfolder1, then repeat it again on any sub-subfolders of C:\Scripts\Subfolder1. Only when we finally run out of subfolders will we jump back to the top of our original For Each loop and start checking C:\Scripts\Subfolder2.

Note. Yes, it is kind of hard to visualize, isn’t it? Fortunately, however, you don’t have to understand how recursion works and how the script keeps track of where it is and where it needs to go next. VBScript does all that for you.

And that’s all we have to do, When the script finishes we’ll see, onscreen, a list of any folders (or subfolders) in which none of the files have been modified in the past 90 days. Which is nice, because that’s what we were hoping to see.

Note. We should note that this script is designed to work only on the local computer; that’s because MM didn’t need it to work against a remote computer. Could it be modified to perform this same task against a remote machine? No, not really; instead it would have to be completely rewritten using WMI rather than the FileSystemObject. We don’t really have any plans to tackle that – it’s a bit gnarly, to say the least – but if there’s enough interest we’ll see what we can do. Just let us know.

That should do it for today, MM, and that should do it for 2007 as well. Have a happy holiday everyone (even you, Scripting Editor!) and we’ll see you all back here on January 2, 2008.