How to search for users in Active Directory with C#

Last time I wrote about how you can reach the Active Directory search dialog in Windows 7. Today I’ll show you how to search comfortable for users in the Active Directory by using C#. The emphasis is on comfort, because there are quite a few articles on the subject in general, on the internet.

However, most of the shown methods/solutions are build exclusively around System.DirectoryServices.ActiveDirectory and the DirectorySearcher. But ever since .NET 3.5 it is also possible to search in the Active Directory much easier.

But let us come to the point. In the following example, I mostly use methods from the System.DirectoryServices.AccountManagement namespace. And here’s how:

//Create a shortcut to the appropriate Windows domain
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain,
                                                      "myDomain");

//Create a "user object" in the context
UserPrincipal user = new UserPrincipal(domainContext);

//Specify the search parameters
user.Name = "he*";

//Create the searcher
//pass (our) user object
PrincipalSearcher pS = new PrincipalSearcher();
pS.QueryFilter = user;

//Perform the search
PrincipalSearchResult<Principal> results = pS.FindAll();

//If necessary, request more details
Principal pc = results.ToList()[0];
DirectoryEntry de = (DirectoryEntry)pc.GetUnderlyingObject();

//Output first result of the test
MessageBox.Show(de.Properties["mail"].Value.ToString());

After you’ve now seen the source code, there are of course a few more notes to it. In line 9, I set the Name property of user. The * is seen as a wildcard. It would be in line 17 all Active Directory user entries returned whose name starts with “he”.

Basically, it has to be said, that you can search for many other properties, instead of the Name property set, which then act as filters. Also, the combining of a plurality of properties is possible.

Also, I would like to mention, that from line 21 on, all code is optional. In most cases, the principal objects contain all the data you need to know. However, these principal objects do not contain all properties that can be set as in the Active Directory.

Should you are searching an actual shaft that does not grasp the principal object, so you have to fall back on the old way method, raised at the beginning of this article.

5 Comments

  1. Pavelsays:

    Thanks, it helped me.

  2. José Juan Glezsays:

    Gracias, excelente publicación.

  3. lwangsays:

    Hi,

    I’m new in writing code to access AD. Recetnly, my company setup a new AD server with the structue similiar to follows:

    DC=UAT,DC=COM
    OU=ORG
    OU=Servers
    OU=Services Accounts
    OU=Users and Groups
    OU=System
    OU=Groups
    CN=Admins
    OU=Users

    OU=Test
    OU=Groups
    OU=Users
    CN=test01
    CN=test02

    OU=XXX
    OU=Groups
    OU=Users
    CN=XXX01
    CN=XXX02

    I need to write an application to search a user and then change the password and also implement other functions.
    But my first task to seach an user to change the password is failed.
    I wrote the following sample codes to search for the user:

    using System;
    using System.IO;
    using System.DirectoryServices;
    using System.Configuration;

    try
    {
    DirectoryEntry userEntry = new DirectoryEntry(“LDAP://SERVERIP/OU=Users and Groups,OU=ORG,DC=UAT,DC=COM”, null, null, AuthenticationTypes.ServerBind | AuthenticationTypes.FastBind);
    DirectorySearcher search = new DirectorySearcher(userEntry);

    search.SearchScope = SearchScope.Subtree;

    search.ReferralChasing = ReferralChasingOption.All;

    // Search user test02
    search.Filter = “(&(objectClass=user)(objectCategory=Person)(sAMAccountName=test02))”;

    SearchResult result = search.FindOne(); // Failed at this line, throw exception

    if (result == null)
    Console.WriteLine(“There is no results to display”);
    else
    Console.WriteLine(“Found result “);

    }
    catch (Exception ex)
    {
    Console.WriteLine(“Error: ” + ex.Message);
    Console.WriteLine(“Trece: ” + ex.StackTrace);
    }

    Error: Configuration system failed to initialize
    Trece: at System.Configuration.ClientConfigurationSystem.EnsureInit(String configKey)
    at System.Configuration.ClientConfigurationSystem.PrepareClientConfigSystem(String sectionName)
    at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
    at System.Configuration.ConfigurationManager.GetSection(String sectionName)
    at System.Configuration.PrivilegedConfigurationManager.GetSection(String sectionName)
    at System.DirectoryServices.SearchResultCollection.ResultsEnumerator..ctor(SearchResultCollection results, String parentUserName, String parentPassword, AuthenticationTypes parentAuthenticationType)
    at System.DirectoryServices.SearchResultCollection.GetEnumerator()
    at System.DirectoryServices.DirectorySearcher.FindOne()

    Could you help and advise what I did wrong?

    Thank you very much!

    Lwang

  4. A.G.says:

    It’s important to note that you should wrap PrincipalContext, UserPrincipal, PrincipalSearcher and PrincipalSearchResult in using statements or to dispose of them when you’re done. All of these use unmanaged code on the backend and you’ll end up with a memory leak if you don’t properly deal with them.

Leave a comment

Please be polite. We appreciate that. Your email address will not be published and required fields are marked