Understanding and creating Windows script files
As I described in "WSH, Part 1: File Types," January 2006, InstantDoc ID 48498, Windows Script Host (WSH) is a COMbased scripting host that can execute scripts in Windows. It natively supports both JScript and VBScript, but other languages are also available if you install them separately.
WSH can execute both standalone (e.g., language-specific) scripts and Windows Script file (.wsf) scripts. The latter scripts are XML-formatted text files that can contain code in more than one scripting language. Although they're slightly more complex to write, .wsf scripts provide the script author some other useful features that are tedious or difficult to implement by using standalone scripts.
The .wsf XML File Format
The XML format that .wsf scripts use looks similar to HTML. XML uses markup tags enclosed in angle brackets (< >), called elements, that describe the data in the file. The full list of XML elements used in .wsf files is provided at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/wsorixmlelements.asp. A brief overview of XML syntax is as follows:
- The file should begin with the <?XML version="1.0"?> element to indicate that the file is in XML format.
- Elements are case sensitive and are enclosed in angle brackets.
- The opening tag for an element is specified as <elementname>, and the closing tag uses a forward slash after the opening angle bracket and before the element name (e.g., </ elementname>).
- Elements can have one or more attributes expressed in the form attribute="value". The attribute's value must be enclosed in double quotes. For example, <elementname attribute1= "value1" attribute2="value2">.
- If an element doesn't have a closing tag, you must use a forward slash before the closing angle bracket in the opening tag; for example, < elementname attribute="value"/>.
- Elements can include other elements as long as the tags don't overlap (i.e., the inner element must have an opening and closing tag before the outer element's closing tag).
- You can create a comment element by inserting text between the opening <!— tag and the closing —> tag.
When you use the <?XML version="1.0"?> element, the angle brackets (< and >) and ampersand (&) characters have special meanings to the XML parser when they occur in element content and must be replaced with the character sequences <, >, and &, respectively.
Unfortunately, these characters tend to occur frequently in VBScript and JScript code. To avoid having to make the replacements while still avoiding XML parsing problems, you can enclose all VBScript and JScript code between the <!\[CDATA\[ and \]\]> markers.
Listing 1 shows the minimum required XML elements for a .wsf script. There must be at least one <job> element. The <script> element contains the VBScript or JScript code. The language attribute of the <script> element tells WSH which language engine it should use to execute the code. The code is placed in between the special <!\[CDATA\[ and \]\]> markers to prevent any problems with the XML parser.
Including Standalone Code
Unlike standalone scripts, .wsf scripts let you easily include VBScript or JScript code from another file. Listing 2 shows a .wsf script that calls the Square function that's defined in the MathFunctions.vbs file. There are two important items to note about this example. First, the language attribute in the <script> element tells WSH the language engine it should use to process both the included file (in this case, MathFunctions.vbs) and the code listed between the <script> and </script> tags. Second, you don't have to include the full path to the included file. WSH assumes it's stored in the same directory as the script unless you specify otherwise.
Note also that the referenced file should contain only code in the desired language, not XML elements. For example, you can't include code from another .wsf file.
You can include the <runtime> element inside a .wsf file's <job> element and enclose a set of elements in the <runtime> element to make a script self-documenting. Then, when you specify a /? argument on the script's command line or call the WScript .Arguments object's ShowUsage method, WSH will display a short usage message based on the < runtime> element's contents. The < runtime> element can include the following elements:
The <description> element. The <description> element should contain a short description of the script. If you execute the script with the /? command-line argument or call the WScript.Arguments object's Show-Usage method, WSH will automatically display the text in between the <description> and </description> tags. Everything inside the < description> and </description> tags is included, including new lines, tabs, and spaces.
The <unnamed> element. The <unnamed> element describes the script's unnamed arguments (i.e., arguments that don't start with the / character). This element doesn't have a closing tag and has two mandatory attributes: the name attribute (which specifies the argument's name) and the helpstring attribute (which describes the argument). You can set a third attribute, the required attribute, to "true" or "false" to determine whether the argument's name will be enclosed in square brackets (\[ \]) in the usage message. (The default is "false".)
The <unnamed> element can also include the many attribute, which must be a boolean ("true" or "false") value. If "true", the usage message will indicate that the argument can be specified more than once by using a number after the argument's name and an ellipsis (...). If you specify many="true", you can also use the required attribute to specify the number of arguments required.
The <named> element. The <named> element describes a script's named arguments (i.e., command-line arguments that start with a / character). This element doesn't have a closing tag and requires the name and helpstring attributes to provide a name and description for the named argument. If you include required= "true", the argument won't appear in square brackets in the usage message.
The type attribute is optional and indicates the argument's data type; it can be "string", "boolean", or "simple" (The default is "simple".) The type attribute affects the display of the usage message: If you use type="string", the argument will be appended with a colon (:) and the string value to indicate that a value is required. If you use type="boolean", the argument is appended with the string \[+|-\] to indicate that the user should type a plus (+) or minus (-) character after the argument name. If you use type="simple" (or omit the type attribute), the argument is displayed as is.
It's important to note that the <unnamed> and <named> elements merely define what appears in the usage message when you run the script with the /? argument or when the script executes the WScript. Arguments object's ShowUsage method. These elements don't validate your script's command-line arguments; they simply document what the arguments should be.
The <example> element. The < example> element is optional; it lets you provide a sample usage for the script. It will be displayed after the description and command-line arguments. As with the <description> element, everything between the <example> and </example> tags is included, including new lines, spaces, and tabs.
The <usage> element. If you don't like the default usage message, you can use the <usage> element to override it. You can still use the other <runtime> elements to benefit anyone reading the script. As with the <description> and <example> elements, everything between the <usage> and </usage> tags is included, including spaces, tabs, and new lines.
Listing 3 shows a sample script that uses the <description>, <unnamed>, and <named> elements, and Figure 1 shows the usage message when you execute the script with the WScript host. Note that the <named> elements don't use the required="true" attribute, so they appear in square brackets to indicate that they're optional.
Another strength of .wsf scripts is their ability to execute code in multiple languages: That is, a <job> element can contain more than one <script> elements. The script shown in Listing 4, contains code in both JScript and VBScript. The VBScript code calls the Square function, which is implemented by using JScript. When using multiple languages in a .wsf script, the ordering of the <script> elements is important— WSH executes them in order from top to bottom. That is, if you re-order the <script> elements in Listing 4 and put the VBScript code first, the script won't work because the VBScript code executes first before the Square function is defined.
A .wsf file can contain multiple scripts by using more than one <job> element. To create such a file, enclose all <job> elements within the <package> element and specify separate id attributes for each job. By default, WSH will execute only the first job that appears in the file. You can specify a different job by using the //Job option on the CScript or WScript command line. Follow the syntax
where jobname is the name of the job and scriptname is the name of the script. The script in Listing 5 has two jobs: UseJScript and UseVBScript. The UseJScript job will be executed by default if you don't use the //Job option on the script host's command line. The job name isn't case sensitive. Also, if the job name contains spaces, don't forget to enclose it in double quotes on the command line.
Note that the <runtime> element (and its associated elements) is job-specific. If you use multiple <job> elements in a .wsf script, you have to use a separate <runtime> element for each job (i.e., the <runtime> element documents a specific job, not the entire script file).
A Real-World Application
Members.wsf is a real-world administrative-script that uses both JScript and VBScript to display a sorted list of members of a named group. (You can download this script along with the other code from this article from the Windows Scripting Solutions Web site. Go to http://www.windowsitpro.com/windowsscripting, enter 48692 in the InstantDoc ID text box, then click the 48692.zip hotlink.) Members.wsf also uses the <runtime> element to display its usage message. This script is a good example of a multi-language script that makes up for the deficiency of one language by using a feature from another. Because VBScript lacks a built-in array-sorting subroutine, the script uses JScript to handle this task.
Standalone scripts lack some powerful features that .wsf scripts offer. Use the information from this article to take advantage of these capabilities in your own scripts.
Bill Stewart (bill.stewart@frenchmortuary .com) is the systems and network administrator for French Mortuary in Albuquerque, New Mexico.