A common job WSH can do for you

Have you postponed rolling out Windows Scripting Host (WSH) because you haven't figured out how your company can use the product? By migrating your logon environment to WSH, you'll be able to schedule and run smarter, more robust scripts on your enterprise's clients, and you'll prepare your firm to take advantage of Windows 2000 (Win2K$#151;formerly Windows NT 5.0). But maybe you're looking for a specific task for WSH to perform before deploying the product across your enterprise.

One common function that you might want to use WSH for is logging on NT users. To translate your current NT logon script to WSH, you need to take three easy steps: Install WSH on your client systems, create a wrapper batch file to run the WSH logon script, and convert existing batch files to Visual Basic Script (VBScript) or JScript.

Installing WSH Throughout Your Enterprise
As you probably already know, the NT 4.0 logon process doesn't support WSH scripts. (For more information about WSH, see "NT Gains Scripting Muscle," April 1998, and Keith Pleas, "Windows Scripting Host in Action," February 1998.) Therefore, you need to install WSH on each client that will run WSH logon scripts. You can use a standard NT logon script to test whether a system already has WSH installed, and to install WSH if the software isn't on the system.

If you're using NT's Directory Replicator service, your first step in distributing WSH to your clients is copying WSH's self-extracting archive, wsh.exe, to the %systemroot%\system32\Repl\Export\Scripts subdirectory on your export server. (For more information about the Directory Replicator service, see Mike Reilly, "Replication in Windows NT," page 187, and Bob Chronister, Tricks & Traps, September 1997.) The export server is generally the Primary Domain Controller (PDC) in an organization's account domain. You can obtain the WSH archive from http://msdn.microsoft.com/scripting.

Next, create a logon script similar to start.bat, which Listing 1, page 192, shows, or include the code at callout A in Listing 1 in your standard logon script. The code at callout A tests whether the client has the Windows-based WSH host, wscript.exe, installed. If start.bat doesn't find wscript.exe, the script launches WSH setup using the quiet option (as the /q switch indicates). The only caveat to this installation approach is that the user account that executes the logon script must have administrative rights on the client machine. If the user doesn't have administrative privileges, the WSH object model control (wshom.ocx), which exposes WSH's Network and Shell objects, fails to register.

Creating the Wrapper File
When you convert your current logon script to WSH, you'll need to embed that WSH script in a wrapper batch file because the NT 4.0 logon process doesn't support WSH-compliant ActiveX scripting. (Win2K will support WSH-compliant ActiveX scripting.) By default, you can run only batch files (files with a .bat or .cmd extension) or executables during an NT 4.0 logon. As start.bat demonstrates, you can include the wrapper code for your WSH logon script in the NT 4.0 logon script batch file you create to verify that client systems contain WSH. At callout B in Listing 1, start.bat calls my VBScript logon script, logon.vbs.

You can use wscript.exe or the console-based WSH host, cscript.exe, to run your WSH logon script. From a logon-script perspective, the key difference between the two is that only cscript.exe can use the ERRORLEVEL environment variable of the NT command processor, cmd.exe. ERRORLEVEL is a built-in variable that contains the exit code from the last command that ran via the command processor. If you want to use WScript's Quit method to return an exit code that the wrapper batch file can test, you must use cscript.exe to run your script.

Rewriting Existing Scripts
After you install WSH on the target clients and decide how to run your WSH script from a batch file, you're ready to start migrating your existing scripts to WSH. The first decision you'll have to make in this migration is whether to write your scripts in VBScript or JScript, the two ActiveX scripting engines that Microsoft packages with WSH. The decision between VBScript and JScript is mostly a matter of preference, but the two languages differ significantly in their syntax and functionality. For example, VBScript looks and feels like Visual Basic (VB); JScript closely resembles C and Java. JScript supports regular expressions, but VBScript does not (although Microsoft included support for regular expressions in the VBScript 5.0 engine, which was in beta at press time). I prefer VBScript for logon scripts because of the language's ease of use, its similarity to VB, and its strong component object model (COM) support. When I write logon scripts, I'm not concerned about cross-platform browser support, which was the initial problem that JScript (and JavaScript) sought to resolve.

You need to become familiar with three scripting tasks to successfully rewrite your current logon scripts in VBScript: executing external commands; replacing NT's net.exe commands with the corresponding WSH objects, methods, and properties; and replacing Microsoft Windows NT Resource Kit or third-party commands and utilities with functionality that the WSH object model provides.

As you work through the migration exercise, you'll find that WSH doesn't provide functionality equivalent to every command or utility you use. Therefore, you must use external commands to accomplish some of your current logon scripts' tasks. For example, WSH doesn't provide a time synchronization object to replace NT's NET TIME command. To use your WSH logon script to synchronize clients' time with the time on the domain that logs them on, you must use the WSH Shell object's Run method to execute an external command.

In addition, when you implement WSH logon scripts, you'll discover tasks that command-line or resource kit utilities perform but that you must add to your WSH scripts through object libraries such as Active Directory Service Interfaces (ADSI). For example, if you convert to WSH a batch file that uses the ifmember.exe resource kit utility to test for a user's group membership, you can replace ifmember.exe with ADSI's Group object and corresponding IsMember method. (I'll explore leveraging ADSI in logon scripts in a future column.)

