Saturday, August 19, 2006

Retrieving data from Active Directory with System.DirectoryServices – the right way

I recently needed to retrieve to some data from Active Directory in an ASP.Net webservice. After looking around a bit, I stumbled upon this article – Accessing Global Address List via System.DirectoryServices namespace on CSharpCorner. The main piece of code shown is the one below – the object you should take a look at is the DirectorySearcher class.

public ArrayList returngal(){
DirectorySearcher objsearch = new DirectorySearcher();
string strrootdse = objsearch.SearchRoot.Path ; DirectoryEntry objdirentry = new DirectoryEntry(strrootdse);
objsearch.Filter = "(& (mailnickname=*)objectClass=user))";
objsearch.SearchScope = System.DirectoryServices.SearchScope.Subtree;
objsearch.PropertiesToLoad.Add("cn");
objsearch.PropertyNamesOnly = true ;
objsearch.Sort.Direction = System.DirectoryServices.SortDirection.Ascending;
objsearch.Sort.PropertyName = "cn";
SearchResultCollection colresults = objsearch.FindAll() ;
ArrayList arrGal = new ArrayList();
foreach(SearchResult objresult in colresults){
arrGal.Add(objresult.GetDirectoryEntry().Properties["cn"].Value);
}
objsearch.Dispose(); return arrGal ;}

Unfortunately, I noticed that it took quite a long time to retrieve more then 3000 usernames and e-mail addresses from AD. When you take a look at the documentation on MSDN about SearchResult.GetDirectoryEntry() it actually says that it can be slow. You should only need to call the GetDirectoryEntry method when you need to do updates, when you merely want to access/read properties - there are some things you should consider to optimize performance:

  • Only load the properties, you need to use through PropertiesToLoad – if you need to access them directly change PropertyNamesOnly to false. Otherwise you will get nothing back when using the Properties collection directly to retrieve the values.
  • Use this code instead to retrieve the property – objResult.Properties[“cn”][0]- this will work a lot faster
  • If you need to retrieve more then 1000 records back from Active Directory – make sure that you specify the PageSize as well - thank you Michael for this posting – DirectorySearcher.FindAll() should have pagesize=1000

So the right way to write it, would be :

public ArrayList returngal(){
DirectorySearcher objsearch = new DirectorySearcher();
string strrootdse = objsearch.SearchRoot.Path ; DirectoryEntry objdirentry = new DirectoryEntry(strrootdse);
objsearch.Filter = "(& (mailnickname=*)(objectClass=user))";
objsearch.SearchScope = System.DirectoryServices.SearchScope.Subtree;
objsearch.PropertiesToLoad.Add("cn");
objsearch.PropertyNamesOnly = false ;
objsearch.Sort.Direction = System.DirectoryServices.SortDirection.Ascending;
objsearch.Sort.PropertyName = "cn";
objSearch.PageSize = 5000;

SearchResultCollection colresults = objsearch.FindAll() ;
ArrayList arrGal = new ArrayList();
foreach(SearchResult objresult in colresults){
arrGal.Add(objResult.Properties[“cn”][0]);

}
objsearch.Dispose();
return arrGal ;
}

3 comments:

Anonymous said...

This post was very helpful to me as I was struggling to figure out why accounts that I knew existed weren't being displayed. So simple yet so frustrating. Thanks for your post.

Anonymous said...

Hi,
This is a great post. Can u tell me how to select groups from AD to add to a SharePoint site group?To be specific I want add a group in AD as user to a site group...all through code...with a .Net interface. Is this possible? Pls help me

Anonymous said...

hi,

i am trying to access users from a user control but getting an exception "An operations error occurred" at FindAll()

Can somebody please help?

Thanks
manoranjan