Windows NT Shell Scripting

The Microsoft Windows NT Server 4.0 Resource Kit and third-party utilities can often make writing scripts easier. However, sometimes you can't use resource-kit or third-party utilities because of corporate configuration management policies, the software loaded on the servers, or other reasons. In these situations, you can use the built-in NT shell commands. With NT shell commands and a little creativity, you can effectively perform almost any task.

For example, suppose you need to write a script that creates 200 local groups at a client site, but you don't have access to any resource-kit or third-party utilities. You can use the NT shell command called Net LocalGroup. This command lets you manage local groups in a domain. This month, I show you how the scripts CreateGroups.bat and PopulateGroups.bat use the Net LocalGroup command to create local groups and populate them with users. I also show you how you can run those scripts in your environment.

Determining the Command's Syntax
Before you can use any NT command, you need to know its syntax. You can obtain any NT command's syntax by typing the command name followed by /? at the command line. So, to obtain Net LocalGroup's syntax, you need to type

                              Net LocalGroup /? 

at the command line. Figure 1 shows the result. This syntax might look intimidating, so let's break it down. The elements with a slash (/) in front of them (e.g., /COMMENT) are switches. Switches tell the command what to do. As Figure 1 shows, Net LocalGroup has four switches:

  • /ADD—adds groups and adds users to already-existing groups
  • /COMMENT—adds the specified text (i.e., "text" in Figure 1) describing the group
  • /DELETE—deletes groups or users
  • /DOMAIN—specifies the domain you're manipulating

The groupname element specifies the group you want to manipulate. So, to add groups and descriptions of those groups, you use the syntax

                              Net LocalGroup groupname /add                              /comment:"text"

Note that I didn't put the switches and command name in all capital letters as Figure 1 shows. NT shell commands are typically case insensitive, so I title-capped the command name and lowercased the switches for easier reading.

Creating the Input File
By determining the syntax, you now know that you must provide the group name followed by the group description for each group you want to create. To provide this information, you can use a Comma Separated Values (CSV) file called grouplist.csv. In this file, the group names (e.g., SalesTeam) are in column A and the group descriptions (e.g., This group contains members of the sales team) are in column B. The Code Library on the Windows Scripting Solutions Web site at contains a template for this CSV file.

Controlling the Script's Execution
Any script that is specific to a particular workstation or server needs to include code that prevents execution on the wrong machine or by an unauthorized user. As Listing 1, page 8, shows, CreateGroups.bat includes such code. Here's how the code works.

Before you use CreateGroups.bat, you specify the computer on which you want the script to run, the user you're authorizing to run the script, and the path to grouplist.csv. The %Server%, %User%, and %InputFilePath% environmental variables hold this information, respectively. (An environment variable, or variable, is a data storage container that lets you transport data from one part of a script to another.) When someone executes CreateGroups.bat, the first two If commands in Listing 1 compare the values in %Server% and %User% with the values in %Computername% and %Username%, respectively. %Computername% contains the name of the computer the script is running on, and %Username% contains the name of the person who is running the script. (NT automatically provides both the %Computername% and %Username% values.) The /i switch tells the If commands to perform a case-insensitive comparison. The last If command checks for the existence of the input file that %InputFilePath% specifies. If the computer names and usernames match and the input file exists, the script proceeds. Otherwise, the script sends an error message and exits.

Adding a Date and Time Stamp
A standard element in any script is a date and time stamp. CreateGroups .bat uses the code in Listing 2 to place the date and time in a log file. The code in Listing 2 uses the Date and Time commands to obtain the current date and time. (The /t switch tells the command not to display a prompt asking the user to specify a new date or time.)

Let's first take a look at the For command that obtains the time, which callout A in Listing 2 highlights. In this code, the For command captures and parses (which the /f switch specifies) the Time command's output, places the output in the temporary iterator variable (%%i), then sets the %%i variable to the %timeoday% variable.

You might be wondering why the time data transfers from one variable to another. Unlike environment variables, iterator variables are temporary data storage containers that exist only within the particular For command you use them in. Thus, to use the time data outside the For command, you need to transfer the data to an environment variable (in this case, %timeoday%). Unlike environment variables, iterator variables are case sensitive and must always be lowercase. Another nuance is that if you use iterator variables in a script, you must use double percent (%%) signs. If you use iterator variables at the command prompt, you use single percent (%) signs.

The For command that obtains the date is a bit more complex. In this code, the For command parses the Date command's output into pieces, or tokens. Because you want only the date (e.g., 12/14/2000) and not the day of the week (e.g., Thu), the For command captures only the second token ("tokens=2"). After placing this captured data in the %%i variable, the For command assigns the date token to the %date% variable. (For detailed information about how to use the For command to parse and extract data, see "Getting Started in NT Shell Scripting, Part 2," April 2000.)

CreateGroups.bat uses the Echo command to output, or echo, the %date% and %timeoday% variables to the log file. The single redirect (>) character redirects output to a file. In this case, the script is redirecting the date and time stamp to the first line of the log file, overwriting any existing data in the log file. If you just want to append the date and time stamp to the existing log file, you can replace the > character with a double redirect (>>) character.

