Much of the information we have learned about reading attribute data we can also apply to writing. However, there are a few basic rules to understand right off the bat.
The rules may seem obvious by now, but they come up as issues surprisingly often in practice.
DirectorySearcher makes it easy to switch to "edit mode" by using the SearchResult.GetDirectoryEntry method:
//given a SearchResult result that you wish to modify using (DirectoryEntry entry = result.GetDirectoryEntry()) { //now, perform modifications on the DirectoryEntry }
To switch from the GC provider to LDAP, create a new DirectoryEntry object with the LDAP provider.
Note: Switching from GC to LDAP May Require Changing Physical Servers Too
In order to switch from GC to LDAP, we need a domain controller in the domain where the object "lives." The global catalog server we were querying might be from a different domain, so this is not always straightforward.
Setting Initial Values
If an attribute has no value, we can use one of the following two approaches to set an initial value.
For example, to set the description attribute on a DirectoryEntry called entry, we might do this:
entry.Properties["description"].Add("a new description"); //or entry.Properties["description"].Value = "a new description"; entry.CommitChanges();
We recommend avoiding using the array index accessor for setting values in general and especially for setting initial values, as it does not behave exactly the same way against all versions of the .NET Framework and ADSI, and it might cause unexpected problems with routine upgrades and service packs. For example:
//don't do this; it might not work as expected entry.Properties["description"][0] = "a new description";
If we wish to set multiple values initially, we can use the Value property again, use the AddRange method, or call Add repeatedly:
//Do this entry.Properties["otherTelephone"].Value = new string[] {"222-222-2222", "333-333-3333"}; //or this entry.Properties["otherTelephone"].AddRange(new string[] {"222-222-2222", "333-333-3333"}); //or this entry.Properties["otherTelephone"].Add("222-222-2222"); entry.Properties["otherTelephone"].Add("333-333-3333"}); entry.CommitChanges();
It may seem obvious, but keep in mind that using the Value property overwrites the entire attribute, which is why it is appropriate for setting initial values and not for simply adding to the existing values.
Clearing an Attribute
If an attribute is set and we wish to clear it, we can simply call the Clear method:
entry.Properties["description"].Clear(); entry.CommitChanges();
Alternately, the Value property can be used to clear an attribute value by setting it to null (Nothing in Visual Basic), but the Clear method seems to convey our intentions better.
Replacing an Existing Attribute Value
If the attribute value is already populated and we want to replace it completely with a different value, the easiest way to do this is with the Value property. Using our first example again:
entry.Properties["description"].Value = "a second description"; entry.CommitChanges();
When we set the Value property, it has the benefit of completely replacing the existing value with whatever we set in a single LDAP modification operation.
Adding and Removing Values from Multivalued Attributes
If the attribute has multiple values and we wish to modify only parts of it, we should use the Add, AddRange, and Remove methods. This is a very common thing to do when we're modifying membership on a group and we want to add or remove individual members:
//given a DirectoryEntry entry bound to a group: entry.Properties["member"].Add( "CN=someuser,CN=Users,DC=domain,DC=com"); entry.Properties["member"].Remove( "CN=someotheruser,CN=Users,DC=domain,DC=com"); entry.CommitChanges();
If we are careful to check the values in the attribute before modification using the Contains method, we can avoid errors caused by adding duplicate entries or removing nonexistent entries.
Attribute Modification Summary
As we have shown, the Value property is extremely useful for attribute modifications. We can use it in just about any situation to set single and multiple values. It is also very efficient, as it uses a single PutEx call under the hood that results in a single LDAP modification operation. Additionally, the Add, AddRange, Remove, and Clear methods are very helpful and efficient under the hood, for similar reasons.
We generally recommend avoiding using array indexers on PropertyValueCollection for modifications. At the very least, changing a value using the array index will result in a remove and an add operation under the hood. In some situations, this simply will not work at all. The upcoming sidebar, Caution with Attribute Writing, provides more details about this problem. The other point here is that LDAP does not guarantee that multivalued attributes are stored or read in any specific order, so it is best not to think about them in that way, either.
Part I: Fundamentals
Introduction to LDAP and Active Directory
Introduction to .NET Directory Services Programming
Binding and CRUD Operations with DirectoryEntry
Searching with the DirectorySearcher
Advanced LDAP Searches
Reading and Writing LDAP Attributes
Active Directory and ADAM Schema
Security in Directory Services Programming
Introduction to the ActiveDirectory Namespace
Part II: Practical Applications
User Management
Group Management
Authentication
Part III: Appendixes
Appendix A. Three Approaches to COM Interop with ADSI
Appendix B. LDAP Tools for Programmers
Appendix C. Troubleshooting and Help
Index