Using VBScript 5.0 and regular expressions to write an alternative to getmac.exe
I had a college professor who enjoyed rewriting system commands in whatever programming language he was teaching at the time. I distinctly remember his lesson about recursion and the corresponding assignment, which required us to rewrite ls (the UNIX equivalent of dir). Although the effort seemed futile at the time, I've grown to appreciate the old man's approach, so I decided to give his exercise a try. I developed the following assignment for myself: Rewrite the Microsoft Windows NT Server 4.0 Resource Kit's Getmac utility in Visual Basic Script (VBScript) using regular expressions. In case you haven't heard of the utility, getmac.exe displays the media access control (MAC) address for each of a machine's NICs.
If you're familiar with Windows Scripting Host (WSH), you're probably wondering how I can possibly complete this assignment because WSH doesn't support regular expressions. Well, I used VBScript 5.0 (the beta 2 version is available at press time) to rewrite Getmac; VBScript 5.0 includes support for regular expressions.
To run my VBScript recreation of Getmac, which I call getmac.vbs, you need to install the latest release of VBScript 5.0. You can download VBScript 5.0 as part of Microsoft Scripting Technologies 5.0 from http://msdn.microsoft.com/scripting. The file you need is scr50en.exe. After downloading the file, run the self-extracting executable file to install the new VBScript and JScript engines. Then, you can run getmac.vbs by typing
C:\> cscript getmac.vbs
Capture MAC Addresses
Listing 1, page 184, contains the source code for getmac.vbs. The script begins by setting the Option Explicit and On Error Resume Next directives. Option Explicit requires the script to declare all its variables. On Error Resume Next initializes Err, the VBScript error-handling object.
Next, getmac.vbs declares its variables and the OpenFileForReading constant, which VBScript's FileSystemObject object will use. Then, getmac.vbs uses an If block to test for user input at the command line. The If block uses the WScript Arguments collection's Count property to determine whether the collection contains any elements. If the Arguments collection isn't empty, getmac.vbs uses VBScript's InStr function to determine whether the first argument contains a question mark (?). If InStr finds a question mark anywhere in the first argument, getmac.vbs calls the Usage subroutine, which echoes usage instructions to the user and exits the script.
At callout A in Listing 1, getmac.vbs runs NT's Ipconfig utility. When you run Ipconfig with the /all switch, the utility provides information about a machine's NICs, including each NIC's MAC address. Getmac.vbs must create a WScript Shell object before it can run the ipconfig.exe command. The script uses WScript's CreateObject method and passes CreateObject the WScript.Shell ProgId to tell the function to create a WScript Shell object.
After creating objShell, getmac.vbs uses the Shell object's Run method to execute ipconfig.exe. If WSH supported standard I/O (STDIO), I could have redirected the output of Ipconfig directly into the script. Because WSH doesn't support STDIO, I had to save the command's output to the machine's hard disk and retrieve it from the disk before I could use it within the script. Getmac.vbs uses the command processor's standard output redirection symbol (>) to save Ipconfig's output to the file C:\temp\ipconfig.txt. In addition, getmac.vbs uses cmd.exe's /C option to ensure that the script doesn't leave an instance of cmd.exe running after ipconfig.exe exits; /C tells cmd.exe to terminate after it runs the command. The Run method's 0 parameter tells Run to execute the command without opening a window, and the TRUE parameter tells Run to wait for the command to exit before returning to the script.
After the Ipconfig command completes, getmac.vbs checks the status of the Err object to see whether Run encountered a problem. Any value other than zero in Err.Number tells getmac.vbs that a Run error has occurred. You can obtain additional error information by examining the Err object's Description property. However, getmac.vbs doesn't look into the error's cause; the script echoes a message to the user and aborts the script if Err has a value other than zero.
Because I had to write the Ipconfig output to disk, getmac.vbs's next step must bring the Ipconfig data into the script. At callout B, getmac.vbs uses VBScript's FileSystemObject object to accomplish this task. You must create an instance of FileSystemObject before you can use it. Therefore, getmac.vbs uses VBScript's CreateObject method. Getmac.vbs passes CreateObject the ProgId for FileSystemObject.
After getmac.vbs creates the objFileSystem object, the script invokes the object's OpenTextFile method and passes OpenTextFile the name of the file getmac.vbs stored Ipconfig's output in and the name of the constant the script initialized. The OpenFileForReading constant tells OpenTextFile to open the file as read-only. OpenTextFile returns a reference to a TextStream object, which initializes objTextStream.
When getmac.vbs has established the objTextStream reference, the script uses the TextStream object's ReadAll method to slurp the entire file into the strIpFileText string. Then, getmac.vbs checks the Err object for error conditions. If getmac.vbs finds no error, the script uses the Close method to close the ipconfig.txt file and continues.