August 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Accessing Directory Services

  • August 8, 2003
  • By Mark Strawmyer
  • Send Email »
  • More Articles »

Searching the Directory

The DirectorySearcher object has two methods for searching a directory. There is the FindOne method that retrieves the first entry from the directory. There is the FindAll method that retrieves all directory entries that match the search string. By default, the results will load all of the properties for the directory entries that meet the filter criteria. For efficiency, you can restrict the properties loaded by using the PropertiesToLoad collection on the DirectorySearcher.

Active Directory Searching Sample using FindOne

The following sample code uses the FindOne method of the DirectorySearcher class to find the same user we authenticated a moment ago. We will limit the properties that are retrieved during the search.

DirectoryEntry entry = new          DirectoryEntry("LDAP://dev.codeguru.com");try{  DirectorySearcher search = new DirectorySearcher(entry);  search.Filter = "(SAMAccountName=administrator)";  search.PropertiesToLoad.Add("Name");  search.PropertiesToLoad.Add("displayName");  SearchResult result = search.FindOne();  if( result != null )  {    Console.WriteLine("User found");    foreach( string key in result.Properties.PropertyNames )    {      // Each property contains a collection of its own      // that may contain multiple values      foreach( Object propValue in  result.Properties[key] )      {        Console.WriteLine(key + " = " + propValue);      }    }  }  else  {    Console.WriteLine("User not found");  }}catch( Exception ex ){  throw new Exception("User not authenticated: " + ex.Message);}Console.ReadLine();

Active Directory Searching Sample using FindAll

The following sample uses the FindAll method of the DirectorySearcher class to retrieve and information on all of the users found in the directory. It then will iterate through the properties for each of the entries found and write them to the console. This time, we will not restrict the properties and will display them all.

DirectoryEntry entry = new                       DirectoryEntry("LDAP://dev.codeguru.com");DirectorySearcher search = new DirectorySearcher(entry);search.Filter = "(objectClass=user)";foreach(SearchResult result in search.FindAll()){DirectoryEntry dirEntry = result.GetDirectoryEntry();foreach(string key in dirEntry.Properties.PropertyNames) {    // Each property contains a collection of its own    // that may contain multiple values    foreach( object propVal in dirEntry.Properties[key] )    {      Console.WriteLine(key + " = " + propVal);    }  }  Console.WriteLine("---------------");}Console.ReadLine();

Adding a User

Adding a user to the directory is not much more complicated than the searching we were performing before. When binding to the directory, we need to provide user credentials that have the authority to modify a user; otherwise, the update will fail. In addition, make sure that you have all of the attributes required by your AD instance; otherwise, you will get a message similar to "The server is unwilling to process the request" and not be able to add a user. Typically, only the cn (full name) and sAMAccountName are required.

There is an Invoke method that you can use to access properties through native ADSI. All user properties accessible through the DirectoryEntry class can also be set through the Invoke method. However, not all user properties are accessible through the DirectoryEntry class. It is a requirement that the user password is set using the Invoke method because it is not exposed through the DirectoryEntry class. The user must exist in the AD before the password can be set.

If you have more than one Domain Controller, please allow time for the changes to be replicated to all Domain Controllers before you will see the new user in the Active Directory Users and Computers MMC snap-in.

Adding a User Sample Code

try{string path = "LDAP://CN=Users,DC=dev,DC=codeguru,DC=com";DirectoryEntry entry = new DirectoryEntry(path, "dev.codeguru.com\\administrator", "password");// Create the user and set propertiesDirectoryEntry user = entry.Children.Add("cn=Test User", "user");user.Properties["sAMAccountName"].Add("testuser");user.Properties["sn"].Add("User");user.Properties["givenName"].Add("Test");user.Properties["description"].Add("Test account added with code.");user.CommitChanges();// User has to be saved prior to this stepuser.Invoke("SetPassword", new object[] {"mypassword1"} );// Create a normal account and enable it - ADS_UF_NORMAL_ACCOUNTuser.Properties["userAccountControl"].Value = 0x200; user.CommitChanges();}catch( Exception exception ){Console.WriteLine( exception.Message );}

Modifying a User

Modifying the properties of a user requires us to find an existing user, retrieve the directory entry for it, then make and commit the desired changes. When binding to the directory, we need to provide user credentials that have the authority to modify a user; otherwise, the update will fail.

If you have more than one Domain Controller, please allow time for the changes to be replicated to all Domain Controllers before you will see the new user in the Active Directory Users and Computers MMC snap-in.

Modifying a User Sample Code

try{  string path = "LDAP://CN=Users,DC=dev,DC=codeguru,DC=com";  DirectoryEntry entry = new DirectoryEntry(path,   "dev.codeguru.com\\administrator", "password");  DirectorySearcher search = new DirectorySearcher(entry);  search.Filter = "(SAMAccountName=testuser)";  SearchResult result = search.FindOne();  DirectoryEntry user = result.GetDirectoryEntry();  user.Properties["description"].Value = "New description for user";  user.CommitChanges();}catch( Exception exception ){  Console.WriteLine( exception.Message );}

Summary

You have now seen ways in which the DirectoryEntry and DirectorySearcher classes of the System.DirectoryServices namespace can be used to interact with directory services. We focused on the LDAP interface exposed by the Active Directory, but the examples can be made to work for different providers by changing the binding path.

Future Columns

The topic of the next column is yet to be determined. If you have something in particular that you would like to see explained here, you can reach me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer, MCSD, MCSE (NT4/W2K), MCDBA is a Senior Architect of .NET applications for large- and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design, and development of Microsoft-based solutions. You can reach Mark at mstrawmyer@crowechizek.com.

# # #





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel