May 22nd, 2007

How Can I Monitor the Number of Files in a Folder?

Hey, Scripting Guy! Question

Hey, Scripting Guy! We have a third-party application that rarely crashes; however, when it does crash it seriously disrupts our business. We can always tell when the application is getting ready to crash; at that point, one of its directories starts filling up with log files. How can we be notified any time the number of log files in this folder exceeds a specified value?

— AE

SpacerHey, Scripting Guy! AnswerScript Center

Hey, AE. You know, before we tackle this question there’s something we feel just has to be said: there are people in this world who are the embodiment of pure evil.

And no, Peter, for once we’re not thinking of you.

Although now that you mention it ….

The other night the Scripting Guy who writes this column stopped at the store on his way home and picked up a carton of milk. At that time the store was jam-packed, with 9 or 10 people standing in line at each checkstand … each checkstand, that is, except the express lane (15 items or less). With his single item safely in hand, the Scripting Guy who writes this column headed towards the express lane, only to be clipped from behind by a woman who shoved her shopping cart directly in his path, in order to get to the checkstand before he could.

Now, that was a bit rude (not to mention painful) but the Scripting Guy who writes this column was consoled by the fact that the lady was about to get her comeuppance. After all, she had way more than 15 items in the cart; there was absolutely no way the clerk would let her in line with that many items. But the Scripting Guy who writes this column didn’t count on the resourcefulness of the truly evil.

Before the clerk could say anything the woman spoke up. “I actually have two separate purchases here, “she said. “I need to pay for half of these items and get a receipt, then pay for the other half and get a separate receipt.” The implication, of course, is that she was buying food for two local orphanages, and needed separate receipts for tax purposes. (Although the Scripting Guy who writes this column couldn’t help but wonder, “What? Satan can’t do his own grocery shopping, you have to do it for him?”) As she explained the reason why she had barged into the express lane despite having way more than 15 items, she took all the groceries out of the shopping cart and piled them on the checkstand.

Note. In case you’re wondering, she had 15 items in pile 1 and 17 items in pile 2. Even her second pile by itself was over the 15-item limit!

Not that the Scripting Guy who writes this column was counting or anything.

To tell you the truth, the store clerk didn’t seem entirely comfortable with this. However, perhaps sensing the presence of pure evil, he decided to let it go. And what do you think happened? You got it: after he finished ringing up the last item in pile 1 the lady said, “You know, in order to make things easier for you, why don’t you just put everything on one order and I’ll pay for it all together.” (And yes, she actually did speak in italics. That’s what evil people do.) The clerk did what he was told, and a few minutes later the woman sashayed out of the store, having successfully purchased 32 items in the express lane (15 items or less).

Pure evil. And did we mention that she also drove an SUV and took up two parking spots in the parking lot? Even Dracula would only take one parking space, especially when the store was crowded.

But, then again, Dracula was at least part human.

Oh, well. Fortunately the Scripting Guys would never stoop that low. (Actually they would stoop that low, except the Scripting Guys would get beat up by angry patrons if they tried to sneak 32 items through the express lane.) For example, if you want to know how to monitor the number of files found in a particular folder, well, the Scripting Guys are only too happy to oblige:

strComputer = “.”

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

Do While True Set colFileList = objWMIService.ExecQuery _ (“ASSOCIATORS OF {Win32_Directory.Name=’C:\Logs’} Where ” _ & “ResultClass = CIM_DataFile”)

If colFileList.Count >= 100 Then Exit Do End If

Wscript.Sleep 60000 Loop

Wscript.Echo “There are at least 100 log files in the target folder.”

There are actually several different ways we could approach this problem; we ended up picking one that seemed pretty easy to script and pretty easy to understand. We begin by connecting to the WMI service on the local computer, although we could just as easily use this same script to monitor a folder on a remote computer; in that case all we have to do is assign the name of that computer (e.g., atl-fs-01) to the variable strComputer:

strComputer = “atl-fs-01”

We next set up a Do While loop, a loop seemingly designed to run forever and ever (or, at the very least, to continue running as long as True is equal to True):

Do While True

But don’t worry; that only sounds like a mistake on our part. As you’re about to see, our loop includes a loophole that enables us bring this seemingly-endless loop to an end.

For our sample script we’ve decided that 100 is the trigger value: if we ever get to 100 or more files in our target folder (C:\Logs) we want to be notified. And that’s a good question: how do we know how many files are in C:\Logs in the first place? Well, a very simple way to determine that is to use the following WMI query, a query that returns a collection consisting of all the files in C:\Logs:

