Getting the most from your directory data
What if I told you that Windows 2000 includes a utility that can easily import and export Active Directory (AD) records for reporting and migration purposes? What if this tool could also automatically add, modify, or delete AD objects? The Lightweight Directory Access Protocol (LDAP) Data Interchange Format (LDIF) Directory Exchange tool, better known as Ldifde, lets you export data from AD, object by object (e.g., user, group), attribute by attribute (e.g., name, company, department) to a file in LDIF format. LDIF is an Internet standard file format based on Internet Engineering Task Force (IETF) Request for Comments (RFC) 2849 for importing and exporting data from LDAP directories such as AD. After you export the data, you can use the LDIF file to import the same objects into a different LDAP directory. Or, you can use Ldifde's output as raw data for a report or as a starting point for creating an LDIF file of changes to reimport into AD.
Let's look at some sample LDIF files so that you can learn how to use Ldifde and its sister utility, Csvde, to get the most out of your AD data. Csvde is the comma-separated value (CSV) version of Ldifde that lets you import data into database applications such as Microsoft Access or spreadsheet applications such as Microsoft Excel that support CSV-formatted files. Ldifde and Csvde come with Win2K Server, but you can copy these utilities from the Win2K Server installation CD-ROM and execute them on Windows XP and Win2K workstations.
Exporting Data from AD
Before you begin using Ldifde, you need to understand the LDIF file structure. Figure 1 displays an organizational unit (OU) called Monterey that contains four users and a group. To export this AD information, I need to execute the command
ldifde -f monterey.ldif -d "ou=Monterey,DC=ad,dc=local"
to create the Monterey.ldif file, as Web Figure 1 shows. (You can either invoke Ldifde from within a script or run the executable from the command prompt.) The -f parameter lets you specify the name of the LDIF file (e.g., monterey.ldif). The -d parameter lets you specify the root distinguished name (DN) of the domain or OU to export from (e.g., the Monterey OU of the ad.local domain), then outputs all attributes for all objects from that point down, including the OU. Be aware that some attributes might be missing (e.g., phone numbers for some users) if these attributes are optional and don't exist until they're explicitly set on each object.
As Web Figure 1 shows, each record in an LDIF file begins with a DN line denoted by dn:. In an LDAP directory, an object's DN uniquely identifies the object for the entire directory. The second line in Web Figure 1 begins with changetype:, which specifies the type of change that Ldifde should execute on the object that the DN identified. All the records in Monterey.ldif have a changetype of add. Whenever you export records, Ldifde formats the file in such a way that you can use the file to import those records into another LDAP directory. After specifying the changetype, Ldifde lists each object attribute in the following format:
You can determine the class of each object by noting the objectClass attribute. Monterey.ldif lists the OU followed by three users, a group, and the final user.
If you need to export AD data (e.g., a list of usernames) for reporting purposes, you must limit Ldifde's output by selection criteria (e.g., class) and specify what object attributes you want to export: You can use the -r and -l parameters to accomplish both objectives. The -r parameter lets you specify a search filter in LDAP syntax in which you specify one or more attributes and their desired values. For example, type
ldifde -r "(objectClass=User)"
to export just the user records. Alternatively, type
ldifde -r "(&(objectClass=user)(sn=Smith))"
to export all users whose surname is Smith.
You use the -l parameter followed by a comma-delimited list of attributes to specify which attributes Ldifde outputs for each object. For example, type
ldifde -l "displayName, physicalDeliveryOfficeName"
to output the display name and office for each user, as Figure 2 shows.
If you're new to LDAP queries, see the Web-exclusive sidebar "LDAP Filters" (http://www.winnetmag.com, InstantDoc ID 38949) for more information about how to structure your queries. If you're unsure of the exact name of an attribute or class name that you want to filter, you can use the Microsoft Management Console (MMC) Active Directory Schema snap-in or export an OU that contains the object you need to work with, then examine the LDIF file. If the attribute in question doesn't appear in that object's record, simply edit the object in AD, set a value for the attribute, and export the OU again. For example, when you edit a user object in the MMC Active Directory Users and Computers snap-in, you'll see an Office field on the user's General tab, as Figure 3 shows. To determine the LDAP attribute name for that field in AD, you can enter a value for the office attribute, then use Ldifde to export the object. The LDAP attribute name will appear in the LDIF file after the physicalDeliveryOfficeName attribute name.
Although the LDIF file format doesn't lend itself to importing AD data into a database for query or reporting purposes, Microsoft provides another utility, Csvde, that accepts the same parameters as Ldifde but outputs data in CSV format. For example, executing the command
csvde -f monterey.LDIF -d "ou=Monterey,DC=ad,dc=local" -l "displayName,physicalDeliveryOffice Name" -r "(objectClass=User)"
produces the same data as Ldifde, but each record now comprises one line of comma-delimited values, as Figure 4 shows. Note that the first line of Csvde-generated files lists the attribute names, which Access and Excel will correctly interpret as column headings.
Working with Text and Nontext Data Types
If you use Ldifde simply to export and import data between LDAP directories, you won't encounter any data-type problems. However, if you use Ldifde or Csvde to export data for reporting purposes or you want to build your own LDIF files for automated changes to AD, you might run into problems with certain attributes. For reporting or automating changes to AD, Ldifde and Csvde work best with text attributes, as opposed to nontext data types such as date and binary. You might be surprised to discover that one attribute in AD can comprise several fields in the Active Directory Users and Computers snap-in. For example, one integer attribute called userAccountControl contains several account options, as Figure 5 shows. Different bits of the userAccountControl integer correspond to check boxes in account options. With no account options set, the decimal value for userAccountControl is 512; the decimal value for a disabled account and no other account options set is 514. For details about interpreting and manipulating userAccountControl, see the Microsoft article "How to Use the UserAccountControl Flags to Manipulate User Account Properties" (http://support.microsoft.com/?kbid=305144). Dates are also problematic because AD represents them as the number of seconds elapsed since 00:00:00, January 1, 1970, in the format of yyyymmddhhmmss.mmmmmm. Also, remember that some AD attributes are multivalued, including group membership lists and phone numbers. In LDIF files, multivalue attributes produce a separate line for each attribute value. When Csvde outputs a multivalue attribute, the utility delimits each value by a semicolon, then surrounds all the values with a set of quotation marks so that the program reading the CSV-formatted file will interpret the list of values as one attribute.
Importing Changes to AD
To use Ldifde to import data into AD, you simply use the -i parameter to specify import mode and use the -f parameter to specify the LDIF file. Let's look at how to use Ldifde to write LDIF files that create, delete, and modify AD objects.
Creating objects. The easiest way to compose an LDIF file that creates a new object is to export an already existing object. Remember, whenever you use Ldifde to export an object, Ldifde outputs the object with a changetype of add. If you then import the Ldifde file to the same directory, Ldifde will try to create a duplicate of the object you just exported. Therefore, you can export a sample object (e.g., an existing user object), then edit the LDIF file so that it creates a new object. When you use this method, you must remove some attribute definitions from the original export file because only the directory service can set some attributes. For example, if you try to set the whenChanged attribute on a user object, Ldifde will display the message Add error on line 1: Constraint Violation. The server side error is "The attribute cannot be modified because it is owned by the system." Although Ldifde exports all attributes, including read-only attributes, by default, the utility can also correctly migrate data from one directory to another. To do this, you simply include the -k parameter when you import the LDIF file, which tells Ldifde to ignore constraint violations and object already exists errors. To improve performance for large imports, you can specify the -y parameter, which causes Ldifde to use lazy commits.
Deleting objects. Creating an LDIF file that deletes one or more objects is a relatively easy process. Simply enter the DN line, then specify delete on the changetype line. For example,
dn: cn=Robert Hall, ou=Marketing, dc=acme, dc=com changetype: delete
instructs Ldifde to delete Robert Hall's user account from the acme.com domain.
Modifying objects. Without a doubt, using LDIF files to modify AD objects is the most challenging of the three types of imports Ldifde can perform. You must begin the LDIF file by listing the DN, then specifying modify on the changetype line. Next, you must specify the type of operation you want Ldifde to perform, followed by the name of the attribute you want to change. For example,
tells Ldifde that the line or lines that follow will specify a new value or new values for the displayName attribute of the object you identified with a DN. (I specified the optional plural lines and values in the previous statement for those cases in which you're modifying multivalue attributes and you need to specify several values for the same attribute.)
The next line of the LDIF file needs to specify the attribute value. For example,
specifies the surname Johnson. If you have additional values to set for the same attribute, simply list them on additional lines in the same format. After you specify the final value line for that attribute, add a line with a single dash on it. For example,
dn: CN=Joe Stokes,OU=Monterey, DC=ad,DC=local changetype: modify replace: sn sn: Johnson -
changes Joe's surname to Johnson.
In addition to using the replace operation, you can specify add and delete operations. You use the add operation when the attribute has never been set for the object of interest. In the case of multivalue attributes, when you use add, Ldifde will add values you specify to the existing values for that attribute. For example,
dn: CN=Managers,OU=Monterey, DC=ad,DC=local changetype: modify add: member member: CN=Joe Stokes,OU=Monterey,DC=ad,DC=local member: CN=James White,OU=Monterey,DC=ad,DC=local member: CN=Lamar McCluney,OU=Monterey,DC=ad,DC=local -
adds Joe, James, and Lamar to the Managers group. By simply changing add: member to replace: member, Ldifde will delete any users who are already members of the Managers group before adding Joe, James, and Lamar. If you use the add operation on single-value attributes such as sn (surname) where a value already exists, Ldifde might report the message Multiple values were specified for an attribute that can have only one value. You use the delete operation to delete all attribute values as though the attribute had never been set for that object. For example,
dn: CN=Joe Stokes,OU=Monterey, DC=ad,DC=local changetype: modify delete: sn -
deletes Joe's current surname. You can also use the delete operation to delete a specific value from a multivalue attribute. For example,
dn: CN=Managers,OU=Monterey, DC=ad,DC=local changetype: modify delete: member member: CN=Joe Stokes,OU=Monterey,DC=ad,DC=local -
deletes Joe from the Managers group without affecting any other members. This modification is similar to setting a field in a Microsoft SQL Server database row to null. To add, replace, or delete multiple attributes for the same object, simply use a single dash to separate the lines for each attribute. For example,
dn: cn=John Smith, ou=Accounting, dc=acme, dc=com changetype: modify add: postaladdress postaladdress: 100 Main St $ Greenville, CA $ 29605 - replace: telephonenumber telephonenumber: +1 864 555 1212 telephonenumber: +1 864 230 1212 - delete: facsimiletelephonenumber -
adds John's postal address, replaces his telephone number with two numbers, and deletes his fax number.
Using Ldifde and Csvde
Now that you understand the concepts behind the LDIF file structure, you can begin to put Ldifde and Csvde to work. For example, perhaps you need to create a new phone directory that includes the name, office phone, mobile and pager numbers, department, and job title of every employee in your organization. To produce a CSV-formatted file, run
csvde -f users.txt -d "DC=acme,DC=com" -r "(objectClass=user)" -l "name,department,title,telephoneNumber, mobile,pager"
then import that file, users.txt, into an Access database to print it as a report or display it on an intranet Web page.
What if you need to obtain specific information about your employees? Many shops are faced with developing part, if not all, of their identity management applications inhouse. Identity management encompasses the life cycle of an employee's user accounts, password resets, and access-level changes, from hiring through job changes and finally to termination. For example, imagine that you need to extract all user accounts for the Research and Development division. Simply run
csvde -f users.LDIF -d "DC=acme,DC=com" -r "(&(objectClass=user) (division=Research and Development))" -l "SAMAccountName,employeeID,telephone Number,department"
to obtain the user logon name, employee ID, telephone, and department for all employees within that division.
Perhaps your identity management application needs to be able to disable user accounts when closing an employee's HR record. To accomplish this, program your application to create an LDIF file structured as
changetype: modify replace: userAccountControl userAccountControl: 514 -
where distinguished name> is the employee's DN. Then, program the application to run
to reimport the data into AD. If you need to delete a user from a group, create an LDIF such as
changetype: modify delete: member member: -
where group> is the group's DN and user> is the DN for the user you want to remove from the group.
Ldifde and Csvde Options
Ldifde has a few additional options for fine-tuning how it runs. By default, Ldifde and Csvde use your user credentials to access AD. However, you can use the -b username> domain password> parameter to specify the credentials you want Ldifde and Csvde to use. If you don't want to include the password on the command line or in a script, you can substitute an asterisk (*) for domain password>, in which case Ldifde will prompt you to enter the password without displaying it as you type. If you want Ldifde to execute the import or export against a specific server, simply use the -s parameter to specify the server name. Likewise, if you want Ldifde to list the DN of each object as it's processed, use the -v parameter.
Ldifde and Csvde are great tools for getting information in and out of AD or other LDAP directories without writing any Active Directory Service Interfaces (ADSI) code. Use Ldifde when you need to transfer objects from one directory to another or when you need to modify information within AD, and use Csvde when you need to extract data for use with other applications. For more information about LDIF, see RFC 2849 at http://www.faqs.org/rfcs/rfc2849.html. To learn more about Ldifde, see the Microsoft article "Using LDIFDE to Import and Export Directory Objects to Active Directory" (http://support.microsoft.com/?kbid=237677).