If your job as a Windows NT systems administrator never gets any easier, you need to find ways to work smarter and be more efficient. Consider the many tasks that you perform. Would writing scripts to automate certain tasks be helpful? If you have a simple task that you need to perform only once, writing a script to automate that task isn't very beneficial. Writing the script would probably take longer than manually executing the task. However, if you perform a task repeatedly (such as continually rewriting similar code fragments or maintaining numerous configuration files), you can develop common scripting solutions that will save you time and effort down the road.
For example, suppose you become the Windows Scripting Host (WSH) and Visual Basic Script (VBScript) guru at work. You develop a dozen scripts that execute tasks on various types of servers. Each script requires an input file that lists the servers on which the script runs. When you add servers to your environment or change the configuration of existing servers, you must revisit each input file to ensure its accuracy. This task becomes tedious because you must keep track of hundreds of servers.
How can you work smarter? You have several possibilities, all of which involve using one input file that includes all servers. What differs is how you write that input file. You can use a Perl/Tk multiselect list box. You can use an INI file format in which the configuration file contains a section for each system type. Or, you can use an integer identifier in conjunction with a bit mask that defines the various roles a server plays.
A good choice is the bit mask approach because you can easily implement the script with numerous scripting languages. Using the bit mask approach involves creating an input file of servers and writing a script. In the following example, I'll show you how to prepare a table of server-type identifiers, create the Servers.txt input file, and use VBScript to write the SrvrRole.vbs script.
Preparing the Table
Before you create the Servers.txt input file, you need to prepare a table of server types, bits, and bit values. Table 1 shows the server types and their associated bits and server-type values for this example. In the first column, you identify the types of servers in your network. The server types can be in any order. In the second column, you assign a unique bit to identify each server type. In the last column, you assign a bit value to that server type. The bit values are the power function of 2, so that bit 1 is 20, bit 2 is 21, bit 3 is 22, and so on.
Next, list the server names in your network and determine what services each server provides. For example, a server might be a Primary Domain Controller (PDC), file server, and print server. Then, using the bits and server-type values in Table 1, calculate an overall value, or services value, for each server. Think of bits as on/off switches. If the server is providing the associated service, the bit is on (represented by a binary value of 1); otherwise, the bit is off (represented by a binary value of 0).
To calculate the services value, sum the server-type values of all the bits that are on. For example, if a server is a PDC, file server, and print server, the services value is 81 (1 + 16 + 64). If a server is a member server, FTP server, Internet Information Server (IIS) system, and SQL Server system, the services value is 5156 (4 + 32 + 1024 + 4096).
Creating the Servers.txt Input F.6
Now, you need to store the information in Table 1 in a text file. Place the services values adjacent to the respective server name. Although the server names can be in any order, you must use the same delimiter to separate the server names and service value pairs as that identified in the script. For example, the Servers.txt input file in Listing 1 uses a comma (with no accompanying spaces) as the delimiter based on the SrvrRole.vbs script in Listing 2.
Using VBScript to Write the SrvrRole.vbs Script
The SrvrRole.vbs script looks for only PDCs and member servers contained in the Servers.txt input file and then displays the names of those servers. To determine whether a server provides a particular service (i.e., the server is a PDC or member server), the script uses the logical And operator to perform a bitwise comparison of the services values (the values from the Servers.txt input file) and the constant bit masks (the server-type values in Table 1). If the result is True, the script executes the task appropriate for that server type; if the result is False, the script skips that server and moves on to the next one.
SrvrRole.vbs begins with the Option Explicit statement, which means that you must declare all variables (in Dim statements) before using them. The script defines several groups of constants (i.e., values that never change).
The constants at callout A in Listing 2 are VBScript constants that the FileSystemObject's OpenTextFile method uses. (FileSystemObject is a VBScript object that allows access to the file system and provides numerous methods, such as the OpenTextFile method, to interact with disks, directories, files, and paths.) The first three constants at A set values that signal whether to open the file for reading, writing, or appending operations. The last three constants at A open the file in either Unicode or ASCII format based on the information stored in the HKCR Registry hive.
The constants at B are the constant bit masks. The script compares these bit masks with the services values.
At C, the script creates a FileSystemObject, whose OpenTextFile method creates and associates a TextStream object with the Servers.txt input file. The OpenTextFile method takes one required and three optional arguments. The required argument is the name of the input file, "Servers.txt", that the script will open. The three optional arguments are ForReading, which specifies the I/O mode; FALSE, which is a create flag in the event the file doesn't exist; and TristateFalse, a file format flag. The OpenTextFile method returns a text stream that the script can read from or append to.
The Do While loop at D contains the code that lets the script read from the sServerList TextStream object and check for the services each server provides until the script reaches the end of the file (i.e., the AtEndOfStream property becomes True). During each loop iteration, the script reads a line from the stream into sBuffer. The script then splits the server name and services value, storing them in the array aServerAndRole. The first element in the array (index 0) contains the server name; the second element (index 1) contains the services value.
At E, the script uses the services value and one or more of the constants defined at B to determine whether the server is a PDC or member server. The script's if statement uses the And operator to compare the services value with the PRIMARYDOMAINCONTROLLER bit mask. If the bit in the services value that corresponds with the bit the constant defines is 1 (i.e., on), the result of the And operation is True. The script then executes the if block, which copies the matching PDC server name to a string. The script's elseif block looks for services values in which the MEMBERSERVER bit is 1. If the bit is on, the script copies the member server's name to a different string.
After the script traverses the entire list of servers in the input file, the script closes the file and then echoes the results to the display. Screen 1 displays the results of executing SrvrRole.vbs.
Although SrvrRole.vbs displays the PDC and member servers, what if you want to manage the password for all Administrator accounts throughout the enterprise? Fortunately, with the bit mask approach, you can easily filter the appropriate target systems from a consolidated server list. Alternatively, if you want to perform an action on all Exchange servers, you can simply change the bit mask filter. Automating such tasks largely depends on valid services values in the input file. In a future column, I'll demonstrate how to calculate and collect these values.
Just Write It
Someday, NT 5.0's Active Directory (AD) will let your scripts and programs access server lists. (For more about AD, see Alistair G. Lowe-Norris, "Managing Permissions for NT 5.0's Active Directory," page 139.) Until then, you can create scripts with this information. Whether you're parsing command-line arguments or generating reports, devising common scripting solutions will improve script maintenance and reduce future script development time.