Declaring and initializing variables
In last month's column, I discussed the structure of a script. I divide scripts into three sections: declarations and initializations, the body of the script, and function and subroutine definitions. This month, I continue my journey into the fundamentals of scripting by examining the declaration and initialization section in detail. Before we start, you need to know some VBScript basics to ease your transition to Windows Scripting Host (WSH).
As with any other programming or scripting language, VBScript has some general ground rules that apply to every script. At first glance, these rules might not appear to be significant, but knowing these language tidbits can often shave a few minutes off a frustrating debugging exercise.
The first ground rule is that VBScript isn't case-sensitive. For example, declaring a variable as strTempFile and later referencing it as STRtEMPfILE is perfectly legal. Likewise, VBScript statements, function names, and subroutine names are case-insensitive. Despite this flexibility, I encourage you to pick a case variation that suits your needs and stick with it.
Although VBScript is case-insensitive, some situations (e.g., comparing two string values) require you to be case-conscious. You also need to be case- conscious when you use Active Directory Service Interfaces (ADSI) namespace identifiers (e.g., LDAP to specify Lightweight Directory Access Protocol, WinNT to specify Windows NT, NDS to specify NetWare 4.x, NWCOMPAT to specify NetWare 3.x). You must key ADSI namespace identifiers according to the ADSI specification, or a runtime error will occur when your script attempts to bind to an ADSI namespace. (For more information about ADSI namespace usage, read the Active Directory Programmer's Guide available at http://msdn.microsoft.com/ developer/windows2000.)
The second VBScript rule is that you can use either an apostrophe (´) or a Rem statement to include comments in a script. I use both styles in Listing 1's demo.vbs script, page 160. You can insert comments on a separate line or at the end of a line of code, but you can't insert comments at the end of a code line that contains a line-continuation marker (_).
A third rule is that VBScript doesn't care about extra white space. Adding extra spaces or blank lines can often improve the code's readability. VBScript ignores the blank lines and the extra spaces between the variable name and the assignment operator (=).
The fourth rule is that although VBScript doesn't impose a maximum line length, breaking long lines into multiple short lines can improve the readability of a script. In VBScript, you can use the line-continuation marker to let a statement or line of code span multiple lines. I often use the line- continuation marker when I initialize dynamic arrays (e.g., at callout A in Listing 1) or to pass a long string to WScript's Echo method (WScript.Echo), which I demonstrate several times in the body of the demo.vbs script. When you use the line-continuation marker, you need to include one space immediately before the underscore, or you will encounter an error with some statement types.
On the flip side of rule 4 is the fifth VBScript ground rule, which lets one line of code contain multiple statements. In VBScript, you can use a colon (:) to separate multiple statements within a line of code. In the code line
Dim strText: strText = "WSH ROCKS!" : WScript.Echo strText
statement 1 is Dim strText, statement 2 is strText = "WSH ROCKS!", and statement 3 is WScript.Echo strText. Although VBScript supports this capability, I generally don't use it.
The sixth VBScript rule is that you must terminate each line of VBScript code with a new-line character. Pressing Enter automatically inserts the new- line character. VBScript doesn't use the visible line terminator (;) that JScript and Perl use.
The seventh and final ground rule in this month's lesson governs VBScript identifiers (e.g., variables, constants, function names, subroutine names). Identifiers can't exceed 255 characters in length and must begin with an uppercase or lowercase letter of the alphabet.
Bob's Declaration and Initialization Section
The primary elements that make up my declaration and initialization section are script directives, variable declarations, constant definitions, and variable initialization. All these elements (with the possible exception of initialization) are optional. However, using these language features can help you produce scripts that are easier to debug and maintain.
VBScript directives. VBScript includes two directives or statements that significantly affect the runtime behavior of scripts. The two directives are the Option Explicit statement and the On Error Resume Next statement.
The Option Explicit statement requires that you declare (i.e., define) all script variables via a VBScript Dim statement before you use the variables in an expression. When you use Option Explicit, the declaration requirement applies throughout the entire script, including variables in the main body of the script and variables in user-defined functions and subroutines. You must include the Option Explicit statement before any other statements in your script. Therefore, you always find Option Explicit at the top of scripts that use it. The benefit of using Option Explicit is that an error occurs whenever the VBScript interpreter encounters an undefined variable during script execution. Using Option Explicit helps you isolate typographical mistakes and variables with incorrect scopes (a scope defines the visibility of a variable to other parts of the script such as functions and subroutines).
The On Error Resume Next statement controls how a script notifies you when a script encounters a runtime error. When a script runtime error occurs and the script doesn't use the On Error Resume Next statement, WSH displays a dialog box containing the execution error information and aborts the script. Screen 1 shows an example WSH Script Execution Error dialog box. Including an On Error Resume Next statement in a script effectively tells VBScript to continue execution despite a runtime error: VBScript's built-in Err object is set with the corresponding error information, and the script continues. The On Error Resume Next statement lets you trap errors and respond to them programmatically. You can choose to display a friendly, descriptive message or write the error information to a log file. Screen 2 shows an example customized error dialog box.
Using On Error Resume Next to help trap errors is important. Suppose I comment out (i.e., add Rem to the beginning of) the line that declares variable intReturnCode at the beginning of demo.vbs:
Rem Dim arrStrings, intReturnCode
If I execute this modified script, the script will run to completion, but it might not produce the desired result. The script won't display the standard WSH Script Execution Error message on the console; instead, the script will produce Screen 2's custom error dialog box, which states that a script variable is undefined. The If-Then-End If statement at callout B in Listing 1 acts as a rudimentary error-handling routine that echos the contents of the VBScript Err object's Number and Description properties. After you click OK to acknowledge the error dialog box, the script continues because the On Error Resume Next directive tells the script to proceed despite the error. (If I commented out the On Error Resume Next directive and ran the script again, Screen 1's WSH Script Execution Error dialog box would display. More important, the script would abort as soon as I clicked OK in Screen 1's dialog box; I'd have no control over the remainder of the script. The only benefit of not using On Error Resume Next is that the error information in the WSH Script Execution Error dialog box can be more descriptive than the information in the Err object's Description property. Screen 1 not only includes the name of the undefined variable, it also provides the specific line number for the error. In Screen 2, the error description simply states that the script tried to use an undefined variable.)
Why does an error occur? In demo.vbs, I initialize intReturnCode to 0 in line 19 of the script, a few lines before callout A. But because I specified the Option Explicit directive at the start of the script and commented out intReturnCode's declaration statement, an error occurs when the script tries to execute the line that initializes the undeclared intReturnCode to 0. I can eliminate this error and other potential variable declaration errors by removing the Option Explicit statement. However, a better way to fix the problem is to define the undeclared variable (in this case, remove the Rem from the declaration statement):
Dim arrStrings, intReturnCode
Unlike Option Explicit, which affects the entire script, On Error Resume Next applies to only the portion of the script (e.g., the script's body, a function, a subroutine) that defines it. On Error Resume Next's narrow scope lets you control precisely when and where it's in effect. (VBScript doesn't support Visual Basic's—VB's—On Error Goto Label construct.) When you use the Option Explicit and On Error Resume Next directives correctly, they can make VBScript routines more robust and user-friendly and play an important role in debugging scripts.
VBScript variables. Earlier, I said declaring variables in VBScript is optional—and it is. However, engaging in the exercise of defining your script's variables can be well worth your time and effort for several reasons, such as debugging and script maintenance. Declaring your script's variables also requires you to consider the environment and objects with which your script interacts, which can result in better-designed scripts that do what you intend them to do.
A VBScript variable is simply a named memory location that contains some value. The value might be a number, a string, or some other data type that the language supports. The variable name is the mechanism through which you assign a value to a variable. Declaring VBScript variables identifies the names that you'll use to refer to the data your script manipulates.
You use the Dim statement to declare VBScript variables. In demo.vbs, the variable declarations follow the script directives at the beginning of the script. VBScript supports one primary data type: variant. You can think of variants as general-purpose variables that aren't bound to a specific type. When you declare a VBScript variable using Dim, you don't supply additional type information as you do in VB. Instead, VBScript determines a variable's type at runtime, based on the variable's contents and the usage context. VBScript supports many different data subtypes and corresponding data conversion functions that let you morph variants to your heart's content. For more information about VBScript variables, download the free VBScript HTML Help file (vbsdoc.exe) at http://msdn.microsoft.com/ scripting/vbscript/ download/vbsdoc.exe.
Variable initialization. Variable initialization is nothing more than assigning a known value to a variable before you use the variable. In demo.vbs, I initialize several variables before using the variables in the script's body. You can initialize a variable to one value, such as a number or a string, or to a more complex value constructed from multiple elements.
For example, in the variable initialization section of demo.vbs, the script assigns to strLogFile the concatenation (from VBScript's & operator) of three substrings. The first substring ("c:\") and third substring (".log") are straightforward. The second or middle substring retrieves the value of WScript's ScriptName property (in this case, "demo.vbs") and splits the string into two strings at the dot (.). In this example, I append the subscript (0) to the end of the function call to force the Split function to return only the first element ("demo") of the array of elements that Split ordinarily returns. The end result is a log file name that is identical to the script name without the extension.
Constant definitions. Constants are named values that don't change throughout the execution of a script. VBScript supports two types of constants: literal and intrinsic. Literal constants are constants that you define for the purpose of making your script more intelligible. Let's say that you write a script that uses the value of Pi (¼). Rather than hard-coding the numeric value each time the script needs it, you might define the following literal constant:
Const Pi = 3.1415926535897932384626433832795
When you need to reference the value of Pi in your script, you simply use the constant's name (i.e., Pi). In this example, referring to the name is much easier than (and significantly reduces potential typing errors from) coding the numeric value each time the script needs to use Pi. Furthermore, if you need to change the value of a constant at some later date, you need to update the constant's value in only one place in the script: in the line where you defined the constant. You can assign only scalar values to VBScript literal constants. The language doesn't support constants constructed from other constants or expressions.
Intrinsic constants are constants that are built into the VBScript language to make the language easier to use and make your scripts easier to read and maintain. Some of my favorite intrinsic constants include the escape sequence constants such as vbNewLine and vbTab that represent ANSI character codes, which you'll find sprinkled throughout demo.vbs. The VBScript Language Reference and the Scripting Run-Time Reference in the VBScript Help file provide a complete list of constants.
VBScript doesn't let you use constants that other objects, such as the scripting runtime's FileSystemObject and ADSI, define. However, Microsoft plans to include this capability in the next release of WSH. In the interim, if you want to use constants that other objects define, simply duplicate the constant definition in your script. In the constant definitions section of demo.vbs, I define the local constant OpenFileForReading to mimic the behavior of FileSystemObject's OpenFileForReading constant.
Before I go, I should tell you what the demo script does. Demo.vbs simply runs NT's ipconfig.exe utility, writes the commands' output to a file, opens and displays the file, deletes the file, and records the success or failure of each major action along the way to a log file. Then, the demo.vbs script opens the resulting log file, displays the file, deletes the file, and exits. Next month, to continue my scripting trek, I'll examine some of the more important elements generally found in the body of a script: I/O and object handling.