VBScript for Windows System Administrators - Part 3

Published:
Welcome, welcome!  If you are new to the series and haven't been following along, please take a brief moment to review the first three installments:

Part 1
Part 2
The Missing Prequel


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")

Open in new window


So, now we have a handle that we can use to access the filesystem - oFS.  What can we do with it?

Set oFS = CreateObject("Scripting.FileSystemObject")
                      Set oFile = oFS.CreateTextFile("c:\myfile.txt")
                      oFile.Writeline("Hello")
                      oFile.Close

Open in new window


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

Hello

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 If
                      oFile.Writeline("Hello")
                      oFile.Close

Open in new window


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 If
                      oFile.Writeline("Hello")
                      oFile.Close

Open in new window


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:

WScript.Echo(Now)

Open in new window


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:

201011
2010110
2010111
...
201012
2010120
2010121
...
201013
2010130
2010131
201014
201015

We'd rather that the filenames were a unform size.  So how do we fix this?  Well, when we created our filename, we should have inserted extra zeros.  This could be done like this:

filename = CStr(year(Now))
                      If mo < 10 Then
                          filename = filename & "0" & CStr(mo)
                      Else
                          filename = filename & CStr(mo)
                      End If
                      If da < 10 Then
                          filename = filename & "0" & CStr(da)
                      Else
                          filename = filename & CStr(da)
                      End If

Open in new window


That would get you a 4 digit year followed by a two digit month and a two digit day.  But, there is a much easier way.  We can use the string function Right, like so:

filename = CStr(Year(Now)) & Right("0" & CStr(Month(Now)),2) & Right("0" & CStr(Day(Now)),2)

Open in new window


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

h = "hello"
                      w = "world"
                      q = h & w
                      WScript.Echo(q)

Open in new window


The output would be:             helloworld               There wouldn't be a space.  If you want a space, you put put the space in there.

h = "hello"
                      w = "world"
                      q = h & " " & w
                      WScript.Echo(q)

Open in new window


Now the output would be             hello world                      because we inserted the space.  

Ok, so back to our filesystem:  The same thing can be done with folders as with files.  For example, say that you wanted each of your log files arranged in a folder hierarchy like this:

Year  (folder)
--Month  (folder)
----Log Files  (text files)

No problem!

Set oFS = CreateObject("Scripting.FileSystemObject")
                      yr = CStr(Year(Now))
                      mo = Right("0" & CStr(Month(Now)),2)
                      da = Right("0" & CStr(Day(Now)),2)
                      YearFolder = "C:\" & yr
                      If Not oFS.FolderExists(YearFolder) Then oFS.CreateFolder(YearFolder)
                      MonthFolder = YearFolder & "\" & mo
                      If Not oFS.FolderExists(MonthFolder) Then oFS.CreateFolder(MonthFolder)
                      FileName = MonthFolder & "\" & yr &mo & da & ".txt"
                      If oFS.FileExists(FileName) Then
                          Set oFile = oFS.OpenTextFile(FileName,8)
                      Else
                          Set oFile = oFS.CreateTextFile(Filename)
                      End If
                      oFile.Writeline("Hello!")
                      oFile.Close

Open in new window


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.Readline
                      oFile.Close

Open in new window


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(CarriageReturnLineFeed).   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:

data = "something something something" & vbCrLf & "something something something" & vbCrLf & "something something something"
                      WScript.Echo(data)

Open in new window


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?

Set oFS = CreateObject("Scripting.FileSystemObject")
                      Set oFile = oFS.OpenTextFile("c:\MyFile.CSV",1)
                      data = oFile.Readline
                      fields = Split(data,",")
                      oFile.Close

Open in new window


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:

Set oFS = CreateObject("Scripting.FileSystemObject")
                      Set oFile = oFS.OpenTextFile("c:\MyFile.CSV",1)
                      data = oFile.Readline
                      fields = Split(data,",")
                      WScript.Echo(fields(0))
                      WScript.Echo(fields(1))
                      WScript.Echo(fields(2))
                      oFile.Close

Open in new window


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.Readline
                      fields = Split(data,",")
                      For i = 0 to UBound(fields)
                          WScript.Echo(fields(i))
                      Next
                      oFile.Close

Open in new window


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.Readline
                      fields = Split(data,",")
                      For Each field in fields
                          WScript.Echo(field)
                      Next
                      oFile.Close

Open in new window


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 data
                      Loop
                      oFile.Close

Open in new window


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)
                      Loop
                      inputFile.Close
                      outputFile.Close

Open in new window


The  Replace method is used like this:  
    Replace( stringToSearch, stringToBeReplaced, stringToReplaceItWith )  
Pretty easy.

So, to copy files or folders:

Set oFS = CreateObject("Scripting.FileSystemObject")
                      oFS.CopyFile(Source, Destination)
                      oFS.CopyFolder(Source, Destination)

Open in new window


Deleting files/folders is similar:

Set oFS = CreateObject("Scripting.FileSystemObject")
                      oFS.DeleteFile(path)
                      oFS.DeleteFolder(path)

Open in new window


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...


Happy coding,
exx
5
4,959 Views

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.