A big benefit of scripting is the time you can save when you have to perform a task on many machines. When you run a script that needs to connect to many machines, you can encounter a small snag: The script might encounter machines that are inaccessible. One scripting technique that you can use to work around this problem is to record the inaccessible machines in an output log, then use the output log as an input file for future script runs. Let's look at how you can incorporate this technique when writing a script that adds a local group to 500 machines.
Suppose a hardware vendor recently delivered 500 Windows 2000 Professional PCs to your company. After several initial spot inspections showed that the PCs were what the company ordered, the vendor's contractor deployed the PCs throughout the company.
After that deployment, several problems surfaced. All the computers were supposed to have a global group named HelpDesk added to the local Administrators group, but the HelpDesk group members discovered that the contractor didn't add this group to every PC. To work around this problem, the group members began using the local Administrators account to log on to make configuration changes. This workaround led to the discovery of another problem: The local Administrators account had been renamed on some machines. (In Windows NT 4.0, the Administrators group is a built-in group that you can't rename. In Win2K and later, you can rename this group.) Thus, the HelpDesk group members had a difficult time performing tasks that required administrative privileges.
Management asked you to resolve these problems. Because 500 PCs were deployed, you knew that checking and changing permissions manually with an administration tool such as User Manager would be too time-consuming. Thus, you decided to automate the process with a script. When you started looking into how to resolve the problems, you ran into another snag: The PCs' machine accounts are members of a domain to which you don't have Domain Admins permissions. Because Domain Admins group membership is restricted, the domain administrators agreed to provide you with the names and passwords of four local Administrators accounts used for the PCs. However, the domain administrators didn't have a list of which accounts to use on which PCs.
Because you're unsure of which account name and password to use, creating a script that accesses and performs tasks on 500 PCs might seem like a daunting task. However, administrators must often face such challenges when writing scripts. The key is to tackle the project in steps. In this case, for each PC, the script Populate Groups .bat needs to determine whether the PC is turned on, find the correct account and password to log on, determine whether the HelpDesk group exists, and if not, add that group.
Determining Whether the PC Is On
You first need to determine whether the target PC is turned on. To test for connectivity, you can embed a Ping command inside a For command, as the Pingit routine in Listing 1 shows. The Ping command pings the PC, and the For command searches the Ping command's output for the string Reply. If the For command finds that string, the script proceeds to the Tstmem routine, which Listing 2 shows. If the For command doesn't find the string, the script concludes that a ping failure has occurred, so it writes the PC's name to the rerun log called runagain .txt. The script will use this output log as an input file for the next script run. The script displays a message that it's adding the PC to the rerun log, increments an operations counter named Leftcntr, then proceeds to the end of the file. (For information about counters in Populate Groups.bat, see the Web-exclusive sidebar "Using Counters to Track Successes and Failures," http:// www.winscriptingsolutions.com, InstantDoc ID 23064.)
To log on to the target PC, you can use the Net Use command. The syntax you need to use is
Net Use \[device\] \\computer\share \[password\] \[\user:domain\username\]
where device is the PC's drive letter, \\computer\share is the PC's Universal Naming Convention (UNC) name, and password is the password for the local account that username specifies. In this case, the username must include the domain.
Because you don't know which account to use when you log on to the PCs, you need to test each local Administrators account by chaining together a series of Net Use commands. As callouts A, B, C, and D in Listing 2 show, four of the Net Use commands contain usernames and passwords. In these four Net Use commands, the double ampersand (&&) tells the command processor to execute the command that follows only if the previous command executed successfully. Thus, the script sets the User variable and goes to the Addthem routine, which Listing 3, page 6, shows, only if the script successfully executes the preceding Net Use command; the successful execution of the Net Use command hinges on whether that command contains the correct username and password for the target PC. If all the Net Use commands fail, the script notes the PC's name in addlog .csv, displays an error message, and increments the Logoncntr counter.
No matter whether a Net Use command succeeds or fails, the command creates a connection to the specified share. Thus, the Net Use commands after callouts A, B, C, and D in Listing 2 delete the connections that the previous Net Use commands made. To disconnect such connections, you use the Net Use command with either the /d switch or the /delete switch. In all eight Net Use commands, the 1>NUL 2>NUL code suppresses the standard and error output of the Net Use commands to eliminate screen clutter. (For more information about redirecting output to NUL, see my Web-exclusive article "Shell Scripting 101, Lesson 4," http://www.winscriptingsolutions.com, InstantDoc ID 20530.)
If a Net Use command contains the correct username and password, the script sets the User variable to A, B, C, or D. These letters represent the four local Administrators accounts. By setting the User variable to letters, the addlog.csv log doesn't include the account username or password. You should also avoid hard-coding usernames, passwords, and other sensitive information in scripts. Sometimes, though, you don't have an option, as is the case with PopulateGroups.bat. In such instances, you should protect the script by assigning appropriate file permissions so that the sensitive information isn't visible to prying eyes. In addition, as soon as you're finished using the script, you should remove all the sensitive information.
Determining Whether the HelpDesk Group Exists
The next step is to determine whether the HelpDesk group is present. You can make this determination with the Local utility, which you can find in the Microsoft Windows 2000 Server Resource Kit or the Microsoft Windows NT Server 4.0 Resource Kit. Before you can check for that group, though, you need to make sure that the local Administrators account hasn't been renamed. Here's why: If the HelpDesk group isn't present, the script uses the Win2K or NT resource kit's Addusers utility to add this group. When adding the Help- Desk group, the Addusers utility also attempts to add the Administrators group. If an Administrators group already exists, the attempt fails with no ill consequences. However, if the Administrators group doesn't exist because someone renamed it, the Addusers utility will add a new Administrators group. Although this added group has the name Administrators, it has none of the permissions of the built-in Administrators group. So, to prevent this situation, you need to test for the existence of the Administrators group and the HelpDesk group.
To test the target PC for the existence of a local Administrators group, you embed the Local command inside a pair of For commands, as callout A in Listing 3 shows. The Local command enumerates the users or groups that are members of the group you specify. In this case, you specify the Administrators group. The Local command will output an error message rather than an enumeration if it can't find the specified group or if the specified name is actually the name of a user, not a group, on that machine. Thus, the pair of For commands searches the Local command's output for two key words—found and GetUsers—that signify either error condition occurred. If the found or GetUsers string is present, the script records the PC and logon information in the add log.csv file, increments the Errorcntr counter, then goes to the next PC.
If the found and GetUsers strings aren't present, the local Administrators group exists and the script proceeds to the For command that callout B shows. After the Local command executes, the For command searches the Local command's output for the string that the %Group% variable holds (i.e., Help Desk). If the For command finds that string, the script concludes that the HelpDesk group already resides in the Administrators group and moves on to the next PC. If the string isn't present, the script proceeds to add the group.
Adding the HelpDesk Group
As I mentioned previously, the Addusers utility adds the HelpDesk group to the local Administrators group. For this utility to work, all the PCs must be members of a domain (not a workgroup) and the domain that contains the PCs must trust the domain that contains the HelpDesk group.
The Addusers utility uses an input file to add users or groups. Because you don't know which PCs need the Help Desk group, you can't create this input file in advance. Instead, the script needs to create the input file on the fly. The code at callout C creates this input file. The Addusers utility then uses the input file to add the HelpDesk group, as the code at callout D shows. To make sure that the Addusers utility successfully added the group, you again use the Local utility to check for its existence.
Sorting the Results
Each time you run PopulateGroups.bat, it updates the addlog.csv file. By default, the PCs appear in the order in which the script processed them. With 500 PCs, finding a particular PC would be difficult. To make PCs easier to find, the script alphabetizes the PC names with the code
Sort <%temp%\log.csv|Findstr /i /v /c:"Group Already Added" >>%Log%
The Sort command places the PC names in alphanumeric order, and the Findstr command removes the header Group Already Added that the Addusers utility might have added to the add log.csv file.
I've tested PopulateGroups.bat on Win2K Pro running Service Pack 2 (SP2) and NT Workstation running SP6. To use PopulateGroups.bat in your environment, you first need to download the script from the Code Library on the Windows Scripting Solutions Web site and install the Win2K or NT resource kit. The resource kit must be in the same path as the script. (If you want the resource kit in another location, you can specify that path in the script.)
Next, you need to create an input file that lists the PCs you want to test initially. Put one PC name per line, and save the PC input file as pclist.txt.
At this point, you need to customize the script for your environment. Here are the customizations:
- Customize the %temp% variable location, if needed. PopulateGroups .bat uses a %temp% variable that's typically a user variable. If you plan to run the script under a system account, this variable might not exist and cause the script to fail. Thus, you need to customize the line
- Customize the name of the group you want to add. In the line
- Customize the location of the PC input file. In the code
- Customize the name of the log. In the code
Set Log= \\dom1pdc\tools\addlog.csv
replace \\dom1pdc\tools\addlog.csv with the path to your log.
- Customize the path to the rerun log that records the PCs to be tested on the next run. In the code
- Customize the local Administrators accounts in the code that callouts A, B, C, and D in Listing 2 highlight. Following the syntax
Rem Set temp=C:\temp
First, uncomment the line by removing the Rem command. Then, replace C:\temp with your temporary variable location. (The location must be on the computer on which you plan to run the script.)
replace domain1\helpdesk with your group's domain and name.
replace \\dom1pdc\tools\pclist.txt with the path to your PC input file.
Set Rerunlog= \\dom1pdc\tools\runagain.txt
replace \\dom1pdc\tools\runagain.txt with the path to your rerun log.
Net Use \\%target%\ipc$ password /user:%target%\username
customize password (e.g., hello1, the 1man) and username (e.g., root, root1). You can add or delete accounts as needed.
Finally, schedule the script to run several times per day during the times when you think most of the computers will be on. After a few days of running the script, you'll have added the group to almost all the computers.