Set colFileList = objWMIService.ExecQuery _
    (“ASSOCIATORS OF {Win32_Directory.Name=’C:\Logs’} Where ” _
        & “ResultClass = CIM_DataFile”)

Admittedly, the syntax is a little weird here. However, all we’re really doing is looking for items that are associated with a particular instance of the Win32_Directory class. (Which instance? The one with a Name of C:\Logs.) Of course, we’re only interested in these associated items if they, in turn, happen to be instances of the CIM_DataFile class; as you can probably guess, if something is an instance of the CIM_DataFile class then that something must be a file. This is kind of a roundabout way of doing things, but it’s also WMI’s way of returning a collection of all the files found in a given folder. If your files are stored in a different folder, well, then just replace the path C:\Logs with the path to your folder.

As it turns out, one of the nifty things about WMI collections is that each collection has a property named Count; this property tells us how many items (in this case, how many files) can be found in the collection. Hence our next line of code, which checks to see if the value of the Count property is greater than or equal to 100:

If colFileList.Count >= 100 Then

Note. What if your target value is actually 10 files or 10,000 files or whatever number of files? No problem; just change 100 to the desired value.

Let’s assume that the Count isn’t greater than or equal to 100; what happens then? Well, in that case we pause the script for 60 seconds (60,000 milliseconds):

Wscript.Sleep 60000

When one minute is up we then loop around and requery the folder C:\Logs, once again checking to see how many files are in the folder. And yes, we do need to requery each time around; that’s the only way to know the current number of files in the folder.

This also means that we’re checking every minute to see if the number of files in C:\Logs has exceeded the target value of 100. However, you can also change this value to anything you desire. For example, maybe 60 seconds is too long; maybe the folder can fill up with files and bring the application to a crashing halt faster than that. OK; here’s a minor modification that causes the script to pause for just 15 seconds (15,000 milliseconds) between checks:

Wscript.Sleep 15000

Alternatively, maybe you don’t need to check every minute; maybe every 10 minutes is good enough. Fine. If there are 60,000 milliseconds in a minute (and there are), then there must be 600,000 milliseconds in 10 minutes. Thus this line of code, which pauses the script for 10 minutes between checks:

Wscript.Sleep 600000

Etc.

Now, what if the Count is greater than or equal to 100? In that case we simply exit our “endless” loop:

Exit Do

And once we exit the loop we echo back a message informing us that the target value has been exceeded:

Wscript.Echo “There are at least 100 log files in the target folder.”

Now, admittedly, we don’t have to exit the loop; we did that simply so we wouldn’t get notified every minute that we had exceeded the target value. That’s the advantage to exiting the loop: fewer nags. The disadvantage? After we restart the application (or whatever we need to do to head off trouble) we’ll need to restart the monitoring script as well. If you don’t mind repeated notifications then you could rewrite the script so that it keeps running (and notifying you) even after the target value has been reached:

strComputer = “.”

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

Do While True Set colFileList = objWMIService.ExecQuery _ (“ASSOCIATORS OF {Win32_Directory.Name=’C:\Logs’} Where ” _ & “ResultClass = CIM_DataFile”)

If colFileList.Count >= 100 Then Wscript.Echo “There are at least 100 log files in the target folder.” End If

Wscript.Sleep 60000 Loop

We should also mention that you aren’t limited to using Wscript.Echo as a way to issue a notification. For example, you might want to write an event to the Application event log, or maybe send an email using the SMTP service. That’s entirely up to you.

Of course, what would really be cool is if the script could fix the application for you. We can’t provide any sample code because we don’t know anything about the application. But it’s possible that the script could stop and then restart the application; that depends entirely on the application. (At the very least, you could no doubt terminate the application process and then restart it. But, depending on the application, that might create more problems than it solves.)

We hope that helps, AE, and we hope that, unlike the Scripting Guy who writes this column, you haven’t lost your faith in humanity. As it is, and to add insult to injury, when he came to work this morning he stopped by the kitchen and grabbed a plastic spoon out of the big bin labeled Plastic Spoons. As he sat down in his office and prepared to eat his daily raspberry yogurt he suddenly realized that he was holding a plastic fork: someone had put a plastic fork in the bin labeled Plastic Spoons!

Evil, pure evil.

Author

0 comments

Discussion are closed.