In "Script User Account and Mailbox Creation," September 2002, http://www.exchangeadmin.com, InstantDoc ID 25843, I discussed how to write a script that creates user accounts and mailboxes in Exchange 2000 Server. In response, I received several email messages from readers who wanted to know how to write a script that creates user accounts and mailboxes in Exchange Server 5.5. The tools required for such a script include Active Directory Service Interfaces (ADSI), Windows Script Host (WSH), and a COM object (AcctCrt.dll), whose source code is contained in the Exchange 5.5 software development kit (SDK). Let's look at how you can use these tools, along with VBScript and a touch of XML, to programmatically create user accounts and mailboxes in Exchange 5.5. I do my best to follow the outline of the previous article. Thus, if you read the previous article, you'll find this article easy to follow.
The System Requirements
The utility that creates Windows NT or Active Directory (AD) user accounts and mailboxes in Exchange 5.5 is called CrUM55. CrUM is short for Create User and Mailbox; 55 designates that this script is designed to create mailboxes in an Exchange 5.5 directory only. To use CrUM55, your network must be running Exchange 5.5 and have a Windows 2000 or NT domain in which you want to create user accounts.
When you manually create user accounts and mailboxes in Exchange 5.5, two possible scenarios exist. In one scenario, you create an NT user account, then create the mailbox. In the other scenario, you create an AD domain user account, then the Active Directory Connector (ADC) automatically creates the mailbox. In either case, Exchange 5.5 automatically assigns the user account SID to a mailbox attribute. When you use CrUM55 to programmatically create user accounts and mailboxes in Exchange 5.5, the script automatically creates the user account and mailbox. CrUM55 uses the user account SID that NT or AD creates to link the account and mailbox.
Before running CrUM55, you need to perform three minor tasks on the client computer on which you intend to run the script. First, you must make sure that you can manually create a user account and mailbox from the client computer.
Second, you must install WSH 5.6. You need version 5.6 because the script uses WSH 5.6's improved method of managing command-line arguments and its XML file format; earlier WSH versions don't support either feature. Windows XP includes WSH 5.6. You can download the WSH 5.6 upgrade for Win2K, NT, Windows Me, and Windows 98 at (http://msdn.microsoft.com/library/default.asp?url=/downloads/list/webdev.asp).
Finally, you need to copy and register AcctCrt.dll on the client computer on which CrUM55 will run. AcctCrt.dll contains the AcctMgmt class, which the utility needs to associate a user account with an Exchange 5.5 mailbox and to generate a Security Descriptor (SD) for the mailbox. The SD gives the user account permission to use the mailbox. The DLL's source code is part of the Exchange 5.5 SDK. I've compiled the source code for the x86 platform and included it in the CrUM55_Utility.zip file, which you can download from http://www.exchangeadmin.com, InstantDoc ID 39177. After you download CrUM55_Utility.zip, copy AcctCrt.dll to the \%systemroot%\system32 folder on a computer running an NT-based OS, such as XP, Win2K, or NT. Then, from a command line, type
and press Enter.
The Script Basics
The CrUM55 utility consists of two files: CrUM55.wsf, which contains the XML-based command-line Help for running the script, and CrUM55.vbs, which contains the VBScript code to complete the creation tasks. The version of this tool that I wrote for creating Exchange 2000 mailboxes and AD user accounts consists of only one file—a .wsf file. However, for creating Exchange 5.5 mailboxes and NT or AD user accounts, I found that separating the VBScript code from the XML code made the utility easier with which to work. For more information about the .wsf file format, see "The Script Basics" section of "Script User Account and Mailbox Creation."
You can run CrUM55.wsf from either WScript (the WSH graphical interface) or CScript (the command-line interface). For command-line help with CrUM55.wsf, type
and press Enter.
When you run CrUM55.wsf from WScript, the .wsf file displays status and Help information in a message box, as Figure 1 shows. When you run CrUM55.wsf from CScript, the .wsf file displays the same information in a command window, as Figure 2 shows.
Whether the Help information appears in a message box or command window depends on which script host you've configured as the default. WScript is the default script host unless you specifically configure WSH to use CScript. To configure CScript as your default script host, type the following code at the command line:
and press Enter.
CrUM55.wsf requires five parameters (i.e., /a, /u, /d, /f, and /l) to create an NT domain user account and Exchange 5.5 mailbox and six parameters (i.e., /a, /u, /d, /c, /f, and /l) to create an AD domain user account and Exchange 5.5 mailbox. Figure 1 and Figure 2 describe the values you specify for each parameter. For example, if you want to create a mailbox and an AD domain user account named EthanW for Ethan Wilansky in the Scripters OU below the IT OU of the adatum.com domain, you'd type
Crum55.wsf /a:ad /u:EthanW /f:Ethan /l:Wilansky /c:ou=scripters,ou=it, dc=adatum,dc=com /d:adatum
and press Enter. (Although this command appears on several lines here, you would enter this command all on one line when you enter it at the command line.)
Notice that the parameter order in the example differs from the parameter order that Figure 1 and Figure 2 show. I switched the order to demonstrate that the parameters' order is irrelevant. You can arrange the parameters any way that works best for you. However, when a parameter's value contains a space, you must enclose the value in quotes (e.g., /u: "Ethan Wilansky").
The XML Advantage in CrUM55.wsf
Listing 1 contains CrUM55.wsf. One reason why CrUM55.wsf uses the XML format is to take advantage of the <runtime> element. This element documents usage information that the .wsf file displays when it runs. The code at callout A in Listing 1 shows CrUM55.wsf's usage information. CrUM55.wsf calls CrUM55.vbs, which uses the ShowUsage method to display the contents of the <runtime> element. Figure 1 and Figure 2 are the result. ShowUsage is a special method that WSH 5.6 includes. If you use the <runtime> element and the ShowUsage method, you don't have to write extra code to provide Help information.
The <job> element, which is the parent of the <runtime> element, encapsulates one task in a .wsf file. I could have defined several jobs in this file, but for simplicity, I defined creating a user account and a mailbox as one task and, therefore, one job. The opening <job> tag appears directly above callout A in Listing 1, and the closing </job> tag appears near the end of Listing 1.
The <package> element is the parent of the <job> element and contains one or more jobs in the .wsf file. Because this .wsf file involves only one job, the <package> element is optional. However, I recommend including it so that you get in the habit of adding this element.
The <script> element is a child of the <runtime> element. Within the <script> element, the language attribute specifies the scripting language to use, and the src attribute specifies the name and location of the source-code file. As the code at callout B in Listing 1 shows, in this case, the language is VBScript and the source-code file is CrUM55.vbs. Because the src attribute doesn't specify a folder location, CrUM55.wsf assumes that CrUM55.vbs is in the same folder that CrUM55.wsf is in.
The Step-by-Step Details of CrUM55.vbs
Now that you know how CrUM55.wsf works, let's look at the inner workings of CrUM55.vbs. CrUM55.vbs performs many tasks, the most notable of which are handling errors, retrieving the parameters you entered at the command line to launch the CrUM55 utility, creating the user account, and creating the mailbox.
Handling errors. Throughout CrUM55.vbs, you'll find the On Error Resume Next statement, which lets the script continue to execute despite common errors that the script might encounter. The goal isn't to skip errors but rather to provide more descriptive information about what caused them. The code in Listing 2 shows one of the error-handling routines in CrUM55.vbs. In this routine, the On Error Resume Next statement appears immediately before an attempt to connect (i.e., bind) to an AD container. If the binding operation fails, the routine informs you that it couldn't find the AD container, tells you to check the value you specified for the /c parameter, then terminates the script. If the binding operation is successful, the On Error GoTo 0 statement enables VBScript's native error-handling capability so that if another error occurs, you'll be informed.
Retrieving the command-line parameters. As I explained previously, the <runtime> element in CrUM55.wsf documents the CrUM55 utility's six command-line parameters. The <runtime> element, however, doesn't retrieve those parameters. Instead, CrUM55.vbs retrieves them with the WshArguments object's Named property.
The Named property returns the WshNamed child object, which is a collection of named arguments (i.e., command-line parameters). As Web Listing 1 shows, CrUM55.vbs sets the returned named arguments collection to the objArgs variable, then uses the WshNamed object's Item property to set each argument to a variable.
Listing 3 shows how the script determines whether you've specified all the required command-line parameters. The code performs a few simple tests. First, it determines whether the value of the /a parameter is NT or AD. The script makes the value uppercase so that case doesn't matter when you enter the /a parameter on the command line. If you specified a different value or no value at all for the /a parameter, the WshArguments object's ShowUsage method displays the Help information, then the script terminates.
After testing the /a parameter, the script uses the WshNamed object's Count method to verify that you entered the correct number of command-line parameters. If the total number of command-line parameters is fewer than five for creating an NT user account or fewer than six for creating an AD user account, the ShowUsage method displays the Help information, then the script terminates. The script also verifies that each required parameter contains a value.
Creating the user account. If the required parameters are present, CrUM55.vbs creates the user account. The script uses the CreateNTDomainUser() subroutine to create NT domain user accounts and the CreateADDomainUser() subroutine to create AD domain user accounts.
CreateNTDomainUser() and CreateADDomainUser() are similar. The difference lies in the ADSI provider that's responsible for making various interfaces available to complete the user account creation task. CreateNTDomainUser() relies on the WinNT provider, whereas CreateADDomainUser() relies on the LDAP provider. In both cases, the following tasks occur:
- The subroutine uses the GetObject function with the appropriate ADSI provider to bind to the container (an NT domain, AD container, or organizational unit—OU) in which it will create the user account.
- The subroutine calls the IADsContainer interface's Create method to create the user account object.
- The subroutine calls the IADs interface's Put method to assign various attributes to the user account object.
- The subroutine calls the IADs interface's SetInfo method to save (i.e., commit) the object to the directory.
Both subroutines assign only a few attributes to the user account objects. If you want to assign more attributes to an NT user account, see the WinNT Schema's Mandatory and Optional Properties Web page (http://msdn.microsoft.com/library/default.asp?url=/library/enus/netdir/adsi/winnt_schemaampaposs_mandatory_and_optional_properties.asp) for examples. For examples of how to assign additional attributes to an AD user account, go to the Microsoft TechNet Script Center (http://www.microsoft.com/technet/treeview/default.asp?url=/technet/scriptcenter/default.asp) and click the Users and Groups link under the Script Center Sections heading.
Creating the mailbox. After creating the user account, CrUM55.vbs uses the CreateMailbox() subroutine to create an Exchange 5.5 mailbox and associate that mailbox with a user account. This subroutine begins by defining three constants: DelivExtContentTypes, ComponentCreateFailed, and ADS_PROPERTY_APPEND. The DelivExtContentTypes constant is the value assigned later in the subroutine to the Deliv-Ext-Cont-Types mailbox attribute. This attribute lets the mailbox convert incoming messages from the X.400 connector to Exchange Server mail format. The ComponentCreateFailed constant is set equal to a VBScript runtime error that indicates a missing ActiveX object. The subroutine uses this constant to gracefully terminate the script and delete the created user account if you didn't copy and register AcctCrt.dll before running the script. The IADs interface's PutEx method uses the ADS_PROPERTY_APPEND constant to add entries to the multivalued otherMailBox attribute.
Next, CreateMailbox() uses Dim statements to declare its local variables, then initializes two of them: strEx55SrvrName and strMailBoxPath. As Listing 4 shows, you must customize these variables' values. You must change the value of strEx55SrvrName to the NetBIOS name of the Exchange 5.5 server on which you want to create the mailbox. You must change the value of strMailBoxPath to the distinguished name (DN) or canonical pathname that points to the container in which you want to create the mailbox. If you're not sure of the canonical name, follow these steps:
- From the Start menu's Run dialog box, type the path to Microsoft Exchange Administrator (admin.exe) and follow the path with /r. For example, if Exchange Administrator is in the C:\exchsrvr\bin folder, typeM
c:\exchsrvr\bin\admin /rand press Enter.
- In the console tree, click the name of the container in which you want to create the mailbox.
- From the File menu, select Raw Properties.
- In the Raw Properties dialog box that appears, scroll down and click the Obj-Dist-Name attribute and look in the Attribute value box to the right for the value that you should specify for the strMailBoxPath variable.
If you aren't in the United States, you must also change the value specified for the strCountry variable to the appropriate value for your country. CreateMailbox() automatically initializes the remaining variables. To do so, it uses the command-line parameters that you supplied; the values you specified for the strEx55SrvrName, strMailBoxPath, and strCountry (if applicable) variables; and the sADsPath function that appears at the end of the CrUM55.vbs file. The sADsPath function uses the Exchange 5.5 directory rootDSE entry to obtain the Exchange server's organization name.
Following variable initialization, the CreateMailbox() subroutine creates the objAcctMgmt object by using the CreateObject function with the MSExchange.AcctMgmt class, which is a class in AcctCrt.dll. The subroutine uses the AcctMgmt class to obtain the user account's SID and to generate the SD for the mailbox. Because you must copy this DLL onto the client machine and register it, I added error-handling code to this section of the subroutine. If the subroutine can't create an instance of the class, the subroutine informs you of the error, deletes the user account that CreateNTDomainUser() or CreateADDomainUser() created, then terminates the script. Deleting the account is important because the script failed to create the corresponding mailbox. CreateMailbox() won't delete a user account it didn't create because, by this point in the script, CreateNTDomainUser() or CreateADDomainUser() has already verified that the user account you specified at the command line didn't previously exist. If the user account had existed, CreateNTDomainUser() or CreateADDomainUser() would have terminated the script before CreateMailbox() could run.
If all goes as planned, CreateMailbox() creates the objAcctMgmt object. Using the IAcctMgmt interface's GetSidFromName method, the subroutine obtains the user account's SID. Later, the script will assign the SID to the Assoc-NT-Account mailbox attribute, which associates a user account with a mailbox. The IAcctMgmt interface's GenerateSecDescriptor method creates an SD, which the script later assigns to the NT-Security-Descriptor attribute. This assignment grants the user account permission to use the mailbox.
The next step is to create the mailbox. The IADsContainer interface's Create method completes this task. CreateMailbox() first binds to the container in which to create the mailbox, then uses the Create method with the OrganizationalPerson class to create the mailbox object. The OrganizationalPerson class is defined in the Exchange 5.5 Schema.
To successfully create any mailbox, you must set two required attributes: mailPreferenceOption and sn. You can also set many other optional attributes. For example, in CrUM55.vbs, I set several attributes, including Deliv-Ext-Cont-Types. CrUM55.vbs includes comments that explain the purpose of the attributes I set. After creating the mailbox and assigning the mailbox attributes, CreateMailbox() calls the SetInfo method to save the mailbox to the Exchange 5.5 directory.
As I just mentioned, you can set many attributes when creating a mailbox. To add a mailbox attribute to CrUM55.vbs, you must know the attribute's lDAPDisplayName, its data type, and whether it's single-valued or multivalued. You can obtain this information by opening Exchange Administrator in raw mode and viewing the mailbox's raw properties, following the instructions I described previously. In the Raw Properties dialog box, you need to review the list of assigned attributes (called existing attributes in the UI) and their values. Note the name of each attribute that you want to assign, then find its lDAPDisplayName.
For demonstration purposes, let's walk through an example of how to add an attribute to CrUM55.vbs. Let's add the City attribute, which lets you store the name of the city in which the mailbox user lives. In this case, let's add Seattle. To obtain the needed information about the City attribute (i.e., lDAPDisplayName, data type, and value type) and add this attribute to the script, follow these steps:
- Double-click a mailbox in raw mode Exchange Administrator, and enter Seattle in the City field.
- Close the mailbox's Properties dialog box.
- From the File menu, click Raw Properties.
- Scroll through the list of attributes until you locate the City attribute. Verify that the value you entered in the mailbox's Properties page matches the value that appears in the Attribute value field. This test is a good way to make sure that you located the correct attribute.
- To the right of the attribute, find the Syntax label and note the data type. In this case, the City attribute is a Unicode string.
- Directly below the Syntax label, the Value(s) label shows how many values this attribute can hold. Notice that the City attribute holds one value, which means that it's a single-valued attribute.
- Close the mailbox's Raw Properties dialog box.
- From the View menu, select Raw Directory.
- In the console tree, click the Schema node; double-click the City attribute in the details pane.
- Click Yes when you see a message box about displaying only raw properties for the attribute.
- Scroll through the list until you locate Description. Click Description.
- The attribute's lDAPDisplayName appears in the Edit value and Attribute values boxes. In this case, the lDAPDisplayName of the City attribute is the letter l.
- Close Exchange Administrator, and open CrUM55.vbs in a text editor (e.g., Notepad).
- In the CreateMailbox() subroutine, find the line that assigns the value of the givenName attribute. After that line, add
objMB.Put "l", "Seattle"
This code uses the IADs interface's Put method to assign the City attribute because the attribute is single-valued. If you want to configure a multivalued attribute, you need to use the IADs interface's PutEx method to preserve any existing entries assigned to the attribute.
An Oldie but a Goodie
As requested, you now know how to programmatically create user accounts and Exchange 5.5 mailboxes. Although Exchange 5.5 is positioned as a legacy email system because Microsoft will retire it soon, many companies are finding Exchange 5.5 to be a perfectly acceptable email system. By adding a touch of automation, you can make the email system easier to administer.