Click here to Skip to main content
13,091,996 members (60,653 online)
Click here to Skip to main content
Add your own
alternative version


217 bookmarked
Posted 13 Feb 2005

Querying Microsoft Active Directory Using Microsoft .NET Framework Library

, 13 Feb 2005
Rate this:
Please Sign up or sign in to vote.
Describes several useful patterns of querying Microsoft Active Directory using standard .NET Framework methods. Some features discussed and some tips suggested. Contains a number of C# code examples with comments.


In addition to Microsoft SQL Server as a data store, most of the modern infrastructure solutions for enterprises also include Microsoft Active Directory. In many cases, AD can serve as a very useful source of users’ information. To get this information, developers have to query Microsoft Active Directory. For example: get a list of users, get a list of users of the particular group, get a particular user information such as first or last name, and so on. Microsoft .NET Framework provides a standard library for working with Active Directory: System.DirectoryServices namespace in the System.DirectoryServices.dll. Unfortunately, there is only a bit of documentation and there are not a lot of examples provided. Developers could spend a lot of time for researching errors especially if they’re not very experienced in AD. But luckily, there are some very useful patterns that developers can use and even customize. Here, you can find several C# code examples that demonstrate how to query AD in an efficient manner. Hope this article will be helpful.

Getting Started

To start querying Active Directory from your C# code, you simply add a reference to the System.DirectoryServices.dll in your project and the following using statement to your code:

using System.DirectoryServices;

According to examples provided in the Visual Studio.NET Help, Microsoft recommends using two main classes from the System.DirectoryServices namespace: DirectoryEntry and DirectorySearcher. In most cases, it is enough to use DirectorySearcher class only. Because I am going to talk about querying AD only, not managing AD, I won’t provide detailed explanation of using DirectoryEntry class. But later on, I will show and comment an example of DirectoryEntry usage. In addition, I assume that Active Directory is always up and running in your environment. One more thing I want to mention before we start is that I will separate all AD queries by two large groups: user-oriented queries and common queries. The difference between these types of queries we’ll figure out later. Let’s get started.

User Oriented Queries

User Name

First of all, I have to tell that a user-oriented query always uses a user name as a parameter. Let’s figure out what the user name is. This is the name part of a login name, which users enter while logging in Windows. This name part follows the ‘\’ symbol that separates the domain name and the user name. It’s a good practice to extract the user name from the login name before using it in the AD query. We can do it easily:

string ExtractUserName(string path)
    string [] userPath = path.Split(new char [] {'\\'});
    return userPath[userPath.Length-1];

First Query

Now we know the user name, and it’s good to know if this user exists in the AD. Let’s do it like:

bool IsExistInAD(string loginName)
    string userName = ExtractUserName(loginName);
    DirectorySearcher search = new DirectorySearcher(); 
    search.Filter = String.Format("(SAMAccountName={0})", userName);
    SearchResult result = search.FindOne();

    if (result == null)
        return false;
        return true;

This is our first AD query, so let’s see what we are doing here. First of all, I extract the user name from the login name that we received from Windows, using the ExtractUserName method. Then I create a new DirectorySearcher object. DirectorySearcher class provides a lot of constructors, but I use a default constructor on purpose in order to show how we will initialize the DirectorySearcher before starting a query.

Actually, the query itself is located in the Filter property of the DirectorySearcher object. I have to initialize it before starting the query. Here we come to the Active Directory territory. To create a Filter string, you have to be familiar with the AD object structure. But in this article, I won’t talk about AD itself, so simply take a look at the code above and learn that the filter keyword "SAMAccountName" allows us to select an AD object with the given name equal to the login name.

Now I have to assign a PropertiesToLoad property of the DirectorySearcher object. This is a collection containing attribute names of AD objects that we want the query to return. By analogy with SQL query, the Filter property serves as the WHERE clause and the PropertiesToLoad property works as a list of column names that the query will return. The "cn" keyword means a common name of the AD object, and in this query, we are not interested in any other properties to return. Basically, this is a good practice to limit the amount of returning properties as much as you can. It can reduce execution time of the query significantly.

