Downloads
49670.zip

VBScript lacks the native capability to sort an array, which is why I created a Windows Script Component (WSC) named VBSort.wsc. As I described in "Sorting Arrays in VBScript" (April 2006, InstantDoc ID 49458), the main object in this WSC is Penton.VBSort. Let's explore how to use this object by looking at a script named Sorter.vbs. This script uses Penton.VBSort to sort data in one file and write it to another file. Because Sorter.vbs supports both standard input and standard output, you can also use it to sort redirected lines of text.

Using Sorter.vbs
Sorter.vbs requires the Penton.VBSort object, so you must register VBSort.wsc on your computer before you run the script. Sorter.vbs also requires the CScript host.

To launch Sorter.vbs, you follow the command-line syntax

\[cscript\] Sorter.vbs \[filename\]
  \[/o:outputfile\] \[/d\] \[/i\] \[/r\]

You include the cscript keyword at the beginning of the command when CScript isn't your default host (more on this shortly). The filename argument specifies the file to be sorted. The script reads all the lines from this input file into an array, then uses the Penton.VBSort object's Sort method to sort the array. If you don't specify an input file, Sorter.vbs sorts the lines from standard input.

The /o:outputfile option lets you specify the output file into which Sorter.vbs saves the sorted lines. If you use the /o option, make sure that the output file doesn't already exist. (The script won't overwrite an existing file.) If you don't specify the /o option, Sorter.vbs writes the sorted lines to standard output (i.e., the command window). If either the output filename or the input filename contains spaces, enclose the filename in double quotes ("). The /d option specifies a descending sort (i.e., Z to A and 9 to 0). The /i option ignores case when sorting (e.g., A and a are equivalent). The /r option specifies a random sort (i.e., lines are rearranged in random order). The /o, /d, /i, and /r options aren't case sensitive and can appear in any order.

As I mentioned previously, you include the cscript keyword if CScript isn't your default host. When you use the cscript keyword, you must specify the path to Sorter.vbs if the script isn't in the current directory. You can avoid this hassle altogether if you simply set CScript as your default host. To do so, run the command

cscript //h:cscript //nologo
  //s

before you run the script. For example, suppose CScript is your default host and you want to use Sorter.vbs to sort the data (ignoring case) in the file Myfile.txt and write the sorted data to Mysortedfile.txt. In this case, you'd use the command

Sorter.vbs Myfile.txt
  /o:Mysortedfile.txt /i

If you want Sorter.vbs to read data from standard input rather than an input file, there's an important quirk you need to know about. Let's say you want to use the Dsquery command to list all user accounts on your domain, then use Sorter.vbs to sort those accounts. Sorter.vbs uses the WScript object's StdIn property to read from standard input. In theory, therefore, if CScript is the default host, you should be able to sort standard input without specifying the cscript keyword. For example, the following command should work:

Dsquery User -limit 1000 |
  Sorter.vbs /i

This command, however, will either execute with no output or display the error message: The process tried to write to a nonexistent pipe.

One explanation for this peculiarity is that cmd.exe doesn't correctly create the standard input and output streams when it executes a script using the file association. Whatever the cause, to work around this behavior, you must specify the cscript keyword when you redirect input to a Windows Script Host (WSH) script. For the dsquery example, the command would be

Dsquery User -limit 1000 |
  cscript Sorter.vbs /i

Inside Sorter.vbs
Now that you know how to launch Sorter.vbs, let's look at what happens after you do so. As Listing 1 shows, the script begins by defining three constants (the script name and two Win32 API error values), then calls the Main subroutine, which contains the heart of the script. The Main subroutine first declares its variables and assigns the Args variable to the WScript.Arguments collection. The subroutine then checks whether the /? option is present on the command line. If /? is present, the Main subroutine calls the Usage subroutine. The Usage subroutine displays a short usage message and uses the WScript .Quit method to end the script. Next, the Main subroutine uses the ScriptHost function to ensure that it's being executed by cscript.exe. If not, the Main subroutine calls the Die subroutine, which displays an error message and ends the script with a non-zero exit code.

The Main subroutine then verifies that it can create an instance of the Penton.VBSort object. If the subroutine fails to create an instance, it uses the Die subroutine to end the script with an error message and a non-zero exit code, as callout A in Listing 1 shows.

The Main subroutine's next task is to evaluate the script's command-line arguments. If an unnamed argument exists (i.e., if there's a command-line argument that doesn't begin with the / character), the Main subroutine uses that unnamed argument as the input filename. The subroutine then uses the FileSystemObject object's FileExists method to determine whether the file exists. If the file doesn't exist, the Main subroutine ends the script with the Die subroutine. If the file exists, the Main subroutine next tries to open the file as a TextStream object. If the Main subroutine fails to open the file, the subroutine ends the script with an error message.

If no unnamed command-line arguments exist, the Main subroutine assumes that you want to sort standard input. The subroutine uses the WScript.StdIn property as the input file.

After evaluating the command-line arguments, the Main subroutine determines whether the /o option is present on the command line. If the option exists and specifies a filename, the Main subroutine checks whether the specified file exists. If the file doesn't exist, the Main subroutine ends the script with an error and a non-zero exit code. Otherwise, it attempts to open the output file as a TextStream object. If the Main subroutine fails to open the file, it ends the script with an error message. If the /o option isn't present or is present but doesn't specify a filename, the Main subroutine assumes you want to use standard output and uses the WScript.StdOut property as the output file.

Next, the Main subroutine checks for the presence of the /d, /i, and /r options and sets the Descending, IgnoreCase, and Random properties of the Penton.VBSort object. At this point, the Main subroutine is ready to read the input into an array.

The Main subroutine uses the On Error Resume Next statement to disable VBScript's default error handler, then uses VBScript's Split function to read the input file into an array. The function uses the newline character (which the vbNewLine constant represents) to delimit array items. In case an error occurs, the Main subroutine caches the Err object's number property (to identify the error number) and uses the On Error GoTo 0 statement to re-enable VBScript's default error handler, as callout B shows.

If no error occurs (i.e., the Result variable contains 0), the Main subroutine calls the Penton.VBSort object's Sort method to sort the array. After the array has been sorted, the Main subroutine uses a For ... Next statement to write each line in the array to the output file, as callout C shows. Finally, the Main subroutine uses the Close method to close both the input and output TextStream objects.

A Useful Demonstration
Sorter.vbs offers a useful file-based command-line implementation of the Penton.VBSort object. The script also provides a simple example of how to use the Penton.VBSort object in your own scripts.