As you look for WSH substitutes for batch file functions, keep in mind that the engine of the script you use provides a number of useful objects. For example, VBScript offers FileSystemObject, Err, and Dictionary objects. (For more information about VBScript Dictionary objects, see "Leveraging Components," January 1999.) Table 1, page 194, highlights approaches for accomplishing common logon script tasks in batch files and the corresponding solutions in WSH.

Sample Logon Script Migration
Now that you understand some of the problems you must consider when you convert logon scripts to WSH, I'll rewrite a batch file logon script in VBScript. Listing 2 contains a simple logon script, logon.bat, that uses NT's NET USE command to map a network drive and uses the NET TIME command to synchronize the local workstation's time with the time on the domain the workstation logs on to. Listing 3 contains a WSH script, logon.vbs, that performs the same functions. At first glance, logon.vbs might appear more complex than logon.bat, but remember that VBScript represents a different programming paradigm than batch files. The primary use of batch files is to glue together command-line utilities; VBScript glues together objects. As you gain experience with VBScript, you'll probably find that the language makes difficult scripts easier to write, enhance, and maintain.

Logon.vbs begins with VBScript's Option Explicit directive to force variable declarations. Next, the script uses the On Error Resume Next statement to enable runtime error handling; the statement lets the script continue executing even when the script encounters an error. Without the On Error Resume Next statement, runtime errors in logon.vbs would result in cryptic messages to the user, after which the script would immediately abort. After the On Error Resume Next statement, Listing 3 declares the script's variables, initializes strDrive and strShare, and uses WScript's CreateObject method to create the script's wshNetwork and wshShell objects. Logon.vbs later uses the wshNetwork object to map a drive to a network share, and the script uses the wshShell object to access system environment variables and run the NET TIME command.

At callout A in Listing 3, the script sets the wshSysEnv variable to the Environment property that the wshShell object exposes. Setting a variable to a wshShell object's Environment property returns a wshEnvironment object that exposes environment variables of the type the script specifies; you can expose SYSTEM, USER, VOLATILE, or PROCESS environment variables. Logon.vbs specifies the SYSTEM environment variable source.

Next, the script uses wshSysEnv to test the OS environment variable. If the OS environment variable matches the string Windows_NT, logon.vbs enters the If block at callout B. If the OS environment variable doesn't match Windows_NT, logon.vbs executes the Else block that appears near the end of the script. The Else block echoes an appropriate message to the user, removes objects the script has created, and exits the script with a return value of 1. If the script is running under cscript.exe, the return value of 1 sets the command processor's ERRORLEVEL value to 1, and the script's wrapper batch file can use ERRORLEVEL to determine whether the script did not complete successfully.

At callout B, the script uses the wshNetwork object's MapNetworkDrive method to map a drive to a network share. However, before logon.vbs maps the drive, it must verify that the client machine hasn't already used the target drive letter to set up a persistent network connection. Logon.vbs performs this verification by obtaining and traversing a network drive collection. It begins by invoking the wshNetwork object's EnumNetworkDrives method, which returns a collection (which you can think of as an array) of current network drive mappings. The script then traverses the collection and compares the even elements with the value of the variable strDrive. (The script compares strDrive with only the network drive collection's even elements because the EnumNetworkDrives method returns the drive mappings as Drive=Share pairs; the drives are the even elements and the shares are the odd elements in the collection.) If strDrive matches any of the even elements in the network drive collection, logon.vbs uses the RemoveNetworkDrive method to remove the current mapping to the target drive. After the script removes the drive mapping or verifies that the system hasn't mapped the target drive letter to another share, it maps strDrive to the network share strShare.

Logon.vbs's last task is running the NET TIME command. The script uses the wshShell object's Run method for this purpose. Run accepts three arguments: the name of the command to run, an optional integer that you can use to specify a type of window for the command to open, and an optional Boolean flag that dictates whether the script waits for the command to complete before continuing. At C in Listing 3, logon.vbs uses the wshNetwork object's UserDomain property and VBScript's string concatenation operator (the ampersand character$#151;&) to specify the target time-synchronization domain. The zero value for the Run command's second argument tells Run not to create a new window, and the TRUE value for the third argument forces the script to wait for the NET TIME command to complete before continuing.

When NET TIME completes, logon.vbs captures the NET TIME command's return value in the variable nReturnCode and tests this value to determine whether the time change was successful. If nReturnCode doesn't equal zero, logon.vbs uses VBScript's MsgBox function to display an appropriate error message. Finally, before exiting, the script destroys the wshNetwork and wshShell objects.

More Logon Script Functionality
The functions this article covers represent the tip of the iceberg in terms of WSH's capabilities as an engine for logon scripts. WSH resembles a real programming language in that the product lets you add real data types to your scripts, implement real control flow, and write real subroutines; batch files don't offer this functionality. VBScript's FileSystemObject provides more robust access to the file system than batch files provide. And WSH provides access to multiple directory services via ADSI, access to databases via ActiveX Data Object (ADO), and send-mail capabilities via Collaboration Data Object (CDO).

Use one of WSH's easy-to-learn scripting languages and support for other Microsoft and third-party components to teach your logon scripts new tricks. Become comfortable with WSH and VBScript today to make sure you're prepared to work with the platform of the new millennium.