Author's Note: Although I help you create some custom tools that let you better administer your Web sites, you don't need a lot of scripting experience to follow and take advantage of what I present in this article. Thus, I don't spend a lot of time on how to create new scripts for the metabase.
In "Getting to Edit the Metabase," February 2001, I introduced you to the capabilities that IIS administrative scripts provide. This month, I show you how to expand the reach of these scripts. First, I show you how to chain the scripts so that you can use one command to complete multiple operations. Then, I show you how to use the existing scripts as raw material from which you can build new scripts. Finally, I introduce a Microsoft Excel spreadsheet that I've created to contain a macro that traverses the metabase and displays data from your server's Web sites in an easy-to-read format.
As a prerequisite for running these or any other scripts, you need a scripting engine on your system. In this case, I'm using the VBScript scripting engine. This engine comes with Windows 2000 and Microsoft Internet Explorer (IE) 5.0 for Windows NT machines. If you need this scripting engine, you can download it from http://msdn.microsoft.com/scripting/default.htm?/scripting/scriptlets/serverdown.htm.
Chaining a Set of Existing Scripts
You can take advantage of existing scripts by using them without modifications. Unfortunately, this method limits you to performing only those tasks the existing scripts can handle. I create a fairly simple script that shows you how to chain together a group of existing scripts. This simple script takes advantage of Windows Script Host's (WSH's) WshShell object.
The WshShell object is essentially a way for a script to grab a handle to the script hosting environment that's running. You can then execute a method against this shell, telling it to run another script. As Listing 1, page 2, shows, I create an instance of the WshShell object, then use this object to run other scripts. However, as I told you in February's article, some scripts, in particular adsutil.vbs, require the CScript host. The good news is that although the WshShell object is referenced as WScript.Shell, the object in fact attaches to either the CScript or WScript host, whichever happens to be running. No CScript version of the WshShell object exists; the object that I use to attach to the running environment is separate from the host that's processing scripts.
Notice that Listing 1 has repeated calls to the WshShell's Run method. This example is simple and involves a string of four commands. The script calls the StopIIS script (i.e., stopweb.vbs) followed by a call to use adsutil.vbs, which uses the Active Directory Service Interfaces (ADSI) Get command as the first parameter to retrieve a value from the metabase. Another call that uses adsutil.vbs to the ADSI Set command sets the same value and follows the Get request, then a call is made to the Start IIS script (i.e., startweb.vbs). For testing purposes, you can comment some of the different calls and see how the script runs each call. The biggest limitation of the Run method is that it doesn't provide a way to get information back from the programs it executes. For example, although the command at callout A in Listing 1 makes a call to adsutil.vbs, which uses the Get command to retrieve the Web site name, the name isn't available in the script to use as part of the next call.
Because WshShell's Run command makes up the majority of the activity, let's take a closer look at the three items that you can pass to this call. Here's the syntax for this method call:
object.Run(str Command, \[int WindowStyle\], \[Boolean WaitOnReturn\])
Let's compare this syntax to the calls in Listing 1 so that you can understand the call's various elements. As you see in Listing 1, the variable that holds the WshShell object (i.e., shell) replaces the generic term object in the syntax. The .Run portion that follows specifies that you're calling that object's Run method. The next item in the syntax is an opening parenthesis. However, notice that some calls in Listing 1 don't include parentheses. If you want the system to return a value following the call to the Run method, you need parentheses; if you're just asking the system to perform this action and continue, you don't need the parentheses.
The next item is the str Command parameter, which represents the string containing the command line you want to run. This value must be present when you use the Run method because if it weren't, what would the system run? Also notice in some of the example calls that the value " " appears. This value is an easy way to tell the system to include a quotation mark within the string. Sometimes you need to enclose the values that are on the command line in quotation marks to account for embedded spaces; this value places a quotation mark in the string. If you attempt to use one quotation mark in the string, the system would look at the quotation mark as ending or starting a new string and wouldn't include it as part of the command line; however, the system sees two quotation marks in a row as an indication to include one quotation mark.
Finally, you see two parameters enclosed in square brackets. The square brackets mean that these values are optional. However, for the majority of Run method calls in this script, the third parameter (i.e., Boolean WaitOnReturn) is necessary.
For the system to know that you want to specify a third parameter, you need to set a value for the second parameter. For this script, a value of 1 is sufficient to act as filler for the second parameter. In the next script, I replace this value with 2. The values indicate how the display for the target executable should behave. For scripts, this display is a command window; as each script runs, it opens a command window to display information. Unfortunately, the options are limited, and no way exists to tell the system that you want the display to remain open until the user has had a chance to read it. When you use a value of 1, which is the default, the system opens a new command window. This command window remains open while the script executes and closes when the script finishes. Running Listing 1, this setup can be a little distracting. By using a value of 2 (as in Listing 2), the system creates the command window in its minimized form, which eliminates the distraction. Other options (11 total) let you control settings such as how the new window opens (maximized or minimized) and which window remains active. (For a list of these command window options, go to http://msdn.microsoft.com/scripting/default.htm?/scripting/windowshost/doc/wsmthrun.htm.)
The third parameter determines whether the script should wait for the command to finish before moving to the next command in the current script. By default, when you use the Run method to execute a command, the shell gets the new command started and immediately moves to the next command in the current script. In some cases, this sequence is fine; but if you're conducting lengthy operations, you want the system to wait until the script to stop IIS has finished before the system continues. To make the system wait, you need to specify the last parameter as having a value of TRUE.
Using a Custom Script to Get Metabase Values
No good solution for getting data back from the Run method exists. Although the method returns error information when you choose to wait on the return, this error information isn't useful for application data. The Run method is great for monitoring the success of server operations or metabase updates, but to get data from the metabase, you need to add code to your .vbs file.
For example, I want to retrieve values from the metabase, so I take the GetCommand function from adsutil.vbs and add it to the code from Listing 1 as the basis for Listing 2. I then modify the function so that it works in another script. For example, the original code didn't have parameters in the call to the function and attempted to parse command-line parameters. In addition, the adsutil.vbs version of this function sends the values to the screen; for our purposes, I want to be able to have the values in local variables so that I can reuse them. Along with other changes to simplify the logic that makes up the GetCommand function, I create a function that I can use in Listing 2 without actually working through how to connect to or retrieve values from the metabase.
The GetCommand function in Listing 2 displays an error message in the event of a problem and returns a value greater than zero if an error occurs, which lets the script decide whether it can continue processing. The function uses five parameters to transfer data to and from the function:
GetCommand(MachineName, _ ObjectPath, ObjectParameter, _ Valuelist, ValueCount)
The first three parameters pass values into the function. The first parameter, MachineName, specifies the machine of interest; in Listing 2, this value is localhost. The second parameter, ObjectPath, specifies from what portion of the metabase you're retrieving a property. The subkey path that appears in Listing 2 is W3SVC/1, but you can use W3SVC/1/Root if you want to get information related to the root directory for the Default Web Site. The third parameter, ObjectParameter, is the name of the property you want to retrieve. The name is based on the property name that appears in the MetaEdit utility. You must know the name of the property; this script isn't designed to loop through all a subkey's properties.
The function's final two parameters return the value that the function looks up. The first parameter, Valuelist, contains either the string that represents the desired value or an array of values. To know the type of data in the Valuelist parameter, the scripted function returns the ValueCount parameter. If the ValueCount value equals 1, the Valuelist parameter is a string; if this value is greater than 1, the Valuelist parameter contains an array.
The code in Listing 2 contains logic that retrieves a value from the metabase. If that value is a simple string, the logic echoes the string to the command window and lets the user edit the string. If the user provides a new value in the input box, the script calls the Run method and uses the existing adsutil.vbs script to update that value. The script then echoes the new value to the command window. You can easily modify this code to use the Run method to go through a series of values or even other calls. Another minor modification is to change the calls to the Run method so that they use 2 in the int WindowStyle parameter, which keeps the various command windows from popping open and closing while the script runs.
Showing the Metabase in a Friendly Format
Writing scripts that access the metabase is a powerful way to complete tasks, but you can take advantage of your knowledge of the metabase in other ways. For example, I created an Excel application, which you can download from the IIS Administrator Code Library (http://www.iisadministrator.com), that will connect to the local metabase and retrieve information related to the security settings on your Web site. The application lists the relative path, security setting, and physical path for each entry. The application has three modes:
- It lists those directories and files in which IIS security changes from the default.
- It lists all the items that are identified in the metabase.
- It provides a list of every resource that can be referenced with an HTTP connection to your site (as long as you limit your scope to the local server).
This last option can take a minute or two, but it provides great mapping between the URLs that are available on your site and the files to which you've mapped them.
When you've enabled macros in Excel, you can run this application on your server. Follow the instructions provided on the workbook's instruction sheet, then start or examine the application code.
As I finish this series on the metabase, I hope you have a much better understanding of what the metabase holds and how to take advantage of its inheritance model. This month, I've spent time putting together some simple custom tools that provide additional power to administer a system. With a little work, you can continue to enhance and customize these tools to meet other needs.
If, as a result of this article, you have a greater interest in scripting, I recommend two valuable resources. The first is the official Microsoft Developer Network (MSDN) site dedicated to scripting (http://msdn.microsoft.com/scripting). This site is loaded with free resources that will help you gain additional knowledge. In particular, bookmark the link to the language reference at http://msdn.microsoft.com/scripting/windowshost/doc/wshtoc.htm. The second valuable resource is one of IIS Administrator's sister publications, Windows Scripting Solutions (http://www.winscriptingsolutions.com). This publication, dedicated to scripting, is running a useful set of publicly available tutorials in the Web Exclusives section of its Web site. You can take advantage of these tutorials to get a start on scripting.