In "Extensible Markup Language," April 2000, I introduced the new XML-based Windows Script (WS) files, which Microsoft Windows Script Host (WSH) 2.0 registers with a .wsf extension. I examined the WS files' XML schema and each element's syntax, definition, and usage. Now let's look at the new capabilities and benefits that WS files provide and put this knowledge to work.
WSH 2.0 Features
Before I dive into the code, let's recap several WSH 2.0 features. The XML-based WS files provide the following top WSH 2.0 capabilities.
Include file support. The include file capability lets you place commonly used code in a separate file or files, then reference the file (or files) in other scripts. The separate file's code becomes available to the script that contains the include directive. The <script> element's optional src attribute (src="filename") is the include enabler.
External constants support. WSH 2.0 uses the <reference> element to support external constants. This feature lets you use mnemonic constants defined in objects outside the script engine. For example, you no longer need to redefine constants that ActiveX Data Objects (ADO), the FileSystemObject, and Windows Management Instrumentation (WMI) already define.
Multiple languages support. WSH 2.0 provides support for multiple languages so that you can use several languages inside one WS file. The <script> element's mandatory language attribute makes switching between languages possible. For example, inside a WS file, you can write part of one job in JScript and write the other part of the job in VBScript. Also, you can pass variables that include object references across code boundaries.
The <object> element. WSH 2.0 lets you use the <object> element to create objects. The <object> element performs the same task that the WScript, VBScript, and JScript CreateObject, GetObject, and new ActiveXObject methods do.
Jobs. Jobs let you partition a WS file into autonomous self-contained work units. You use the <job> element's id attribute to give a unique name to each job in the file, and you use the new //job:jobid option to identify the job to execute at runtime. For example, you might use the jobs feature to divide your WS file into discrete tasks in which each job represents a primary script capability.
Tools support. The development tool enhancements let WS files leverage the IntelliSense and syntax-coloring features in Microsoft Visual InterDev 6.0 Service Pack 3 (SP3) and the Microsoft Office 2000 Script Editor. (For information about how to enable IntelliSense and syntax coloring in Visual InterDev, see the Microsoft article "HOWTO: Enable Windows Script Version Tools Support for Visual InterDev" at http://support.microsoft.com/support/kb/articles/q249/0/24.asp.)
Let's now examine a script that demonstrates an XML-based file's capabilities. Eventlog.wsf is a WSH 2.0 script that leverages the WMI Scripting API to search Windows 2000 (Win2K) event logs. (To make eventlog.wsf work with Windows NT, you need to run NT 4.0 with SP4 or later and download and install WMI Core 1.50 or later from http://msdn.microsoft.com/downloads/sdks/wmi/download.asp.) Eventlog.wsf uses WMI's Event Log provider and query language to produce a console-oriented utility that you can use to search for specific event records in Win2K's six event logs. (For more information about WMI, see Mark Russinovich, Internals, "Inside Windows Management Interface," February 2000.)
The script is easy to use and provides detailed instructions, which Screen 1, page 180, shows, when you provide a question mark (?) as the first argument. The script also includes a set of default values; therefore, eventlog.wsf will perform meaningful operations whether or not you provide command-line arguments to the script at runtime.
All the script's arguments are optional. When you don't specify arguments, eventlog.wsf searches for and echoes all events in the local computer's Application log. You can specify one or more arguments to control the script's search behavior and identify the target log file, event source, event type, event id, and target computer. For example, if you wanted to search the System log for DCOM errors with an id of 10006 on a remote computer named dell610, you'd enter the command line that appears toward the bottom of Screen 1.
The Notes at the bottom of the usage text in Screen 1 provide additional instructions about how to use the script. The Notes say you must use the console-based host, cscript.exe, to run eventlog.wsf. The cscript.exe requirement is mandatory because eventlog.wsf writes its search results to STDOUT. You can use WScript's STDIO properties, which include STDOUT, only in console-based scripts. You don't want to use WScript's Echo method because you might receive hundreds of pop-up windows if you inadvertently use the Windows-based host to run the script. You also need to use double quotes to enclose values containing spaces. For example, when you want to search the local domain controller's Directory Service (DS) log for all errors, enter the following command:
C:\> eventlog.wsf l="directory service" t=error
In this example, I don't specify cscript.exe on the command line. You can omit the host if you use the //h:host option to configure cscript.exe as the default host. If cscript.exe isn't the default host, eventlog.wsf will fail because the script depends on the console-based host. Also, this command doesn't contain the //job:xxxx option. When you don't define a job at runtime, WSH 2.0 runs the first job in the package, which is the Search job in eventlog.wsf.
Script Meets XML
Our solution to create a utility that searches Win2K event logs consists of two files: eventlog.wsf, which Listing 1 shows, and library.vbs, which is an include file that contains several common functions and subroutines that the eventlog.wsf script uses. You can download the complete listings for both files from Windows 2000 Magazine's Web site at http://www.win2000mag.com/articles. (Enter 8631 in the InstantDoc text box, go to the Article Info box, and click the 8631.zip file.)
Eventlog.wsf contains the solution's primary logic. When you take a closer look at Listing 1, you might think the script is a bizarre form of HTML—but it isn't. XML takes run-of-the-mill source code and adds definition and structure to produce a more powerful and extensible scripting framework.
When you apply what you learned about XML and the WS XML schema from "Extensible Markup Language," you can easily identify several eventlog.wsf characteristics. For example, eventlog.wsf's <?xml?> directive at callout A in Listing 1 enables XML validation. This XML directive puts the script into a strict XML-compliance mode in which element and attribute names are case sensitive and in which you must enclose attribute values in double quotes. The XML directive also suggests that you place the source code inside a <!\[CDATA\[ ... \]\]> section. Otherwise, the XML parser (scrobj.dll) might interpret valid source code or data as XML. The <package> start tag at callout A and </package> end tag at callout D imply that eventlog.wsf contains several jobs. The job at callout C is a job template that I use as a placeholder.
The XML elements that appear at callout B play a crucial role in the script's search job. Let's examine each element at callout B in detail. Like all jobs in a WS file, the search job must begin with a <job> start tag and end with a </job> end tag. The <job id="search"> element provides an optional id attribute that lets you uniquely identify every job in a package. The id attribute is optional in eventlog.wsf because the search job is the only functional job in the package. However, I encourage you to use the id attribute to name your jobs.
Three <object> elements follow the <job> element at callout B. The <object> element provides another way that you can create a reference to an automation object. To help you better understand the <object> element, I've compared the equivalent VBScript CreateObject function calls with the three XML <object> elements in Figure 1, page 182.
The <object> element uses its optional reference attribute to provide an additional capability. The reference attribute at callout B is a Boolean value. When you set the reference attribute to true, you can use mnemonic constants that the object you create defines. This process provides the same capability that the <reference> element provides. Therefore, the optional reference attribute, which is part of the <object> element, eliminates the need for the <reference> element. I commented the <reference> element at callout B because the <object> element's reference attribute performs the same function.
The last element at callout B is the <script> element, which is a mandatory element and the most beneficial element that the WS XML schema defines. The <script> element's language attribute governs the scripting language that appears between the element's <script> start tag and </script> end tag. Because one job can have several script blocks, the <script> element's language attribute lets you switch scripting languages midway through a job. The XML parser uses the mandatory language attribute to determine which script engine to pass the corresponding script block to.
The <script> element also provides support for include files. You use the src attribute to identify the file to include. You can also specify the src attribute as part of the mandatory <script> element when you use the same scripting language in both the script block and the include file. However, if the language in the script block differs from the language in the include file, you need to add a separate <script> element that identifies the include file's language and src attribute. For example, Figure 2 shows how to structure XML to accommodate a VBScript block that needs to use the routines that a JScript library defines.
In the example in Figure 2, the first script tag doesn't have an end tag because the element doesn't contain content. You append a slash to the immediate left of the closing angle bracket to close elements that don't contain content. The same rule applies to <object> and <reference> elements.
Eventlog.wsf uses the library.vbs include file extensively. Library.vbs contains several functions and subroutines that I use in many of my WS files, including Function IsHost (strPreferredHost), Sub ParseArgs (objHash), Function CWmiDate(cim_DateTime), Function CWmiTime(cim_DateTime), and Sub UsageForSearchJob(). When I put these functions and subroutines in an include file, I avoid recreating the wheel for every script I develop. However, I need to caution you that if your include file contains a body (i.e., code that resides outside any function or subroutine), that code is immediately executed at the point where you define the src attribute. I use this behavior to initialize STDIO references in my library.vbs include file. The functions and subroutines in library.vbs provide the following capabilities.
Function IsHost(strPreferredHost). IsHost compares strPreferredHost with the running host. The function returns TRUE when the two hosts match and FALSE when they don't.
Sub ParseArgs(objHash). ParseArgs processes command-line arguments. The subroutine reads WScript's Arguments collection and expects arguments to be in the form of switch=value. The subroutine adds the switch=value pairs to the dictionary object that objHash references as key/value pairs.
Function CWmiDate(cim_DateTime). CWmiDate(cim_DateTime) converts a WMI CIM_DATETIME Type to a VBScript variant of subtype Date. The function returns the date part of the CIM_DATETIME value in the mm/dd/yyyy format.
Function CWmiTime(cim_DateTime). CWmiTime(cim_DateTime converts a WMI CIM_DATETIME Type to a VBScript variant of subtype Date. The function returns the time part of the CIM_DATETIME value in the hh:mm:ss AM|PM format.
Sub UsageForSearchJob(). UsageForSearchJob echoes usage instructions for the search job that eventlog.wsf defines. After completing this task, UsageForSearchJob exits the script.
The rest of the script's action takes place inside the <!\[CDATA\[ ... \]\]> section. And because everything inside CDATA is VBScript, my job concerning the XML-based WS file is complete.
Still Not Convinced?
Do XML-based WS files have a place in your toolbox? If you still can't decide, try the WS files' tools support. The IntelliSense feature alone is compelling enough to justify making the switch. I encourage you to become familiar with WS's XML grammar because I predict that you'll see more WS file capabilities that Microsoft roots entirely in XML.
I suspect several of you are interested in eventlog.wsf from the WMI perspective. Stay tuned because I embark on an incredible journey through the WMI Scripting API in my next column.