Downloads
50325.zip

I want a list of scheduled tasks for the member servers in my Active Directory (AD) domain. The list should include the user accounts the servers use to run the tasks. I also want to be able to import the list into Microsoft Excel. How can I do this?

I'll answer this question in two parts. First, I explain how to get an appropriate list of computers by searching AD. Second, I show you how to get the scheduled tasks from each computer in the list. Microsoft provides an excellent overview of how to search AD in the "Microsoft Windows 2000 Scripting Guide" (http://www.microsoft.com/technet/scriptcenter/guide). Briefly, using a script to search AD requires the following steps:

  1. Create a Connection object (ADODB.Connection) and use its Open method to establish a connection to AD.
  2. Create a Command object (ADODB.Command) and set its ActiveConnection property to the open Connection object.
  3. Set the Command object's CommandText property to an appropriate LDAP query string.
  4. Use the Command object's Execute method to return a RecordSet object.
  5. Close the Connection object.

The ListComputers.vbs script in Listing 1 uses VBScript to list all Computer objects in the current domain. The code at callout A in Listing 1 uses the rootDSE object to retrieve the current domain's name, and the LDAP query at callout B selects the common name (CN) property (i.e., just the computer name) for all Computer objects. The code at callout C iterates the RecordSet and echoes the Value property of the CN field for each record. The CN field (or column) exists because that's the property that the LDAP query at callout B specifies.

Getting a list of domain controllers (DCs) requires a different approach. Listing 2's script, ListDCs.vbs, shows how to use VBScript to get the list. The code at callout A in Listing 2 uses the rootDSE object to return the current domain's configuration naming context, and the LDAP query at callout B selects the AdsPath property for all nTDSDSA objects. In the AD hierarchy, the nTDSDSA object's parent is a DC. The code at callout C iterate the RecordSet, retrieves the Parent object of each nTDSDSA object, and echoes the Parent object's CN property (i.e., the DC's name).

Because AD doesn't have attributes that store a computer's role (e.g., workstation, member server, DC), you can't include such attributes in a query. To work around this limitation, you can include the operatingSystem attribute in the LDAP query. If the operatingSystem attribute contains the word "server," then the computer is a server. However, note that DCs will be included in such a search.

A script can generate a member server list that doesn't include DCs by first retrieving a list of DCs. After it gets the list of DCs, the script can retrieve a list of Computer objects. If a Computer object's operatingSystem attribute contains the word "server" and the Computer object's name isn't in the list of DCs, the computer is a member server. I've written a complete script, EnumComputers.js, that performs this task for you. It's too long to print here, but you can download it from the Windows Scripting Solutions Web site at http://www.windowsitpro.com/windowsscripting, Instant-Doc ID 50325.

The EnumComputers.js script has the following command-line syntax:

\[cscript\] EnumComputers.js /wks <br>  | /dc | /srv \[/dc\] EnumComputers.js is intended to run in a command window, so it requires the CScript host. The cscript keyword at the beginning of the command line is required only if CScript isn't your default host. To set CScript as your default host, type into a command window the following command:  cscript //h:cscript //nologo //s

EnumComputers.js returns a list of computer names, one per line. The /wks option lists computers that don't have the word "server" in the operatingSystem attribute. The /dc option lists only DCs. And the /srv option uses the technique I described previously to list only member servers. If you use both the /srv and /dc options, EnumComputers.js will list all servers, including member servers and DCs.

Now that we have a script that can retrieve a list of member servers, we can move on to the second part of the question: getting a list of scheduled tasks for the member servers. Complicating the answer is the fact that Windows provides two different APIs for managing scheduled tasks: the At and Task Scheduler APIs. The At command and the WMI Win32_ScheduledJob interface can modify At API tasks, but Microsoft doesn't provide a script object for managing Task Scheduler API tasks.

However, all is not lost because the Schtasks command-line tool provides a method for enumerating Task Scheduler API tasks from the command line. If you include the /v (verbose output) option, the Schtasks /query command returns the user account that's configured to run each task.

Listing 3's Cmd.exe shell script (batch file), EnumTasks.cmd, lists scheduled tasks for each computer in a text file. The script first makes sure that you've provided a command-line argument. Then, the script sets the LISTFILE variable equal to the first argument on the command line, stripping any leading and trailing double quotes in the process. If the file containing the list of computers (which is the text file pointed at by the LISTFILE variable) doesn't exist, the script exits with a non-zero exit code, as the code at callout A in Listing 3 shows.

Because EnumTasks.cmd will simply execute a Schtasks /query command for each line in the text file, the script provides a comma-separated value (CSV) header line to begin its output. Then, EnumTasks.cmd uses the For /f command to parse each line of the text file and calls the ENUM procedure for each line of the file, as the code at callout B shows.

The code at callout C in Listing 3 contains the ENUM procedure. This section of code first creates a temporary filename by calling the TEMPNAME procedure, then calls the ALIVE procedure to determine whether the computer responds to a ping request. If the computer doesn't respond, the script returns the computer name and the message NO REPLY as CSV text and jumps to the end of the ENUM procedure. Next, the ENUM procedure executes the Schtasks command and redirects its output to the temporary file. If the Schtasks command returns a nonzero exit code, the procedure returns the computer name and the message ERROR as CSV text, then jumps to the end of the procedure. Next, the procedure uses the Findstr command to determine whether the temporary file contains at least one double-quote character ("). If the double-quote character doesn't exist in the temporary file, the ENUM procedure returns the computer name and the message NO TASKS as CSV text, then jumps to the end of the procedure.

At this point, the ENUM procedure assumes that the temporary file contains valid CSV text, including a list of the scheduled tasks for the computer. The procedure uses the For /f command to skip the first two lines of the temporary file (the first line is blank, and the second line contains column headings) and displays the remainder of the lines in the file. The ENUM procedure then deletes the temporary file and returns control to the main body of the script.

You can use EnumComputers.js with EnumTasks.cmd to accomplish your goals. First, to use EnumComputers.js to get a list of servers in a text file, run the following command:

EnumComputers.js /srv >
  Servers.txt  

Next, to use EnumTasks.cmd to read the list of servers and redirect the previous command's output to a CSV file, run the following command:

EnumTasks Servers.txt >  
  ServerTasks.csv

You can then use a database or spreadsheet tool such as Excel to import the CSV file for processing.