advanced web statistics

Query Active Directory Users using C#

6/1/2006 10:55:02 AM

I've been dinking around in the System.DirectoryServices namespace lately trying to update user's in Active Directory. This particular namespace has 2 main component classes: DirectoryEntry and DirectorySearcher. After a couple of days (hence no posting) I have successfully accomplished the tasks of querying for and updating users.  I will share some basic functionality for looking up and verifying users in Active Directory to lay the foundation for those of you that are interested.  It might be useful to read up on LDAP to get a good understanding of what it is and how it works with Active Directory.

Setting up the connection
public static DirectoryEntry GetDirectoryEntry()
{
   DirectoryEntry de = new DirectoryEntry();
   de.Path = "LDAP://OU=Domain,DC=YourDomain,DC=com";
   de.AuthenticationType = AuthenticationTypes.Secure;

   return de;
}

Does a User Exist?
Before you update any user information it is probably a good idea to find out if they actually exist in the Active Directory.

public bool UserExists(string username)
{
   DirectoryEntry de = GetDirectoryEntry();
   DirectorySearcher deSearch = new DirectorySearcher();

   deSearch.SearchRoot = de;
   deSearch.Filter = "(&(objectClass=user) (cn=" + username + "))";

   SearchResultCollection results = deSearch.FindAll();

   return results.Count > 0;
}

