In "Querying and Updating AD, Part 1," February 2003,, InstantDoc ID 27569, I described how to install and use the Net::LDAP modules to query Active Directory (AD) according to search criteria and retrieve attributes of matching objects. In Part 2, I describe the various Net::LDAP methods available to add, delete, modify, rename, and move objects in AD.

Adding Objects
Using Net::LDAP to add objects is straightforward. For example, Listing 1 contains code that adds the John Doe contact object. Callout A in Listing 1 shows the parameters that you need to modify to get the code to work in your environment. For the $dc variable, you specify the domain controller (DC) against which to perform the add operation. You set the $user and $passwd variables to the username and password, respectively, with which you want to connect to the specified DC. The $parent_dn variable needs to contain the distinguished name (DN) of the parent container in which you want to put the John Doe contact object. The code after callout A in Listing 1 connects to the specified DC and uses the specified credentials to bind with it.

The code at callout B in Listing 1 calls the add() method. The first parameter is the DN of the new object you're adding. The second parameter, attrs, points to an array reference that contains the attributes that you're assigning to the new object. You must include any mandatory parameters (e.g., objectClass) that don't have a default value, or the add method will fail. For example, if you want to add a user object, you would at a minimum have to specify user for the objectClass parameter and a person's username for the sAMAccountName parameter.

The add() method returns a Net::LDAP::Message object, which has a code() method that lets you determine whether an error occurred. When the Net::LDAP::Message object's code() method returns a value of 0, you've successfully added the contact object. If the code() method returns any other value, an error occurred and the error() method displays an error message.

Listing 1 adds only one object to AD. You can extend the code to add thousands of objects if necessary. You can even use the Perl Database Interface (DBI) modules to query a database and populate AD with the retrieved information. You can find the DBI modules on the Comprehensive Perl Archive Network (CPAN) Web site (

Deleting Objects
Using Net::LDAP to delete objects is even easier than adding them. All you need to do is pass the DN of the object you want to delete to the Net::LDAP object's delete() method. For example, Listing 2 contains code that deletes all the contact objects in the ou=Contacts,dc=mycorp,dc=com organizational unit (OU).

The code at callout A in Listing 2 shows the parameters you need to customize. The code at callout B in Listing 2 searches for the objects to delete. In Part 1, I discussed how to use the search() method, including how to set each parameter. In this case, you set the base parameter to the DN of the container that holds the objects you want to delete. Because you want to delete all objects in that container but not the container itself, you set the scope parameter to 'one', which omits the base DN from the search by searching for objects one level down from the base DN. The filter parameter contains the search filter that looks for contacts objects. The attrs parameter contains an array reference to a single attribute, 'cn'. The search() method returns the matching objects as an array of Net::LDAP::Entry objects.

The code at callout C in Listing 2 uses the Net::LDAP::Entry object's dn() method to retrieve the DN for each matching object so that the delete() method can delete the object. The code() method checks the result to see whether an error occurred and prints an appropriate message.

In some cases, instead of deleting each object in the OU, you might want to delete the parent OU and all its children in one operation. Unfortunately, you can't perform this type of delete operation with a simple delete command. You must use an extension to Lightweight Directory Access Protocol (LDAP) called a control to inform the server to delete a particular container and all its children. Using the Net::LDAP controls is beyond the scope of this article and will be the topic of a future article. If you want to learn about controls in the meantime, you can read the online documentation on the perl-ldap Web site (

Modifying Objects
Net::LDAP provides quite a bit of flexibility when you need to modify an object's attributes. You can add, delete, or replace values on an individual basis or perform all your value modifications in one call.

Like the add() and delete() methods, the modify() method's first parameter is the DN of the object you want to modify. The second parameter is a named option that specifies the type of modification to perform. The modify() method has several options from which to choose:

The add option. You use the add option to add or set a value for an attribute that previously didn't have a value. You also use the add option to add a new value to a multivalued attribute. The add option expects a reference to a hash. The hash key contains the attribute's name; the hash value contains the attribute's value. For example, to add the mail attribute and give it the value, you use code such as

                              $ldap->modify($dn, add =>                                 \{ mail => '' \} );

The delete option. You use the delete option to remove specific values associated with an attribute or all values associated with an attribute. The delete option expects either a reference to a hash containing specific key-value pairs to delete (similar to the add option) or a reference to an array of attributes for which you want to delete all values. For example, to delete all the values associated with the mail and displayname attributes, you use code such as

                              $ldap->modify($dn, delete =>                                 \[ 'mail', 'displayname' \] );

The replace option. You use the replace option to change an attribute's existing value with the specified value. The replace option uses the same parameters as the add option. So, for example, if you entered the wrong email address when you added the mail attribute, you can change it to the correct email address with code such as

                              $ldap->modify($dn, replace =>                                 \{ mail => ''\});

The changes option. You use the changes option to group a set of add, delete, or replace options together in one call. The changes option expects a reference to an array that contains pairs of option names and values. For example, to delete the value associated with the mail attribute and to add the givenname and sn attributes, whose values are John and Doe, respectively, you use code such as

                              $ldap->modify($dn,                                 changes => \[                                 add => \[ givenname => "John" \],                                 add => \[ sn => "Doe"\],                                 delete => \[ 'mail' \] \] );

Web Listing 1 (, InstantDoc ID 37717) uses the options I just described to modify a user object. Like the add() and delete() methods, the modify() method returns a Net::LDAP::Message object, whose code() method you can use to determine whether an error occurred.

Renaming and Moving Objects
To have complete control over manipulating objects in AD, you need the ability to rename and move objects. Luckily, Net::LDAP provides the moddn() method, which lets you perform both functions. As with the other three methods I've described so far, the moddn() method's first parameter is the DN of the object you want to rename or move. The second parameter can consist of one or more of the following options:

The newrdn and deleteoldrdn options. In AD, you identify objects by their DN, which includes a relative distinguished name (RDN). The RDN specifies the object's name. Take, for example, an object with a DN of cn=jdoe,cn=users,dc=mycorp,dc=com. In this case, the RDN is jdoe. You use the newrdn option to assign a new RDN to an object. The newrdn value must include not only the object's name (e.g., jsmith) but also the identifier (e.g., cn=).

Listing 3 contains code that renames the user object cn=jdoe,cn=users,dc=mycorp,dc=com to cn=jsmith,cn=users,dc=mycorp,dc=com. Callout A in Listing 3 highlights the code that includes the newrdn option. This code also includes the deleteoldrdn option. By setting the deleteoldrdn option to 1 (i.e., true), you're deleting the object that has the old RDN. If you don't include the deleteoldrdn option or you set the option to 0 (i.e., false), the old object being renamed or moved will still remain. In nearly all situations, you'll want to set deleteoldrdn to 1.

The newsuperior option. You use the newsuperior option to move an object to a different parent container. You set this option to the DN of the new parent container. For example, Listing 4 contains code that moves all user objects whose department attribute is equal to Sales to the Sales OU. As callout A in Listing 4 shows, the $old_parent variable specifies the parent container in which to search for the objects and $new_parent specifies the parent container to which you want to move the objects. Callout B in Listing 4 highlights the code that searches $old_parent for all user objects with a department attribute equal to Sales. The code at callout C in Listing 4 uses a foreach statement to move each of those objects to $new_parent.

You Have Everything You Need
In this two-part article, I covered how to use the Net::LDAP modules to manipulate objects in AD. With these Perl modules, you can perform every object manipulation function you need to manage the data in AD.