views:

2869

answers:

5

Can anybody show me how to query user information from the active directory? I have code that works, but it's really slow. I'm using C#. This is the code i currently use:

    static void Main(string[] args)
    {
        SearchResultCollection sResults = null;

        try
        {

            //modify this line to include your domain name
            string path = "LDAP://EXTECH";
            //init a directory entry
            DirectoryEntry dEntry = new DirectoryEntry(path);

            //init a driectory searcher
            DirectorySearcher dSearcher = new DirectorySearcher(dEntry);

            //This line applies a filter to the search specifying a username to search for
            //modify this line to specify a user name. if you want to search for all
            //users who start with k - set SearchString to "k"
            dSearcher.Filter = "(&(objectClass=user))";

            //perform search on active directory
            sResults = dSearcher.FindAll();

            //loop through results of search
            foreach (SearchResult searchResult in sResults)
            {
                if (searchResult.Properties["CN"][0].ToString() == "Adit")
                {
                    ////loop through the ad properties
                    //foreach (string propertyKey in
                    //searchResult.Properties["st"])
                    //{

                        //pull the collection of objects with this key name
                        ResultPropertyValueCollection valueCollection =
                        searchResult.Properties["manager"];

                        foreach (Object propertyValue in valueCollection)
                        {

                            //loop through the values that have a specific name
                            //an example of a property that would have multiple
                            //collections for the same name would be memberof
                            //Console.WriteLine("Property Name: " + valueCollection..ToString());
                            Console.WriteLine("Property Value: " + (string)propertyValue.ToString());

                            //["sAMAccountName"][0].ToString();
                        }

                    //}
                    Console.WriteLine(" ");
                }

            }

        }
        catch (InvalidOperationException iOe)
        {
            //
        }
        catch (NotSupportedException nSe)
        {
            //
        }
        finally
        {

            // dispose of objects used
            if (sResults != null)
                sResults.Dispose();

        }
        Console.ReadLine();
    }

Can anyone show me a faster code to get user information from AD?

A: 

I'm not sure how much of your "slowness" will be due to the loop you're doing to find entries with particular attribute values, but you can remove this loop by being more specific with your filter. Try this page for some guidance ... Search Filter Syntax

Handleman
A: 

I've had luck with the code in this Code Project article:

Howto: (Almost) Everything In Active Directory via C#

Check out the 'Active Directory Users Tasks' section.

Jay Riggs
+4  A: 

The reason why your code is slow is that your ldap query retrieves every single user object in your domain even though you're only interested in one user with a common name of "Adit":

dSearcher.Filter = "(&(objectClass=user))";

So to optimize, you need to narrow your ldap query to just the user you are interested in. Try something like:

dSearcher.Filter = "(&(objectClass=user)(cn=Adit))";

In addition, don't forget to dispose these objects when done:

  • DirectoryEntry dEntry
  • DirectorySearcher dSearcher
barneytron
+1  A: 

You can simplify this code to:

        DirectorySearcher searcher = new DirectorySearcher();
        searcher.Filter = "(&(objectCategory=user)(cn=steve.evans))";

        SearchResultCollection results = searcher.FindAll();

        if (results.Count == 1)
        {
            //do what you want to do
        }
        else if (results.Count == 0)
        {
            //user does not exist
        }
        else
        {
            //found more than one user
            //something is wrong
        }

If you can narrow down where the user is you can set searcher.SearchRoot to a specific OU that you know the user is under.

You should also use objectCategory instead of objectClass since objectCategory is indexed by default.

You should also consider searching on an attribute other than CN. For example it might make more sense to search on the username (sAMAccountName) since it's guaranteed to be unique.

You might want to consider reading my blog posts on DirectorySearcher performance found at http://blog.scevanscg.com/tag/ldap-search-performance/

Steve Evans
A: 

Well, if you know where your user lives in the AD hierarchy (e.g. quite possibly in the "Users" container, if it's a small network), you could also bind to the user account directly, instead of searching for it.

DirectoryEntry deUser = new DirectoryEntry("LDAP://cn=John Doe,cn=Users,dc=yourdomain,dc=com");

if (deUser != null)
{
  ... do something with your user
}

And if you're on .NET 3.5 already, you could even use the vastly expanded System.DirectorySrevices.AccountManagement namespace with strongly typed classes for each of the most common AD objects:

// bind to your domain
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "LDAP://dc=yourdomain,dc=com");

// find the user by identity (or many other ways)
UserPrincipal user = UserPrincipal.FindByIdentity(pc, "cn=John Doe");

There's loads of information out there on System.DirectoryServices.AccountManagement - check out this excellent article on MSDN by Joe Kaplan and Ethan Wilansky on the topic.

Cheers, Marc

marc_s