Accessing the Input File Data
To access the data in the input file, the script uses another For command:

                              For /f "tokens=1,2 delims=,"                              %%i in (%InputFilePath%)                              Do (Set Group=%%i) &                               (Set Desc=%%j) & (Call :Next)

This command returns each row of data in grouplist.csv as a string and uses a comma as a delimiter (delims=,) to split each string into two tokens (tokens=1,2), which will hold the group name and group description, respectively. The command temporarily assigns the tokens to %%i and %%j, respectively, then sets %%i and %%j to the Group and Desc variables, respectively.

Making Sure the Output Is Meaningful
Some NT shell commands don't provide meaningful output that specifies the command's success or failure. Thus, you need to determine whether you can use the output as is or you need to manipulate it.

Let's test the output of Net LocalGroup. Create a grouplist.csv test file with three group names and three descriptions. Then, type

                              For /f "tokens=1,2 delims=," %i                              in (C:\grouplist.csv) Do                               @Net LocalGroup "%i"                              /Add /Comment:"%j"

at the command prompt. Figure 2 contains the output. Now, run the same command again to try to create groups that already exist. This second execution lets you observe the error output, which Figure 3 shows. Looking at the output in Figure 2 and Figure 3, you can easily determine which groups you successfully and unsuccessfully created. This determination wouldn't be as easy to make, however, if you were creating 200 groups instead of 3.

To obtain output that is easier to read, you can suppress a command's output and create customized messages. To suppress output, you can take advantage of the three standard file handles in command-line programs: standard input (STDIN, which has a value of 0), standard output (STDOUT, which has a value of 1), and standard error (STDERR, which has a value of 2). Thus, to suppress positive output (i.e., output from a command's successful execution), you can use the code >Nul. To suppress error output, you can use the code 2>Nul. (For more information about file handles, see Toby Everett, "Reader to Reader: Use Command-Line Operators to Their Fullest Extent," November 1999.)

As Listing 3 shows, you can use >Nul and 2>Nul together to suppress all command output. How, then, do you determine whether the command succeeded or failed? You use the double ampersand (&&) operator to create a compound command. You're probably familiar with the single ampersand (&) operator. When you use the & operator to join commands, the second command executes whether or not the first command successfully executes. With the && operator, the second command executes only if the first command successfully executes. Thus, the code in Listing 3 is telling the script to use the Echo command to display the message %group% successfully created! (where %group% is the group's name) only if the Net LocalGroup command successfully executes. Because >Nul and 2>Nul immediately precede the && operator, you might think that their execution determines whether the Echo command executes. However, >Nul and 2>Nul aren't commands but rather redirect instructions for the Net LocalGroup's output, so their success or failure doesn't affect whether the Echo command executes.

Counting the Successes
Knowing how many times a command successfully executes is helpful. You can use the Set command to obtain these numbers. When you use the Set command with the /a switch, the command performs mathematical operations. The code in Listing 3 uses the Set command to increment a counter by 1. The && operator ensures that the counter increments only when the Net LocalGroup command successfully creates a group.

Customizing and Running CreateGroups.bat
CreateGroups.bat adds local groups to the server or workstation on which you run batch files. You can find both CreateGroups.bat and PopulateGroups.bat in the Code Library on the Windows Scripting Solutions Web site. Both scripts include comments to help you understand the code.

To get CreateGroups.bat working in your environment, follow these steps:

  1. Create a CSV file in a spreadsheet program such as Microsoft Excel, following the guidelines discussed in the "Creating the Input File" section.
  2. Configure the CreateGroups.bat script. Toward the top of the script, you'll find the section that Listing 4 shows. In this code, replace
    • work1 with the name of the computer on which you'll run the script.
    • Administrator with the username of the person authorized to run the script.
    • C:\grouplist.csv with the path to your input file. This path must not contain spaces.
    • C:\errorlog.txt with the path to your error-log file. This path must not contain spaces.
  3. Test the script carefully in a nonproduction environment before you run it in your production environment.

Adding Users to the Groups
Now that you've created groups with the CreateGroups.bat script, you need to populate them. The script PopulateGroups.bat does just that. The code in PopulateGroups.bat is similar to CreateGroups.bat. PopulateGroups.bat parses a CSV input file called userslist.csv and adds the appropriate users to each group. The script echoes the success and failure of each attempt to both the screen and the log file.

To use PopulateGroups.bat, you need to follow these steps:

  1. Create an input CSV file that contains the group name, domain, and username for each user you want to add. In this file, put the group names in column A, the domain in column B, and usernames in column C. Save the spreadsheet as userslist.csv. If you open userslist.csv, it has the format
                                  Group1,mydomain,username1                              Group1,mydomain,username2                              Group2,mydomain,username3
  2. Configure PopulateGroups.bat. Toward the top of the script, you'll find the section that Listing 5 shows. In this code, replace
    • C:\userslist.csv with the path to your input file. This path must not contain spaces.
    • C:\errorlog.txt with the path to your error-log file. This path must not contain spaces.
  3. Test the script carefully in a nonproduction environment before you run it in your production environment.

I wrote and tested both CreateGroups.bat and PopulateGroups.bat for systems running Windows 2000 and NT 4.0 Service Pack 6 (SP6). If you follow the steps just given, these scripts will be creating and populating groups in your system.