Use third-party products to fill in WSH's gaps

You just finished your first automated user management script. The script is great, but as soon as you distribute it, someone requests that you add support for Remote Access Service (RAS) permissions. This request is troubling because you developed the script using Visual Basic Script (VBScript) in Windows Scripting Host (WSH), a tool that doesn't support RAS permissions by default.

What do you do? If you followed my column throughout the past year, you might look outside WSH for a solution. Many of my articles emphasized that scripts are bits of syntax that glue together command-line utilities, components, and any libraries, modules, or objects your scripting language includes.

The fact that you used WSH to create your user management script implies that you also used Active Directory Services Interfaces (ADSI) because WSH doesn't include user management capabilities, per se. Therefore, you might begin your search for RAS permission capabilities in ADSI. Unfortunately, you won't find the functionality you're looking for because ADSI doesn't expose Windows NT's RAS settings. Next, you might look for a command-line utility that you could spawn or call from your script, but again you'll come up empty-handed. You might begin to think you've hit a dead end and the enhancement isn't possible.

However, you just need to find the right third-party component. As you think about your RAS permissions problem, remember that WSH is a component object model (COM) controller. If you can find a COM component that exposes NT's RAS permissions, you've solved your problem. As you've probably guessed, such a component exists.

The Component
NTAccess.RAS, which you can download from Zaks Solutions (http://www.zaks.demon.co.uk/code/), is a third-party COM component that exposes NT's RAS configuration and permissions settings. Zaks Solutions developed NTAccess.RAS for use with Internet Information Server (IIS) and Active Server Pages (ASP). Because WSH is merely a repackaging of the COM-based ActiveX scripting engine in IIS and Internet Explorer (IE), you can leverage NTAccess.RAS in the WSH script you created for user management. Listing 1, page 194, contains a WSH script called RasPerms.vbs that uses NTAccess.RAS. I'll walk through RasPerms.vbs to show you how it works.

If you want to run RasPerms.vbs, download and register NTAccess.RAS. Download the archive that contains the component from the developer's Web site, unzip the file, and place the component's .dll, nta_ras.dll, in your component directory. Then, use NT's regsvr32.exe utility to register the component. Type

D:\Components\NTAccess.RAS> regsvr32 nta_ras.dll

A message box will appear to let you know that you successfully registered the component. After you register the component, you're ready to use the script.

The Code
To start RasPerms.vbs, you type

D:\Scripts> wscript rasperms.vbs

then enter the arguments you want RasPerms.vbs to use. RasPerms.vbs recognizes five command-line arguments in the format option=value (for options h, u, s, t, and n).

TABLE 1: Keys and Values in a Sample objHash Dictionary ObjectKeyValue
h
u
s
t
n
\\compaq575
tmtowtdi
1
2
(123) 456-7890
You must include a value for the u and h options. You use u to specify the username for which you want to modify permissions and h to specify the Uniform Naming Convention (UNC) host name of the server that holds the user's account. You can include the s option to specify whether the user has dial-up permissions. Set s to 0 to disable the user's RAS permissions; set s to 1 to enable the target user to use RAS. If you set s to 1, you can include the t option to specify NTAccess.RAS's CallBackType property, which tells RAS whether to call back a user who dials in. If you set t to 1, RAS doesn't call the user back. If you set t to 2, RAS calls the user back at a phone number you specify. If you set t to 4, RAS calls the user back at a phone number the user provides. If you set t to 2, you also need to include the n option on the RasPerms.vbs command line. Set n to the phone number you want RAS to use to call the user back.

RasPerms.vbs begins by setting the Option Explicit directive, declaring the script's variables, and initializing the Messages array that the script uses to communicate its results to the user. WScript automatically initializes the Arguments collection with the option=value pairs the user enters at the command line; RasPerms.vbs just needs to set a reference to the collection to access it. At callout A in Listing 1, RasPerms.vbs initializes objArguments with WScript's Arguments collection. Next, the script uses the Count property to test the number of arguments in the collection. If the number of arguments is zero or the first argument in the collection, objArguments(0), contains a question mark character (?), RasPerms.vbs calls the Usage subroutine, which appears at the end of Listing 1. The Usage subroutine echoes the script's instructions, as Screen 1, page 196, shows, and uses WScript's Quit method to exit the script.

If RasPerms.vbs doesn't call the Usage subroutine, it creates a VBScript Dictionary object called objHash that stores the WScript arguments as switch=value pairs. VBScript's Dictionary objects are identical in concept to (although not as functional as) Perl hashes. Rather than storing list elements based on a numerical index as arrays do (e.g., array(0), array(1), array(2)), hashes and Dictionary objects use a named index to store elements. You refer to the named index as the hash or Dictionary object key, and to the data each key points to as its value.

At callout B, RasPerms.vbs adds the command-line arguments that objArguments references to objHash. Each iteration of the For Each loop begins by assigning the next element in objArguments to the variable arg. Next, VBScript's Left function returns the leftmost character of the current arg, which is the argument's switch (h, u, s, t, or n). The script initializes cSwitch with the character the Left function returns, then compares cSwitch with single characters that represent the options that the script supports. When cSwitch matches a character that the script supports, RasPerms.vbs uses the Dictionary objects Add function to add the switch and value to objHash: RasPerms.vbs selects the switch for addition to objHash as the value's key, then uses the VBScript Split function to separate the value from the rest of the argument. The 1 subscript tells Split to return only the second part of the arg string, in this case the part of the string that comes after the equal sign (=). Table 1, page 196, illustrates the contents of objHash when a user types the following command line to start RasPerms.vbs:

D:\Scripts> wscript rasperms.vbs h=\\compaq575 u=tmtowtdi s=1 t=2 n="(123)456-7890"

NTAccess.RAS Enters the Script
I used a Dictionary object rather than simple variables to hold RasPerms.vbs's command-line arguments because of a problem I ran into with the NTAccess.RAS component. NTAccess.RAS disables RAS permissions if the component's Dialin property is 0. Testing whether the user running the script failed to enter a value for the s option or specifically set s to 0 would be difficult with simple variables because VBScript initializes simple variables to 0 by default. I could have traversed the objArguments collection multiple times or set a flag the first time I traversed it, but the Dictionary object provides a more elegant and efficient method for determining whether the user entered a value of 0 for s. Dictionary objects let you test for the existence of a key so you can determine whether the user supplied a certain argument.

At callout C in Listing 1, RasPerms.vbs creates an NTAccess.RAS object. Before creating the object, the script uses the Dictionary object's Exists method to verify that the user supplied u and h arguments at the command line. The Exists method takes one argument in the form of a key name. If the key exists in the Dictionary object, Exists returns true; otherwise, Exists returns false.

When Exists returns false for objHash's u or h key, RasPerms.vbs displays an appropriate error message and exits the script. When Exists returns true for both keys, the script calls VBScript's CreateObject method and passes CreateObject the ProgID of NTAccess.RAS, the object the script is creating. Then, RasPerms.vbs initializes the mandatory properties.

Next, the script applies the changes to the target user's RAS permissions via properties that the NTAccess.RAS object, objRAS, exposes. RasPerms.vbs tests for the existence of the s key in objHash. If an s key exists, the script sets the Dialin property for the user to the value of the objHash("s") key. If the value grants the user dial-up permission, RasPerms.vbs tests for a t key in objHash and sets the CallBackType property to that key's value. Finally, the script checks for an n key in objHash. If the n key exists and the t key has a value of 2, the script sets the CallBack property to the n key's value.

RasPerms.vbs uses the variable nMsgIndex to communicate which changes the script makes to the target user account. If RasPerms.vbs doesn't find the s key, it sets nMsgIndex to 2 and displays a message saying that the user's RAS settings didn't change. If RasPerms.vbs finds the s key but the s key's value is 0, the script sets nMsgIndex to 1 and displays a message saying that the script disabled the user's RAS permissions. If the s key's value is 1, RasPerms.vbs sets nMsgIndex to 0 and displays a message saying that the script enabled the user's RAS permissions. At callout D, RasPerms.vbs uses nMsgIndex as an index to the script's Messages array and echoes to the user an appropriate message and the target account's current RAS settings.

Screen 2 shows a successful RasPerms.vbs command line and the resulting message that RasPerms.vbs produces. Screen 3 shows the user's dial-up information in User Manager after Screen 2's command line successfully changes user Tim Towtdi's RAS permissions.

The Bigger Picture
You can take other routes to get around WSH's lack of support for RAS. For example, ActivePerl's Win32::RasAdmin module and FastLane Technologies' FINAL PowerTools for Windows NT's RAS functions provide functionality similar to RasPerms.vbs. You can also use ActivePerl's Win32::OLE module to control NTAccess.RAS. The best path for you to take depends on your environment and what you're comfortable with.

NTAccess.RAS is an example of dozens of components you can use to fill the functionality voids in WSH and other scripting languages that support COM automation. I chose to write a script to add RAS functionality to WSH because RAS support is missing from many of the scripting and task-automation solutions available today. Whether you use a COM component, an equivalent command-line utility, or a built-in library function is a matter of availability and your preference.