After all, we are ready to run a query. I simply call a FindOne() method of the DirectorySearcher object that returns a special SearchResult object containing a searching result. If the result object is null, that means there is no information in the AD corresponding to our query. In that particular case, it means a user with the given name is not found. Otherwise, we assume that the user exists in the AD. In order to make sure that the user does exist, we can check out the result object. As we remember, the result object should contain the "cn" property. We can test it out like:

lang=csstring cn = (string)result.Properties["cn"][0];

The result object contains a special property named Properties that returns a typed collection containing the values of properties of the object found in the AD. We can also use this method for retrieving additional information about the user from AD. To do this, we only need to add additional PropertiesToLoad arguments before searching and retrieving them after searching. The following code shows that:

SearchResult result = search.FindOne();
string samaccountname = (string)result.Properties["samaccountname"][0];
string givenname = (string)result.Properties["givenname"][0];
string surname = (string)result.Properties["sn"][0];

The example above contains the names of the most widely used properties. You can for sure retrieve any possible property from AD simply using its name.

That’s it actually. Now I am going to show you several more queries, but you already know how to query AD.

User’s Groups

Let’s find out what groups our user belongs to. See the code:

string GetADUserGroups(string userName) {
    DirectorySearcher search = new DirectorySearcher();
    search.Filter = String.Format("(cn={0})", userName);
    StringBuilder groupsList = new StringBuilder();
    SearchResult result = search.FindOne();
    if (result != null)
        int groupCount = result.Properties["memberOf"].Count;
        for(int counter = 0; counter < groupCount; counter++)
    groupsList.Length -= 1; //remove the last '|' symbol
    return groupsList.ToString();

We can notice that the Filter property and PropertiesToLoad property are what makes the difference from the previous query. And also in this query, I assume there are several outputs in the result object. This method returns a list of the AD groups the user belongs to as a string containing '|'-symbol separated group names. Actually, group names in that list appear in a relatively unusual format, and you can examine this format by yourself.

Common Queries

Common queries allow us to retrieve much more information from AD. This type of queries are potentially dangerous because of potentially huge amount of information that might be received back from AD. So you have to be careful while experimenting with such queries.

Group’s Users

Let’s get a list of users belonging to a particular AD group. The code below shows how to do this:

ArrayList GetADGroupUsers(string groupName)
{    SearchResult result;
    DirectorySearcher search = new DirectorySearcher();
    search.Filter = String.Format("(cn={0})", groupName);
    result = search.FindOne();

    ArrayList userNames = new ArrayList();
    if (result != null)
        for (int counter = 0; counter < 
                 result.Properties["member"].Count; counter++)
            string user = (string)result.Properties["member"][counter];
    return userNames;

Here I use the same search filter as for user search, but different set of PropertiesToLoad. So the query returns to us an object with the common name equal to the group name and a properties list containing a list of other objects that are a "member" of the group object obtained. Then I iterate through the list of the "member" objects and add them to the ArrayList being returned. I encourage you to investigate a format of the ArrayList items in order to figure out what actually you have back from AD. You’ll see it’s not a simple user name.

All Users

The last query I want to discuss in this article is meant to return a list of all the AD domain users. This is an extremely risky operation because of a large amount of users in the AD domain and possible incorrect implementation of AD. I’d like to explain the second sentence. This query uses a special search filter that looks for every object with a specific property that should mean this object is a user object. But sometimes administrators design AD structure even without this property or enter new records to AD not setting this property. So it’s very possible to get a list of all objects in AD instead of domain user objects only. But it’s enough of bad things, let’s get to the code.

ArrayList GetAllADDomainUsers(string domainpath)
    ArrayList allUsers = new ArrayList();

    DirectoryEntry searchRoot = new DirectoryEntry(domainpath);
    DirectorySearcher search = new DirectorySearcher(searchRoot);
    search.Filter = "(&(objectClass=user)(objectCategory=person))";

    SearchResult result;
    SearchResultCollection resultCol = search.FindAll();
    if (resultCol != null)
        for(int counter=0; counter < resultCol.Count; counter++)
            result = resultCol[counter];
            if (result.Properties.Contains("samaccountname"))
    return allUsers;

If we go through the code above, we can see some differences from the previous examples. First, I use a DirectoryEntry object. I do it to connect to a specific context of AD and limit my search by this context. In my case, I suppose to use a single domain context and thus I have to provide a path to the domain I’m interested in. I have to use a specific form of this path in terms of LDAP language. It could look like the following:


Here <domain> is the name of a particular domain. Another example is using a current domain. To find out the name of the current domain, I can get it from the user login name (remember ExtractUserName method?), or I can determine it programmatically like the following:

DirectoryEntry entryRoot = new DirectoryEntry("LDAP://RootDSE");
string domain = entryRoot.Properties["defaultNamingContext"][0];
DirectoryEntry entryDomain = new DirectoryEntry("LDAP://" + domain);

This is an example of using a DirectoryEntry class.

Well, let’s get back to the code. The next thing you may want to pay attention is a Filter string. It contains no parameters, but instead it consists of an AD specific pattern. (If you have no idea what that pattern means, probably it’s a good idea to get familiar with AD some day ;-)) And the last difference is the use of FindAll() method instead of the FindOne().

Best Practice

In the examples above, I was using a simplified code for demonstration purpose only. But the real code could be much more complex. Especially in the part of PropertiesToLoad and parsing of search outcome. To help you work with AD, I’d like to share some useful tips that have been practically proven.

  1. Always limit the amount of information returned by DirectorySearcher object by setting its public property PropertiesToLoad.
  2. Querying Active Directory is a very time-consuming process. Besides, information in AD always doesn’t change frequently. So the good practice is to cache information received from AD as much as possible.
  3. Results returned by DirectorySearcher object depend on the AD implementation very much. So even if you expect some object properties to be returned, always check them for null before using.
  4. Querying AD is a network operation. That means you never know if there are some problems with network unless they happened. As a developer, you should assume the worst scenario and always place your AD-querying code in the try-catch block.
  5. And the last one. Usually, you don’t know how much information AD contains. So keep off using very common queries that potentially can return a very large and even huge amount of information as a result. There are two main risks in such queries: first, the query can last for a very long time like tens of minutes and even hours; and second, the size of the result returned can exceed the memory size and crush your program.


This article is aimed to illustrate the opportunities of working with Microsoft Active Directory provided by the .NET Framework library. Here I have shortly described a common methodology of building AD queries using the .NET Framework standard features. This methodology was illustrated by a number of code examples that can be used practically. Also, some practically proven tips are provided. Using the approach described, developers can create their own AD queries and extend the ones suggested.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Alexander Turlov
Canada Canada
Alexander Turlov has been working in IT industry since 1987. His programming experience includes such languages as FORTRAN, Pascal, and Basic, C, C++ and C#. He's been working for different industries like science, manufacturing, retail, utilities, finance, insurance, health care, education and so on. His area of interests is rich web applications development with .NET, C#, ASP.NET/MVC and JavaScript. He is working in software development doing architecture, design and development on .NET platform and using Microsoft Visual Studio, IIS and SQL Server as his primary tools, and a lot of other commercial and open source frameworks and tools. He holds a M.Sc. degree in physics and an MCSD.NET certification.

View my profile on LinkedIn

View my blog

You may also be interested in...


Comments and Discussions

QuestionAD access thrown error Pin
Kevin Ramírez Murillo5-Jun-15 6:39
memberKevin Ramírez Murillo5-Jun-15 6:39 
AnswerRe: AD access thrown error Pin
Kevin Ramírez Murillo5-Jun-15 7:07
memberKevin Ramírez Murillo5-Jun-15 7:07 
QuestionAD Search Error Pin
Member 1156737030-Mar-15 6:11
memberMember 1156737030-Mar-15 6:11 
QuestionWorking with more than one LDAP path Pin
Member 1102954522-Aug-14 2:48
memberMember 1102954522-Aug-14 2:48 
QuestionSearch user by employee ID Pin
Member 97066335-Feb-13 5:07
memberMember 97066335-Feb-13 5:07 
GeneralMy vote of 5 Pin
Petr Pechovic4-Dec-12 3:41
memberPetr Pechovic4-Dec-12 3:41 
QuestionUsing group users Query that is posted above. How do you get the users name and not network sign on? Pin
5kracing19-Jul-12 2:17
member5kracing19-Jul-12 2:17 
QuestionRetrieving the attribute value from Account Tab of an User Object in the Active Directory Pin
Prethesh Kumar Bhalotia2-Feb-12 2:22
memberPrethesh Kumar Bhalotia2-Feb-12 2:22 
QuestionI get unspecified Error while querying for logged in user Pin
Member 33018046-Nov-11 20:56
memberMember 33018046-Nov-11 20:56 
Generalgetting the role of the user Pin
jiaudheen25-Apr-11 2:00
memberjiaudheen25-Apr-11 2:00 
Generalfind group names that a user is part of Pin
boyhamilton3-Feb-11 10:18
memberboyhamilton3-Feb-11 10:18 
GeneralRe: find group names that a user is part of Pin
Nanda Kish7-Feb-11 18:19
memberNanda Kish7-Feb-11 18:19 
GeneralMy vote of 5 Pin
magham31-Jul-10 9:45
membermagham31-Jul-10 9:45 
GeneralRetreive users list from several groups Pin
stan926-Apr-10 21:22
memberstan926-Apr-10 21:22 
AnswerRe: Retreive users list from several groups Pin
Alexander Turlov7-Apr-10 8:54
memberAlexander Turlov7-Apr-10 8:54 
Glad you found the article useful. I'll try to answer your question but my problem is that I don't work with AD for quite a while and I don't have the environment to play around so I'll try to give you an idea but it's up to you to test it.

Based on just common sense (it does not always work with AD however) you could perform an AD query to retrieve all the objects of "objectClass=group" without limiting the results by the "cn" attribute value. At the same time you want for every group object found to have a list of the members the belong to that group. So all that you need to do is to perform your query like this:

DirectorySearcher search = new DirectorySearcher();
search.Filter = "(objectClass=group)";
SearchResultCollection resultCol = search.FindAll();

Then you simply iterate through the result collection and retrieve the members for every group. Since I can't test this I leave to you at this point. Hope it'll help.
Alexander Turlov

QuestionADGroup access from different domain ?? Pin
monishankar2-Feb-10 7:13
membermonishankar2-Feb-10 7:13 
GeneralMy vote of 1 Pin
Zolile12-Aug-09 2:21
memberZolile12-Aug-09 2:21 
QuestionGroup policies [modified] Pin
PsyAfter14-Jan-09 6:23
memberPsyAfter14-Jan-09 6:23 
GeneralGet AD rights/permission of a User on a group [modified] Pin
Offlinesurfer31-May-08 0:50
memberOfflinesurfer31-May-08 0:50 
GeneralSearch in ActiveDirecotry Pin
oneforall20129-May-08 21:11
memberoneforall20129-May-08 21:11 
AnswerRe: Search in ActiveDirecotry Pin
Alexander Turlov29-May-08 10:13
memberAlexander Turlov29-May-08 10:13 
Generalupdating active directory phone number on a web form Pin
Troopa15-Apr-08 1:10
memberTroopa15-Apr-08 1:10 
GeneralRe: updating active directory phone number on a web form Pin
Troopa15-Apr-08 1:12
memberTroopa15-Apr-08 1:12 
GeneralRe: updating active directory phone number on a web form Pin
Alexander Turlov21-Apr-08 4:38
memberAlexander Turlov21-Apr-08 4:38 
GeneralRe: updating active directory phone number on a web form Pin
Troopa6-May-08 4:07
memberTroopa6-May-08 4:07 
QuestionHelp finding Direct Reports Pin
lisa044030-Aug-07 12:16
memberlisa044030-Aug-07 12:16 
GeneralA question about DirectorySearcher Pin
benliliu6-Aug-07 4:44
memberbenliliu6-Aug-07 4:44 
GeneralRe: A question about DirectorySearcher Pin
Alexander Turlov2-Jun-08 3:35
memberAlexander Turlov2-Jun-08 3:35 
QuestionLDAP error when performing C# query Pin
kstory0030-Jul-07 6:06
memberkstory0030-Jul-07 6:06 
AnswerRe: LDAP error when performing C# query Pin
tonytzh18-Oct-07 19:23
membertonytzh18-Oct-07 19:23 
GeneralError: The server is not operational Pin
cksat122-Jun-07 3:48
membercksat122-Jun-07 3:48 
Generalhelp,I want get someone's directReports Pin
tfe_tao_feng20-Jun-07 7:34
membertfe_tao_feng20-Jun-07 7:34 
GeneralRe: help,I want get someone's directReports Pin
mbowles20127-Jun-07 9:18
membermbowles20127-Jun-07 9:18 
GeneralRe: help,I want get someone's directReports Pin
lcg426130-Aug-07 8:41
memberlcg426130-Aug-07 8:41 
QuestionSearchResult .Property.Name always lower case??? Pin
sallas000111-Jun-07 21:03
membersallas000111-Jun-07 21:03 
GeneralExcellent Article! Pin
mobfigr6-Jun-07 5:22
membermobfigr6-Jun-07 5:22 
QuestionOperations error occured Pin
humberprogrammer25-May-07 5:54
memberhumberprogrammer25-May-07 5:54 
GeneralPermissions question Pin
RLMcCutchen8-May-07 9:04
memberRLMcCutchen8-May-07 9:04 
GeneralAwesome article! Pin
search_find29-Apr-07 15:49
membersearch_find29-Apr-07 15:49 
GeneralGroup Name (CN) truncated for a small % of groups Pin
rlivelyppk19-Apr-07 7:33
memberrlivelyppk19-Apr-07 7:33 
GeneralGetting User Groups Pin
Eagle_Tsui10-Apr-07 16:08
memberEagle_Tsui10-Apr-07 16:08 
GeneralRe: Getting User Groups Pin
informax21-Jun-08 3:09
memberinformax21-Jun-08 3:09 
GeneralRe: Getting User Groups Pin
Dewi Rutledge22-Apr-09 0:46
memberDewi Rutledge22-Apr-09 0:46 
GeneralRe: Getting User Groups Pin
ke4vtw7-Jan-11 6:13
memberke4vtw7-Jan-11 6:13 
GeneralResultPropertyCollection returns System.Byte[] Pin
smartoez3-Apr-07 7:44
membersmartoez3-Apr-07 7:44 
GeneralRe: ResultPropertyCollection returns System.Byte[] Pin
Miguel Martinez4-Jan-11 5:57
memberMiguel Martinez4-Jan-11 5:57 
GeneralOnly works when I use "Administrator" as the user name. Pin
Grounds3-Apr-07 4:58
memberGrounds3-Apr-07 4:58 
AnswerRe: Only works when I use "Administrator" as the user name. Pin
Alexander Turlov11-Apr-07 4:25
memberAlexander Turlov11-Apr-07 4:25 
GeneralRe: Only works when I use "Administrator" as the user name. Pin
cksat122-Jun-07 3:39
membercksat122-Jun-07 3:39 
GeneralNested groups Pin
Refky Wahib1-Apr-07 0:08
memberRefky Wahib1-Apr-07 0:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170813.1 | Last Updated 13 Feb 2005
Article Copyright 2005 by Alexander Turlov
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid