Hey, Scripting Guy! How can I monitor a folder for new files and then automatically open each new file that gets added to that folder?
— CA
Hey, CA. You know, today is Valentine’s Day in the US, which means that right now most American men are saying to themselves, “What? Today is Valentine’s Day? Uh-oh ….” We’re not sure how many other countries around the world celebrate Valentine’s Day, but in the US today is the day when you’re supposed to lavish your significant other with jewelry, flowers, chocolates, heartfelt cards and other expensive gifts, all as a way to say thank you for the … wonderful … things they do for you.
Note. In case you’re wondering, the answer is no; instead, the Scripting Guy who writes this column and his son are going to a college basketball game tonight. On the other hand, what greater gift could this Scripting Guy give someone than to not hang around with them? |
If you’re not familiar with the occasion, Valentine’s Day is named after St. Valentine, although which St. Valentine remains a matter of debate. (Apparently, in the early days of Christianity there were at least three St. Valentines.) According to legend, sometime in the third century a Roman emperor barred young men from getting married; he believed that unmarried men would make better soldiers. (Today most scholars disagree with that, pointing out that no one has more fighting experience than a married man.) As the story goes, St. Valentine was a priest who elected to defy the emperor, continuing to perform marriages in secret. When he was caught, he was martyred for his faith, although not before sending a note to a young lady signed, “From your Valentine.” The rest is history.
Or legend. Take your pick.
At any rate, if you’re like most American men you haven’t gotten that certain special someone anything for Valentine’s Day. Might we suggest a script that monitors a folder for new files and then automatically opens each new file that gets added to that folder:
Set objShell = CreateObject(“Wscript.Shell”)strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _ (“SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE ” _ & “Targetinstance ISA ‘CIM_DirectoryContainsFile’ and ” _ & “TargetInstance.GroupComponent= ” _ & “‘Win32_Directory.Name=””c:\\\\scripts””‘”)
Do Set objLatestEvent = colMonitoredEvents.NextEvent strNewFile = objLatestEvent.TargetInstance.PartComponent arrNewFile = Split(strNewFile, “=”) strFileName = arrNewFile(1) strFileName = Replace(strFileName, “\\”, “\”) strFileName = Replace(strFileName, Chr(34), “”) objShell.Run(“notepad.exe ” & strFileName) Loop
And no, you don’t need glasses: the script really does look like that. But maybe it will help if we explain why it looks like that.
We start out simple enough, creating an instance of the Wscript.Shell object, the object we’ll use to open a file. We then do something equally straightforward, connecting to the WMI service on the local computer. (Although, as usual, this script works equally well against a remote machine.)
We then encounter this line of code:
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _ (“SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE ” _ & “TargetInstance ISA ‘CIM_DirectoryContainsFile’ and ” _ & “TargetInstance.GroupComponent= ” _ & “‘Win32_Directory.Name=””c:\\\\scripts””‘”)
We won’t explain this monstrosity in minute detail today; for that you might take a peek at the Scripting Guys webcast An Ounce of Prevention. In brief, this query is designed to check the folder C:\Scripts every 10 seconds and see if any new files have been added to that folder. How do we know that this query checks for new files? Well, we know that it’s looking for new items because it’s querying for instances of the __InstanceCreationEvent class. And we know that we’re looking for files because we’re specifying that we’re only interested in new members of the __InstanceCreationEvent class if they happen to also be members of the CIMDirectoryContainsFile class.
And that’s not all. The 10 second interval between checks is what the WITHIN 10 is all about; if that value is too long or too short then just adjust the time accordingly. Last but surely not least, we know that we’re looking at the C:\Scripts folder because of this:
‘Win32_Directory.Name=””c:\\\\scripts””‘
For better or worse, all those \’s and all those single and double quote marks are required.
Got all that? Well, to be honest, we don’t, either. But if you use the preceding example as a template and change only those items (such as the folder name) that you need to change you should be fine.
We’d like to tell you that all the craziness is over, but we can’t do that; there’s still a bit more craziness to come. Our next step is to set up a Do loop that’s designed to run forever; you might note that there’s no exit criteria like “Do Until x = 1” or “Do While x < 10”:
Do
Inside that loop the first thing we do is issue a command that causes the script to “block.” That simply means that the script will sit on this line of code until our query notifies us that an event of interest has occurred:
Set objLatestEvent = colMonitoredEvents.NextEvent
Needless to say, thanks to the criteria specified in our query, such notification can only mean one thing: a new file has been added to C:\Scripts.
Now the craziness returns. Each time a new file is added to the folder we get notified; in addition, we can take a peek at the PartComponent property to determine the file path:
strNewFile = objLatestEvent.TargetInstance.PartComponent
That’s the good news. The bad news is that the PartComponent looks something like this:
\\ATL-WS-01\root\cimv2:CIM_DataFile.Name=”c:\\scripts\\New Text Document.txt”
Yuck. But don’t despair; we can extract the path from that. Guaranteed.
To do that, we first use the Split function to split the PartComponent on the equals sign. That’s going to give us an array consisting of two items:
• |
\\ATL-WS-01\root\cimv2:CIM_DataFile.Name |
• |
“c:\\scripts\\New Text Document.txt” |
As you can see, the path we need is – more or less – contained in the second item in the array. (Which, arrays being what they are, the second item in the array is assigned the index number 1.) With that in mind, we use this line of code to put this item into a variable named strFileName:
strFileName = arrNewFile(1)
Now we just need to clean things up a bit. First, we use the Replace function to replace any double \ characters with a single \, like so:
strFileName = Replace(strFileName, “\\”, “\”)
That’s leaves strNewFile equal to this: “c:\scripts\New Text Document.txt“. That right there is our file path. Or at least it will be after we use the Replace function to remove the double quote marks (which have an ASCII value of 34):
strFileName = Replace(strFileName, Chr(34), “”)
And now that strFileName contains the real path to the new file we can use the Run method and open the new file in Notepad:
objShell.Run(“notepad.exe ” & strFileName)
Good question: do you have to open new files in Notepad? No. However, you do need to specify an executable file; we can’t just ask the Run method to directly open the file C:\Scripts\New Text Document.txt. We took the easy way out here and assumed that all the new files that might be added to C:\Scripts can be opened with Notepad. If that’s not the case then you’ll need to add some additional code to the script, code that checks the file extension and then runs the appropriate application (e.g., it calls Excel if we happen to be dealing with a .xls file). Most likely you can figure that part out on your own. If not, we’ll cover it in a future column.
With any luck that will not only answer your question, CA, but also take care of your Valentine’s Day shopping. If not, maybe we could be so presumptuous as to suggest a Dr. Scripto Bobblehead doll for that certain special someone. Granted, you can’t actually buy a Dr. Scripto Bobblehead doll, but there’s still time to win one as part of the 2007 Winter Scripting Games. All you have to do is enter an event and you’re automatically entered in a drawing to win one of 250 Dr. Scripto bobbleheads.
Sure, it doesn’t sound like much. But what man or woman could say no to a face like this:
Error: objLatestEvent.TargetInstance.PartComponent
Object does not support this method or property