I'm trying to write a script that sets user account information (e.g., a user's street, city, and zip code) in Active Directory (AD). However, I can't figure out what Active Directory Service Interfaces (ADSI) calls each property. How can I find out this information?
You aren't alone. Many ADSI coders ask the same question. There are multiple approaches to getting to this information. Before I explain some of these approaches, it's useful to understand the relationship between AD classes and the objects created from those classes in AD and the relationship between an AD object's attributes and how those attributes appear in snap-ins, such as the Microsoft Management Console (MMC) Active Directory Users and Computers snap-in.
An object class is the underlying template that AD uses to create (i.e., instantiate) objects. This definition is simplistic because AD doesn't create objects from all object classes. However, it's a sufficient definition for describing the relationship between an AD object and the class from which it's derived. Each class defines the attributes that can be associated with an object created from that class. Therefore, by reviewing the User class, you can identify all the attributes that can possibly be associated with user objects.
There are a number of ways to review the attributes associated with an object class. For example, you can use a UI tool such as the MMC ADSI Edit snap-in or the MMC Active Directory Schema snap-in, a command-line tool such as ldifde.exe, or a script. Because this is a scripting column, I'll detail a scripting approach.
The AttributesOfUserClass.vbs script in Listing 1 demonstrates how you can read information about all the mandatory and optional attributes that are part of the User class in AD. The code at callout A in Listing 1 first binds to the User class in the AD schema, then uses the IADs interface's Parent property to bind to the parent container of the User class. IADs is a core ADSI interface. Binding to this interface's Parent property is a necessary step for binding to the User class attributes later in the script.
Next, the script uses two For Each...Next statements and two ADSI schema management interfaces (i.e., IADsClass and IADsProperty) to display the attributes in the User class. The first For Each loop, which callout B shows, displays the mandatory attributes; the second For Each loop, which callout C shows, displays the optional attributes. For each mandatory and optional attribute, the script specifies the lDAPDisplayName, the data type, and whether the attribute is single-valued or multivalued. All this information is necessary for reading and writing attributes from a script, but the crucial piece of information you need is the attribute's lDAPDisplayName.
You can download AttributesOfUserClass.vbs from the Windows Scripting Solutions Web site. Go to http://www.windowsitpro.com/ windowsscripting, enter 44581 in the InstantDoc ID text box, then click the 44581.zip hotlink. (This file also contains another script, AttributeViewer.vbs, which I'll discuss shortly.) To run AttributesOfUserClass.vbs, you need to use Windows Script Host (WSH) 2.0 or later (WSH 5.6 is preferable) because the script relies on the WScript object's StdOut property to display output. You also need to run the script from CScript and not WScript because the StdOut property displays its output in a command-shell window. I recommend that you increase the command-shell window's buffer size. Otherwise, a User class with many attributes might overrun the buffer. Setting the buffer size to a height of 500 is usually adequate.
You now know the lDAPDisplayName of each attribute that can possibly be associated with a user object. Why do I write possibly be associated rather than is associated? Because when you create an AD object, the only attributes that the object contains are the mandatory attributes and any optional attributes to which you assign values. Attributes without values aren't associated with the object. It's only after an attribute is assigned a value that it becomes part of the object. This characteristic keeps AD objects as small as possible. It also makes matching the attribute's lDAPDisplayName to its user-friendly label in the Active Directory Users and Computers snap-in easier.
To map the attribute's lDAPDisplayName to its user-friendly label, you need to create a user account in the snap-in. Don't set any values other than those that the New Object Wizard requires you to create.
Next, extract the AttributeViewer.vbs script from the 44581.zip file if you haven't already done so. Open AttributeViewer.vbs in Notepad or your favorite script editor. Modify the strOU and strName variables, which Listing 2 shows, so that they point to the user account you just created. Save the file.
Run AttributeViewer.vbs from a command line using CScript (not WScript) and review the script's output. Next, return to the snap-in and specify a value in the City text box. After clicking Apply (which saves the changes) or OK (which saves the changes and closes the dialog box), return to the command prompt and run AttributeViewer.vbs again. In the new output, look for the value you entered in the snap-in's City text box. By finding this value, you'll see that the attribute with the lDAPDisplayName of c maps to the snap-in's user-friendly label, City. You can take this same approach to identify the lDAPDisplayNames of other attributes that you can configure through the snap-in.
This approach works well for most attributes, but it's not perfect. There are three drawbacks that I can think of:
- There isn't necessarily a one-to-one mapping of attributes to snap-in settings. For example, many options appearing on the snap-in's AD Users and Computers Account tab are actually stored in one attribute, specifically the userAccountControl attribute. This attribute is a bitmask, and you change bits in the attribute to configure several of the settings that appear on this tab.
- AD calculates some attributes, such as the canonicalName and msDS-KeyVersionNumber attributes. ADSI documentation calls this type of attribute operational or constructed. I didn't write the script to display any of these attributes. However, you can't directly set operational attributes' values, so this omission isn't a problem.
- The snap-in shows only a subset of all attributes that you can associate with a user account. If you review the output created by AttributesOfUserClass.vbs, you'll notice many more attributes than the snap-in shows.
As I mentioned in the second drawback, you don't set operational attributes, so the only real obstacles to work around are the first and third drawbacks. To work around the fact that there isn't necessarily a one-to-one mapping of attributes to snap-in settings, you can search for attribute information on the Web. I recommend you review the Active Directory Platform Software Development Kit (SDK) at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/users_in_active_directory.asp and the ADSI content in the Microsoft TechNet Script Center at http://www.microsoft.com/technet/scriptcenter/default.mspx. When I worked closely with the Script Center team, I wrote a user-attributemapping diagram in Microsoft Visio. By the time this article is published, this diagram should be posted on Script Center. You'll also find scripts that demonstrate how to write every writeable attribute in the snap-in.
To work around the fact that the snap-in shows only a subset of all user account attributes, you should run AttributesOfUserClass.vbs to see the lDAPDisplayNames and other important information about the User class attributes. Then, use the documentation I just mentioned to learn more about those attributes.
If you take the approach I outlined here, you should be well on your way to identifying user object attributes and how to work with them in a script. If you still reach a dead-end, please email me at firstname.lastname@example.org and I'll try to help.