private String FindName(String userAccount)
{
   DirectoryEntry entry = GetDirectoryEntry();
   String account = userAccount.Replace(@"Domain\", "");

   try
   {
      DirectorySearcher search = new DirectorySearcher(entry);
      search.Filter = "(SAMAccountName=" + account + ")";
      search.PropertiesToLoad.Add("displayName");

      SearchResult result = search.FindOne();

      if (result != null)
      {
         return
result.Properties["displayname"][0].ToString();
      }
      else
      {
         return "Unknown User";
      }
   }
   catch (Exception ex)
   {
      string debug = ex.Message;

      return "";
   }
}

The form I created has 2 textboxes (Username & Password) and a submit button. When the button is clicked all the events are fired and if everything checks out the user is updated in Active Directory.

private void btnUpdate_Click(object sender, EventArgs e)
{
   if (tbUser.Text != "" && tbPass.Text != "")
   {
      string username = tbUser.Text.ToString();
      string password = tbPass.Text.ToString();

      if (UserExists(FindName(username))
      {
         ModifyUser(FindName(username), username, password);
      }
   }
}

Modify User Information
public void ModifyUser(string userDisplayName, string username, string password)
{
   DirectoryEntry de = GetDirectoryEntry();
   de.Username = username;
   de.Password = password;

   DirectorySearcher ds = new DirectorySearcher(de);
   ds.Filter = ("(&(objectclass=user)(objectcategory=person)
               (displayname="
+ userDisplayName + "))");

   ds.SearchScope = SearchScope.Subtree;

   SearchResult results = ds.FindOne();

   if (results != null)
   {
      try
      {
         DirectoryEntry updateEntry = results.GetDirectoryEntry();
         updateEntry.Properties["department"].Value = "555";
         updateEntry.CommitChanges();
         updateEntry.Close();
      }
      catch (Exception ex)
      {
         tbError.Text = ex.ToString();
      }
   }

   de.Close();
}

Good luck! With a little patience you will find that Active Directory is quite fun to work with.  Also keep in mind that this is a very basic example.  When you master this you can start pulling data from external data sources, formatting, look them up in Active Directory and then update accordingly!

.NET, C#, Code, Programming

kick it on DotNetKicks.com

Comments


Will, watch your naming conventions here. Underscores can be used to differentiate between class fields and methods but they are mainly useful in VB where you don`t have case sensitivity. With C#, I really feel they are unnecessary but many people do still use them. In general, fields and parameters should be camel (firstName) cased while methods should be pascal (FirstName) cased. Underscores should never be used with parameters.

Also, watch the hungarian notation. Microsoft has come out pretty firmly against it.

If you want to read the difinative book on the subject and learn alot, check out "Framework Design Guidelines : Conventions, Idioms, and Patterns for Reusable .NET Libraries". I can show you a copy at lunch one day but can`t part with it...

Posted by: Andrew | 6/4/2006 5:03:10 PM

I should just buy it then.

Thanks for the feedback Andrew. Speaking of lunch, does tomorrow work?

Posted by: Will | 6/5/2006 10:51:59 AM

Yes, Lunch today Tues. Have your people phone my people. 11:30ish?

Posted by: Andrew | 6/6/2006 1:08:05 PM

Hi,

U r post is very useful to me for my project. But I am at starting level i got windows xp operating system and i need to download the openldap server into my machine and configure so the i can add the users and permissions to them. Can you help me in this regarding.

Or else just give me some links which i can go thru.Already i have gone thru many links but every link leads to confusion.

Ram.S

Posted by: Ram | 6/26/2006 6:43:15 AM

HI,
My self Harikrishna,

This is realy very good article.

See, what my problem is:

I wanto to taking the List of Users from the system and Just Insert it into the Our Database.

So, please give me the complete information regarding this.

Please.

With Regards,
Harikrishna

Posted by: Harikrishna | 7/12/2006 2:36:01 AM

It`s a joke right. Posting untested uncompiled code that has flagrant coding violations and no consistency. You might as well stick your head through a hole in the fence as ask for someone to give you a pie-face.

Now.... Go read ".NET Developer`s guide to Directorey Services Programming and do this again.


Posted by: grbryan | 7/26/2006 10:27:27 AM

Are you able to read Bryan?

"Also keep in mind that this is a very basic and generic example..."

Coding violations? Maybe.
First Active Directory application? Definitely.
Actual production version of this code working? You bet.

This is more about concept than it is completeness. I learned something and I wanted to share and many people are thankful for that. Now... you learn how to fucking read and spell "Directory" correctly. The inconsistency issue comes with changing naming conventions after I originally posted the code snippets. I admit I wasn`t using the correct naming conventions and thought I had completely edited the document correctly.

You shouldn`t have to depend on people to supply you with complete production environment-ready code. In a round-about way, thank you for pointing out the inconsistency.

Thanks again Bryan from Olympia, WA.

Posted by: Will | 7/26/2006 2:32:01 PM

Thanks for posting this...I found it *very* useful! It is exactly what I needed to see to begin learning about System.DirectoryServices.

Posted by: Jeff | 7/27/2006 8:02:34 AM

You are welcome Jeff. I`m glad someone appreciates this!

Posted by: Will | 7/27/2006 12:48:33 PM

Hi Will

One question, about DirectorySearcher`s filter property. Is this case sensitive? if the Windows LoginId is created as SmnP7812. If we search for search.Filter = "(SAMAccountName=sMnp7812)"; will it find the User ?

Posted by: Suman | 8/1/2006 12:44:37 AM

Suman,

As far as I know Active Directory does not force case-sensitivity.

- Will

Posted by: Will | 8/1/2006 8:39:44 PM

Will, would you by chance have a project with all this up and running I could steal from you? I`m having a hard time getting my head around AD and thought that might help.

Thanks,
Brad

Posted by: Brad | 8/4/2006 11:47:10 AM

Brad,

I do and I don`t. The only code I have for this is in production on my previous employers` network.

What are the problems that you are having? I will be glad to assist if at all possible.

- Will

Posted by: Will | 8/4/2006 1:22:31 PM

Thank you for taking the time to post this very helpful code. I may still need to read ".NET Developer`s guide to Directorey Services Programming." The problem that I am having is that I can login in debug mode but not when I am running from the published web code (ASP.NET 2.0). I get the error "DirectoryServicesCOMException: Login failure..." Several posts at other forums put the error on the AuthenticationType, but I have not had any success changing it. Any suggestions?
-greg

Posted by: greg | 10/4/2006 9:58:19 PM

Can you show me a sample using the Users GUID instead of their accountName?

Posted by: Thurst | 12/19/2006 9:50:12 PM

Plz can you provide me the way to do paging in c# for active directory entries.

Posted by: ramchandra | 12/20/2006 9:02:28 AM

Not bad man. I just completed a hellish project at work that was a literal AD nightmare. Not bad for your first app. Do not listen to anal retentive folks who have nothing better to do than flame. Post on man. Good show.

Posted by: CT | 1/10/2007 8:35:45 PM

I meant Active Directory app :). My bad.

Posted by: CT | 1/10/2007 8:36:43 PM

Hi
Thanks for this code, really use full and achieved good success by this, but can u send me the code for getting the list of password for the Existing users in the Active Directory. This is needed for my project.

Regards,
Rom

Posted by: romrombus | 2/23/2007 2:15:06 AM

Very nice

Posted by: sunita | 3/29/2007 5:37:55 AM

Found your code very useful. Exactly what I needed. Do you have any favorite books on the subject that helped you out, or electronic resources?

-Isaac

Posted by: Isaac | 3/30/2007 8:04:48 AM

hey the code works excellent...i am looking for a code that has a password check too..mean to say it finds the user name and checks the password associated with them...

Can u give a brief idea on how the above subject works ? would appreciate ur help in this matter.



Posted by: danny | 3/31/2007 12:33:58 AM

Hi,
The article is excellent and I got a lots of help from it.
But my problem is :

I have two text box name txtUser and txtPassword and I want to display the current user name and password whnever the form is loading.

My code for displayng user name in the load event is
txtUserName.Text = Environment.UserName;

I am being able to display the user name in txtUser but not being able to display the corresponding user password in txtPassword.


Can you help me in this regard? I am really facing a lots of problem on this matter.



Posted by: Biswajit | 4/4/2007 4:02:32 AM

Hi Will,
I`m new to the .net world although I`ve come a long way in the past 8 months working with VS 2003, C#, and HTML. Sometimes I feel like I`m so close to understanding all this stuff and then something unexpected happens that drives me to drinking...lol. Anyway, I`m getting a compiler error on the code in the button1_click event. The error is as follows "The name `userName` does not exist in the class or namespace `Validate_AD_UserID_Pswd.WebForm1`
I`ve been trying different things and I`ll continue to try but I was hoping you might be able to point me in the right direction.

Posted by: Tony DAmbrosia | 4/13/2007 11:49:21 AM

Can you show me a sample using the Users GUID instead of their accountName?

Posted by: Abdurahim | 5/22/2007 2:27:23 AM

Very good article. I am just learning ASP.Net and need to query my AD for the existence of users. I think this is a great start. I have seen a lot of tutorials that are incomplete and leave you wanting a LOT more or they claim to be complete and don`t work.

I`ll play with this and hopefully if I have any questions, you will be able to fill in the blank areas for me.

Posted by: CNorman | 5/29/2007 10:17:47 PM

This is very good article. It helps me a lot understanding the sync tool for our Employee Management System..Cheers

Posted by: GGunawan | 5/31/2007 7:59:18 PM

Basic, straight forward, and clear. Great article Will! Keep on keeping on!

Posted by: DPrimetime | 6/14/2007 12:00:57 PM

I found this very usefull also. Keep them coming. Those that bash people who try to help others because of every little nit picking thing, suk in my opinion. (I intentionally left out the c in suk, so don`t bash for typos) ;)
They need to realize that these helpful instructions should be used for functionality reference and understanding concepts, not cut and paste code without checking first.
Very nice job.
Jeff


Posted by: Jeff | 6/21/2007 1:48:12 PM

Hey will

Thats was a big help !
But plz help me, i am stuck with path problem . I have to access Active Directory of a remote server of which i know only address (e.g 192.16.20.8)
How can i set the path to acess its ctive directory

please answer me
Bye

Posted by: Khan | 7/20/2007 7:33:16 AM

Hi Will,
I am trying to implement some kind of Online Phone book as opposed to the current paper based one that my company is using. I would like to link a page to the AD so that when one queries for the user`s phone number, it actually searches against the AD and comes up with the current information.
I would appreciate some pointers.
Regards

Posted by: Bruce | 7/24/2007 11:25:36 AM

Nice article, if you use Active Directory a lot you may want to check out AD-Advantage (ad-advantage.com). Those guys put together a great library that does everything for you. For example, you can search with a single line of code!

Posted by: Tom | 8/7/2007 2:13:07 AM

Great job Will! Love the help about AD! Keep up the good work.


Posted by: Gary | 8/31/2007 12:01:47 PM

Why is it that these rama dama people that are billing themselves as hotshot computer programmers, taking programming jobs in our country haunt these blogs and forums begging us to do the work for them. They cant write english so there spoken english must be as bad. I can imagine the kind of code they turn out. Really burns me.

Posted by: rmiller | 9/28/2007 8:05:41 PM

I actually LOL`ed at that comment rmiller.

haha

Posted by: Will Asrari | 9/28/2007 8:07:43 PM

I hope rmiller is not coding in English ;-)

Posted by: John | 10/4/2007 9:51:43 PM

thanks for posting it. great source, since I don`t expect for other people to write my code and just copy-paste it. I understand this to be a guideline or a starting point. don`t listen to the flaming comments

Posted by: me | 10/8/2007 5:30:46 PM

Thx for post, very useful stuff ... short & sweet. Keep it up!

Posted by: JTThegeek | 11/30/2007 2:33:21 PM

Hey Will - i was doing a search on google and your site popped up as #2 with this blog entry. I recognized the name (from previous job at HT) so thought I`d say hello - hope your current job is more enjoyable.

Posted by: Rachel | 12/3/2007 2:26:50 PM

HI,

iam trying to do the security with Active Directory but iam not able to find the exact domain name

Posted by: ravindar | 12/7/2007 4:32:46 AM

http://msdn2.microsoft.com/en-us/library/ms180890(VS.80).aspx

Posted by: matthew | 12/11/2007 1:29:56 AM

Typing whoami at the command prompt will tell you who you are. Its always handy if you forget...lol.

Posted by: Matthew | 12/11/2007 1:31:46 AM

copy and paste this code somewhere useful. I made an aspx page with a simple textbox that i displayed the info to.
I grabbed it from and modified it quickly:
http://msdn2.microsoft.com/en-us/library/ms180881(VS.80).aspx

Try to use msdn2s tech net its quite good if you can find it.
// add these to your page
using System.Text;
using System.Collections;
using System.DirectoryServices;

// also make sure you add the reference to system.directoryservices to your visual studio 2005 project by rightclicking on your project and add reference.

//your AD ldap path will be different to mine, I am currently coding this at www.sstuwa.org.au as im setting up an IN OUT web system for the people here. You can find yours by going into Active directory Users and Computers, or asking your administrator or looking at your email address as the last part is probably your domain or one of them.

protected void Page_Load(object sender, EventArgs e)
{
SearchResultCollection results = null;

try
{
// Bind to the users container.
string path = "LDAP://CN=users,DC=sstuwa,DC=org,DC=au";
DirectoryEntry entry = new DirectoryEntry(path);

// Create a DirectorySearcher object.
DirectorySearcher mySearcher = new DirectorySearcher(entry);

// Set a filter for users with the name test.
//mySearcher.Filter = "(&(objectClass=user)(anr=test*))";

// Use the FindAll method to return objects to a
// SearchResultCollection.
results = mySearcher.FindAll();

// Iterate through each SearchResult in the SearchResultCollection.
foreach (SearchResult searchResult in results)
{
// Display the path of the object found.
//Console.WriteLine("Search properties for {0}", searchResult.Path);

// Iterate through each property name in each SearchResult.
foreach (string propertyKey in
searchResult.Properties.PropertyNames)
{
// Retrieve the value assigned to that property name
// in the ResultPropertyValueCollection.
ResultPropertyValueCollection valueCollection =
searchResult.Properties[propertyKey];

// Iterate through values for each property name in each
// SearchResult.
foreach (Object propertyValue in valueCollection)
{
string temp1 = (string)propertyKey;
string temp2 = (string)propertyValue.ToString(); //(string)(string)propertyKey

if (temp1=="name") TextBox1.Text += ""n "+temp2;
}
}
}
}
finally
{
// To prevent memory leaks, always call
// SearchResultCollection.Dispose() manually.
if (null != results)
{
results.Dispose();
results = null;
}
}
}

Posted by: matthew | 12/11/2007 3:11:04 AM

Well,
Is it possible to retrieve all the groups associated with a GUID ??
If possible please can u give some pointer on it?
Thanks in Advance

Posted by: Vinod | 12/15/2007 6:45:29 AM

This is very helpful to start wih my project. I need to update AD form two different databases that has the employees information, I will be updating phone numbers, manager info, no username or password but I need to do it using c#. I was thinking that maybe a web service will help or a stored procedure.

Any suggestions?

Posted by: Luis | 2/13/2008 11:54:54 AM

I have question that my domain name is neal1102 ok and i am getting error of
"The Server is not operational" but i am getting regularly successful ping from my server So can u please tell me what the problem.

I ma writting The code like which as follow :

DirectoryEntry entry = new DirectoryEntry("LDAP://" + txtDomainName.Text);
DirectorySearcher searcher = new DirectorySearcher(entry);

searcher.Filter = "(objectClass=User)";

foreach (SearchResult res in searcher.FindAll())
{
lblLoginName.Text = "LoginName :" + GetProperty(res, "cn");
lblFirstName.Text = "FirstName :" + GetProperty(res, "givenName");
lblLastName.Text = "LastName :" + GetProperty(res, "sn");
lblCompany.Text = "Company :" + GetProperty(res, "company");
}

Please help to slow my problem

Posted by: Nikunj Matawala | 3/14/2008 5:04:30 AM

Hi Will,

I`m crating a phone directory in from our intranet and the data is pulled from Active Directory, my question is to filter data(searcher.Filter) is it necessary to be user name always coz in my case anyone accessing the intranet should be able to view the phone book.
Please help!!

Regards

Posted by: Leela | 4/11/2008 7:40:06 AM

Damn!! my language is so bad. Should read it before posting.
To miller, no offence
i do code in english and because of intellisense it does not turn bad :)

Posted by: Leela | 4/11/2008 7:48:30 AM

Nice posts.

I was wondering if anyone knows how to update Active Directory Objects using the "person who started the .NET app with runas".

So if I did a right-click "runas" on the compiled C# .NET executable / application with a privileged account. How would I then update / search for users in Active Directory?

Any example of how to do this would be of great help,

thanks,

JW

Posted by: JW | 5/12/2008 8:17:08 PM

can any one help me i want code to add users to active directory

Posted by: kavya | 8/1/2008 10:21:42 AM

Note: the first three times I tried to comment I got this error on this web server blog page:

Server Error in `/` Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

===================


This bit
> String account = userAccount.Replace(@"Domain"", "");

unfortunately assumes the domain casing matches exactly with what is in the userAccount string -- if there is any difference, this bit will fail. In my own version (developed before I saw this), I go to the bother of lowercase matching to handle case discrepencies here. Tedious, but worth getting right, especially as I`ve seen this exact problem.

Also, btw, getting the current server machine
s name turned out to be quite a bother of pinvoke declarations to successfully call DsRoleGetPrimaryDomainInformation using DsRolePrimaryDomainInfoBasic.

Posted by: Perry | 8/5/2008 10:49:03 AM

In my experiments, I found that this

> DirectoryEntry updateEntry = results.GetDirectoryEntry();

triggers a read of all properties, no matter how you`ve limited it with PropertiesToLoad. Therefore I have determined that you should never call results.GetDirectoryEntry in aspx server-side code.

Do you know any other solution (besides avoiding that call, and only checking specific properties)?

Posted by: Perry | 8/5/2008 10:53:08 AM

Nice report. I`ve read a couple because it is interesting.

Posted by: solraC# | 11/28/2008 5:26:53 AM

hi, its been a week... Still i cant access AD from aspx.net using c#. We are using Windows server 2003. I used and test a lot of samples found in net... Still, I couldn figure it out. I am a new in ASPX and AD.... Any help will much apriciated.... my ym is g[dot]palawan[at]yahoo[dot]com

Posted by: gpalawan | 12/13/2008 4:45:03 AM

Leave a Comment

   

  Enter the text to proceed!