Ad perfect information capture

Source: Internet
Author: User
Tags call back findone ldap samaccountname
    • User Name
    • First Query
    • User's groups
    • Group-s users
    • All users
Getting started

To start querying Active Directory from your C # code, you simply add a reference toSystem. directoryservices. dllIn your project and the followingUsingStatement to your code:

Using system. directoryservices;

According to examples provided in the Visual Studio. NET Help, Microsoft recommends using two main classes fromSystem. directoryservicesNamespace:DirectoryentryAndDirectorysearcher. In most cases, it is enough to useDirectorysearcherClass only. Because I am going to talk about querying ad only, not managing ad, I won t provide detailed explanation of usingDirectoryentryClass. But later on, I will show and comment an exampleDirectoryentryUsage. 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 queriesuser 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 );
Search. propertiestoload. Add ("cn ");
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 have Ed from windows, usingExtractusernameMethod. Then I create a newDirectorysearcherObject.DirectorysearcherClass provides a lot of constructors, but I use a default constructor on purpose in order to show how we will initializeDirectorysearcherBefore 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 callFindone ()Method ofDirectorysearcherObject that returns a specialSearchresultObject ining a searching result. if the result object is null, that means there is no information in the ad corresponding to our query. in that particle 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 shoshould contain"CN"Property. We can test it out like:

Lang = csstring Cn = (string) result. properties ["cn"] [0];

The result object contains a special property namedPropertiesThat 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 additionalPropertiestoloadArguments before searching and retrieving them after searching. The following Code shows that:

Search. propertiestoload. Add ("samaccountname ");
Search. propertiestoload. Add ("givenname ");
Search. propertiestoload. Add ("Sn ");
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);
search. propertiestoload. add ("memberof");
stringbuilder groupslist = new stringbuilder ();
searchresult result = search. findone ();
If (result! = NULL)
{< br> int groupcount = result. properties ["memberof"]. count;
for (INT counter = 0; counter {< br> groupslist. append (string) result. properties ["memberof"] [Counter]);
groupslist. append ("|");
}< BR >}< br> groupslist. length-= 1; // remove the last '| 'symbol
return groupslist. tostring ();

We can notice thatFilterProperty andPropertiestoloadProperty 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 ining '|'-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 stored Ed 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 special 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 );
Search. propertiestoload. Add ("member ");
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];
Usernames. Add (User );
Return usernames;

Here I use the same search filter as for user search, but different setPropertiestoload. 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"Member"Of the group object obtained. Then I iterate through the list of"Member"Objects and add them toArraylistBeing returned. I encourage you to investigate a format ofArraylistItems 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 shoshould 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) 
{< br> arraylist allusers = new arraylist ();
directoryentry searchroot = new directoryentry (domainpath );
directorysearcher search = new directorysearcher (searchroot);
search. filter = "(& (objectclass = user) (objectcategory = person)";
search. propertiestoload. add ("samaccountname");
searchresult result;
searchresultco Llection resultcol = search. findall ();
If (resultcol! = NULL)
{< br> for (INT counter = 0; counter {< br> result = resultcol [Counter];
If (result. properties. contains ("samaccountname")
{< br> allusers. add (string) result. properties ["samaccountname"] [0]);
}< BR >}< br> return allusers;

If we go through the code above, we can see some differences from the previous examples. First, I useDirectoryentryObject. 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 cocould look like the following:

"LDAP: // dc = <domain>"

Here<Domain>Is the name of a participating 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 (rememberExtractusernameMethod ?), 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 usingDirectoryentryClass.

Well, let's get back to the code. The next thing you may want to pay attention isFilterString. 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 useFindall ()Method instead ofFindone ().

Best Practice

In the examples above, I was using a simplified code for demonstration purpose only. But the real code cocould be much more complex. Especially in the partPropertiestoloadAnd 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 returnedDirectorysearcherObject by setting its public propertyPropertiestoload.
  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 stored ed from ad as much as possible.
  3. Results returnedDirectorysearcherObject depend on the ad implementation very much. So even if you have CT 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 shoshould assume the worst scenario and always place your ad-querying code inTry-CatchBlock.
  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.

Enable account ad




Private void enableuser (directoryentry de)
Int val = (INT) De. properties ["useraccountcontrol"]. value;
De. properties ["useraccountcontrol"]. value = Val &~ Convert. toint32 (adhelper. ads_user_flag_enum.ads_uf_accountdisable );

De. commitchanges ();
De. close;




Http:// (vs.80). aspx





User Account attributes
Character name "regular" label
Name: givename
Display name displayname
Office physicaldeliveryofficename
Phone number: multiple other othertelephone numbers are separated by semicolons.
Webpage wwwhomepage
Webpage: multiple other URLs are separated by semicolons
"Address" label
Country/region C such as CN, UK GB
Province/Autonomous Region St
City/County L
Street streetaddress
Zip code postalcode

"Account" tag
User Login userprincipalname is like:
User Login Name (Previous Version) samaccountname, for example, S1
Multiple logon userworkstations are separated by commas (,).
User Account Control useraccountcontrol (Enabled: 512, Disabled: 514, password never expired: 66048)
Account Expiration accountexpires

"Configuration file" label
Configuration File Path: profilepath
Login script scriptpath
Main Folder: local path homedirectory
Connect to homedrive
To homedirectory
"Phone" label
Homephone .)
Pager, for example, otherhomephone.
If multiple mobile phone numbers are separated by semicolons.
Fax facsimiletelephonenumber
Note info

"Unit" label

"Affiliated" label
The DN affiliated to the memberof user group does not need to be enclosed in quotation marks. Multiple DN IDs are separated by semicolons (;).
"Dial in" label remote access permission (dial in or VPN) msnpallowdialin
Allowed access value: True
Access denied value: false
Callback option msradiusservicetype
Set by the caller or call back to the value: 4
Always dial back to msradiuscallbacknumber

I can only find a way to passCodeTo obtain the desired information.

The research is actually very simple.


String text = string. empty;
Directoryentry entry = new directoryentry (configurationmanager. etettings ["LDAP"], configurationmanager. etettings ["adminname"], configurationmanager. etettings ["password"]);
// Obtain the subnode
System. directoryservices. directoryentry subentry = entry. Children. Find (ouname, "organizationalunit ");

// Loop the child object
Foreach (directoryentry res in subentry. Children)
If (res. Name. tostring (). substring (0, 3) = "cn =" & res. schemaclassname = "user") // user
Foreach (Object P in res. properties)
Response. write (system. directoryservices. propertyvaluecollection) (p )). propertyname. tostring () + "=========\ N" + (system. directoryservices. propertyvaluecollection) (p )). value );

Response. Write ("---------------------------------------------------------");
If (res. Name. substring (0, 3) = "ou = ")
Foreach (Object P in res. properties)
Response. write (system. directoryservices. propertyvaluecollection) (p )). propertyname. tostring () + "=====================\ N" + (system. directoryservices. propertyvaluecollection) (p )). value );


Comprehensive ad attributes are available.




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.