Ok, so now that we are all up to speed and on the same page, let's get on with the learnin', shall we? This article will focus on manipulating the Windows filesystem using the VBS FileSystemObject. Why do we want to do this? Well, as I'm sure you know, lots of times users need things done on file servers, or you need to create home directories for new users, or copy base profiles, all sorts of stuff. If you get it all into one script, it saves lots of time in the long run. So, to get at the filesystem:
Set oFS = CreateObject("Scripting.FileSystemObject")
If you run that, you'll get a text file created in the root of your C: drive called myfile.txt, and it will contain one line that says
Easy, huh? This is useful for when you are debugging applications that have a LOT of data in them (like arrays of over 1000 objects), and echoing all of that data to the screen simply isn't practical. Why do I say that this is only useful for debugging? Well, the CreateTextFile method will overwrite any text file that is there, so you'll have a fresh one every time, with only the data from the last run. If you wanted to append to a text file, then we can use another filesystem method, FileExists:
Set oFS = CreateObject("Scripting.FileSystemObject")If oFS.FileExists("c:\myfile.txt") Then Set oFile = oFS.OpenTextFile("c:\myfile.txt", 8)Else Set oFile = oFS.CreateTextFile("c:\myfile.txt")End IfoFile.Writeline("Hello")oFile.Close
That will check to see if the file exists, and if the file does not exist, then it will create it and allow you to write to it; if it does exist, it will open it and begin appending data at the end of the file, as opposed to completely overwriting the file (the 8 in the OpenTextFile function in line 3 indicates "ForAppending"). This is useful for logging for automated processes. Now, what if we want to have a different log file every day? We can use the built-in date functions to get that information for us and create the filenames on the fly.
Set oFS = CreateObject("Scripting.FileSystemObject")mo = Month(Now)da = Day(Now)yr = Year(Now)filename = CStr(yr) & CStr(mo) & CStr(da)If oFS.FileExists(filename) Then Set oFile = oFS.OpenTextFile(filename, 8)Else Set oFile = oFS.CreateTextFile(filename)End IfoFile.Writeline("Hello")oFile.Close
And there you have it. Every time you run this piece of code, it will check today's date, and look for a file with that name. If it exists, it will append text to the end of it. If it does not exist, it will create it. How did we get the date? Well, Now is a reserved word, a function that returns the date and time right now. Year returns only the year, Month returns only the month, Day returns only the day, Hour would return only the hour, Minute would return only the current minute. So, if you open your IDE and run this single line of code:
the output you get will be the date and time that you run it, and it will be localized (different countries display the month/day in different orders, some use a / to separate, some a -, etc). The problem with this, as far as file system organization, is that it is not all two digit, so when you go to sort, it might be out of order. For example, if we go YearMonthDay.txt, you might have a group of files that look like this:
The code above does essentially this: filename is set to the year, then the month is retreived, and is added to a 0. So, if it is January, the month would be 01. If it is December, the month would be 012. But, since we only want a 2-digit month, we take the Right(string,2) of it - the "2" in the expression says take the right-most two characters. So 01 becomes 01, and 012 becomes 12. Same principle for the day. Another thing to note: the "&" character is the string concatenation character. This takes two strings, and just shoves them together. So, if we had
As mentioned previously, the 8 used in the OpenTextFile method causes output to be appended to the existing file. If you want to open a text file for reading ONLY, then you would use a "1" there, like this:
Set oFS = CreateObject("Scripting.FileSystemObject")Set oFile = oFS.OpenTextFile("c:\myfile.txt",1)data = oFile.ReadlineoFile.Close
Now, the file is safe. It is opened in read-only mode, so no data can be accidentally changed. Also, this introduces the Readline method of the FileSystemObject object. That will read to the next vbCrLf(CarriageReturnLineF
eed). vbCrLf is a reserved word, and can be used at any point in string concatenation to go to the next line. For example, if you had a very long string that you wanted to echo, instead of it opening a messagebox that would display across the entire monitor, you could break it up with vbCrLf, like this:
That will display on three separate lines. It's much easier to read. About inserting vbCrLf - the Writeline method will do that for you automatically at the end of the string you pass in. If you would prefer manual control over placement of line breaks, you can simply use the Write method, and you will need to insert your own line breaks then.
Another useful string method is Split This is useful when you are reading from files that contain records, such as CSV files. Some files use pipes ( | ) for delimiters, some will use other characters, but record layouts always have some type of delimiter to separate the fields. How can we handle that?
We used Split to create an array named fields that contains each field that was in the line that we read. What is an array? Think of it like a drawer in a file cabinet. A single file drawer holds multiple files, right? Well, an array is a single variable that holds multiple values. They are accessed like this:
Arrays are always numbered beginning with 0, and are referred to as being "zero-based". So, the example code above would read the line, split the line of text with all the fields on the commas in the line, and store each field in a separate array position. But what if there are more than 3 fields? What if there are 100 fields? We don't want to have to type out 100 lines of WScript.Echo(fields(100)),
so what can we do? Well
Set oFS = CreateObject("Scripting.FileSystemObject")Set oFile = oFS.OpenTextFile("c:\MyFile.CSV",1)data = oFile.Readlinefields = Split(data,",")For i = 0 to UBound(fields) WScript.Echo(fields(i))NextoFile.Close
is one way of doing it. Note the use of "UBound(fields)" This returns an integer value that tells you what the Upper Boundary of the array is. Since you can have arrays of any size, it is very important that you know how large the array is so that you don't get an "Index out of Bounds" error generated. Another way to handle this would be:
Set oFS = CreateObject("Scripting.FileSystemObject")Set oFile = oFS.OpenTextFile("c:\MyFile.CSV",1)data = oFile.Readlinefields = Split(data,",")For Each field in fields WScript.Echo(field)NextoFile.Close
That will automatically go through the array one item at a time and echo the contents.
Another useful string method is InStr For example, say you want to read an entire file, and every line that contains the word "the" should be echoed.
Set oFS = CreateObject("Scripting.FileSystemObject")Set oFile = oFS.OpenTextFile("c:\MyFile.txt",1)Do While Not oFile.AtEndOfStream data = oFile.Readline If InStr(data,"the") Then WScript.Echo dataLoopoFile.Close
In that code is also the control logic to read an entire file, using AtEndOfStream.
Now, say you had that same file, but you wanted to replace the word "apple" with the word "orange" everywhere in the file.
Set oFS = CreateObject("Scripting.FileSystemObject")Set inputFile = oFS.OpenTextFile("c:\MyFile.txt",1)Set outputFile = oFS.CreateTextFile("c:\newfile.txt")Do While Not inputFile.AtEndOfStream data = inputFile.Readline data = Replace(data,"apple","orange") outputFile.Writeline(data)LoopinputFile.CloseoutputFile.Close
So, now that we've got some basic filesystem stuff down, adding logging to our scripts should be a piece of cake. An example on logging errors was provided in the previous installment of this series, be sure to take a look at it if you haven't already. The next installment will cover functions and subroutines, why they're useful, and how to write them. Until then...