Geeks With Blogs

Mike H. - Another Geek In Need... WebLog

Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries

 

 

QUESTION

Mike,

 

I am new to AD and LDAP but have programmed the last couple of years in C#.

 

I have read your articles.  I am trying to write a program that will go in and check three columns in a User OU for each of the objects in that OU.  I need to check the sAMAccountName, EmployeeNumber and UIDNumber.  I have to make sure that the EN and the UID are the same but they must be different than the sAMAccountName.  I then must make sure that that data is different from all the other objects.

 

do you have any suggestions?  is there a way to do a Select * from LDAP here to just get those attributes from each object?

 

Thanks I appreciate any help you could provide.

 

Dean

 

 

RESPONSE

 

As I proceed, I want to clarify a little about properties and object references. Please forgive me if I seem critical in some of this – as I certainly do not intend to. Rather, I want to clarify object references in an effort to help others.

 

In AD, an OU does not share the properties EmployeeNumber or uid. However, a user object, referred to as the CN, does share these properties. So, when we’re talking about a user object, it is not the same as User OU – but is simply the user object, and is referenced by the CN= for that object. I hope this makes sense.

 

Meat and Potatoes

 

I would imagine that the real objective here is to determine how to query AD for specific properties and property values. I will focus on that for now, but if more is desired, please let me know and I will respond.

 

Foremost, the EmployeeNumber and the uid are standard properties available for user objects, and you can write to and read from these manually. They are not dynamically updated by AD – out of the box. What I mean by that is, if you have a standard deployment of AD and a typical network architecture, your AD server will not maintain these fields for you. In some organizations you may find Group Policy Objects (GPO’s) in place that do maintain specific properties within AD – but this is not very common. So, lets move forward…

 

I have an employee makeup that not only includes an AD user account (the sAMAccountName – or user login ID), but also includes a unique employeeNumber and uid (or user ID for another system perhaps). And I want to maintain these in my AD schema.

 

First, write a component that adds / updates / deletes these properties based on AD account maintenance. If you are already writing code that does basic user maintenance in AD, then you know how to read / write these additional properties.

 

OPEN QUERIES

 

Now, I have a database (forgive the reference) of users in AD that I want to query based on their employeeNumber and / or uid property settings.

 

The following assumptions are made:

 

  • You have an application that will populate the search variables needed.
  • The search variables included here are mEmpNumber and mUID.
  • Data from this example is written to a listbox control mEmpsListBox

 

Now, the fun stuff…

 

First, simply retrieve just the employeeNumber / uid I’m looking for…

private void PopulateEmployee()

{

            // Creates a new DE based on the current default context…

            // This may be different than what you need, and you would thus

            // modify the = new DirectoryEntry() to include the LDAP path

            // and relative data for the context you want to bind to…

            DirectoryEntry root = new DirectoryEntry();

 

            DirectorySearcher searcher = new DirectorySearcher(root);

            searcher.Filter = “(employeeNumber=”+mEmpNumber.ToString()+”;uid=”+mUID.ToString()+”)”;

           

            // Generally, we are going to find only one instance of the data we’re looking

            // for, but the following code can be used for multiple data…

            foreach (SearchResult searchResults in Searcher.FindAll())

            {

                        mEmpsListBox.Add(searchResults.Properties[“employeeNumber”].Value.ToString()+” – “+searchResults.Properties[“uid”].Value.ToString());

            }

}

 

The above example performs a simple LDAP query for the employeeNumber and uid properties in the AD context referenced. We did not create a context based on a specific user account (CN=), because we wanted to search based on the employee number or unique UserID in this example – so we queried only those properties in the context referenced.

 

Also, this example searches for BOTH of the properties – and will fail if both are not found together. What if we wanted a group of employees whose number may begin with a specific range? For example, we have employee numbers unique for Accounting vs. Development, and Accounting could start with something like ACCT<number> and Development with something like DEV<number>. So, we want to return all developers only.

 

private void PopulateEmployees()

{

            // Bind to our default context…

            DirectoryEntry root = new DirectoryEntry();

 

            DirectorySearcher searcher = new DirectorySearcher(root);

            searcher.Filter = “(employeeNumber=DEV*”)”;

           

            // For each item returned, populate our listbox…

            foreach (SearchResult searchResults in Searcher.FindAll())

            {

                        mEmpsListBox.Add(searchResults.Properties[“employeeNumber”].Value.ToString());

            }

}

 

Pretty neat, eh? See how we can use the wildcard reference in our search? This snipet returns all AD objects that have an employeeNumber that begins with DEV – regardless of the actual number.

 

Now, what if we want to query on all developers, and we’re a large company with several thousand developers? We’re going to run into some inherent problems with the System.DirectoryServices DirectorySearcher class object. Inherently, data returned from AD is paged and the page size in memory is fixed!!!! (I didn’t say that!!!) Yea, believe it or not, out of the box, the number of records returned is limited by this paging setup – and out of the box – you will only get the first 1,000 employees!!!! So, what to do? Let’s modify our code and stipulate only a few properties per record be returned. This 1) tells the class to handle more pages and data per page, and 2) cuts down on the amount of data returned for each employee (or AD record reference).

 

 

 

private void PopulateEmployees()

{

            // Bind to our default context…

            DirectoryEntry root = new DirectoryEntry();

 

            DirectorySearcher searcher = new DirectorySearcher(root);

            searcher.Filter = “(employeeNumber=DEV*”)”;

 

            // Narrow the number of properties and subsequent data to return…

            searcher.PropertiesToLoad.Add(“sn”);

            searcher.PropertiesToLoad.Add(“givenName”);

            searcher.PropertiesToLoad.Add(“uid”);

            searcher.PropertiesToLoad.Add(“telephoneNumber”);

            searcher.PropertiesToLoad.Add(“employeeNumber”);

 

            // Change our PageSize – NOTE: This is largely affected by the amount of memory in your server…

            searcher.PageSize = 8;

            searcher.SizeLimit = 8000;                   // With ample RAM (4GB+) this’ll give us 10’s of thousands of returns…

 

            // For each item returned, populate our listbox…

            foreach (SearchResult searchResults in Searcher.FindAll())

            {

                        mEmpsListBox.Add(searchResults.Properties[“employeeNumber”].Value.ToString()+” – “+searchResults.Properties[“givenName”].Value.ToString()+” “+searchResults.Properties[“sn”].Value.ToString+” | “+searchResults.Properties[“telephoneNumber”].Value.ToString());

            }

}

 

 

I was not going to get heavily into the DirectorySearcher class until Part 3 of my work on Directory Services development – but I wanted to take time to respond to this request, and I hope this snipet is useful. I realize that some of this is rarely documented stuff – particularly the paging issue with the DirectorySearcher. I will try to address this more thoroughly in my upcoming Parts on Directory Services Programming.

 

Finally, please forgive any typos (in case you copied/pasted and there was one).

Posted on Sunday, December 11, 2005 9:01 AM .Net Development | Back to top


Comments on this post: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
I'm just not getting this. Perhaps my LDAP path is poorly formed, though I've tried several.

I am working toward single sign-on for our intranet. My approach is to grab the server variable "auth_user" and query AD for that user, then pull the groups for a compare with rights given to applications or pages, perhaps even objects on pages.

My pages don't work. I get "System.Runtime.InteropServices.COMException: An operations error occurred." if I try
"phoneNumber = ADentry.Properties["telephoneNumber"].Value.ToString();"

Left by BillC on Dec 21, 2005 2:37 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
I've found that I have to give it my user name and password with the LDAP string even though impersonate and windows authentication are on.

Why do I always see searchResults.Properties[].Value.ToString(); when 'System.DirectoryServices.ResultPropertyValueCollection' does not contain a definition for 'Value'? Or at least thats the error I get. What gives?
Left by BillC on Dec 22, 2005 4:26 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
BillC

You may have caught me short-handed - it looks like I may have overlooked something.

Once you have a resultset, see if you can:

DirectoryEntry currentEntry = searchResults.GetDirectoryEntry() // I believe that's the proper syntax. I'm not where I can check it directly. I'll look again tonight
Left by MikeH on Dec 22, 2005 4:56 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Short handed over the holidays... imagine that ;)

I had specified my LDAP connection string like: LDAP://basename.command.directory.branch.mil ,DC=basename,DC=command,DC=directory,DC=branch,DC=mil

It didn't work but specifying just our domain name without the .command.directory... and without the DC=... did. The double hop issue also came into play.

Thanks for the response, your example was the most lucid I could find. here is the nearly final codebehind:

/*
** Will not work on Win 2k Server
**
* REQUIRED:
* - IIS: Turn on windows authentication (turn off anonymous access)
*/
using System;
using System.DirectoryServices;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.SessionState;

public partial class sessionUser : System.Web.UI.Page
{

public string domainName, logonName, fullName, phoneNumber, ADsearchFilter, ADgroups;

public void get_user()
{
string sessionID;

sessionID = HttpContext.Current.Request.ServerVariables["LOGON_USER"];
//sessionID = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
domainName = sessionID.Substring(0, sessionID.LastIndexOf("\\"));
logonName = sessionID.Substring((domainName.Length + 1), (sessionID.Length - sessionID.LastIndexOf("\\") - 1));

DirectoryEntry ADentry = new DirectoryEntry("LDAP://<domain name>", <Authorized User's Name>, <Authorized User's Password>);
DirectorySearcher ADsearch = new DirectorySearcher(ADentry);
ADsearchFilter = "sAMAccountName=" + logonName;
ADsearch.Filter = ADsearchFilter;
ADsearch.PropertiesToLoad.Add("displayName");
ADsearch.PropertiesToLoad.Add("telephoneNumber");
ADsearch.PropertiesToLoad.Add("memberOf");
SearchResult searchResults = ADsearch.FindOne();
fullName = searchResults.Properties["displayName"][0].ToString();
phoneNumber = searchResults.Properties["telephoneNumber"][0].ToString();
ADgroups = searchResults.Properties["memberOf"].Count.ToString();

/*
Authorized user above needs to have read rights.
*/

}

protected void Page_Load()
{
get_user();

}
}
Left by BillC on Dec 28, 2005 2:59 PM

# Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi,

I am looking how to query AD as well but differentiating groups (email groups, security groups), so getting a specific type of groups.

Does anyone know how to give the filter for this?
Left by Rd on Apr 11, 2007 2:07 AM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi Rd,

There are a few articles posted that do deal with querying AD for a context of data.

If you can provide a specific context - perhaps we could provide more specific exmples???
Left by MikeH on Apr 11, 2007 2:15 AM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
MikeH,

I wanted to query users in a specific OU. This is the code that I've used. When I queried, it was pulling way more information than I needed, so I used the 2nd part of the code below to pull out each users name. Hope it helps.

// Create a new Directory Entry showing the path of my group
// You may need to modify your path depending on how deep your group structure goes
DirectoryEntry adOU = new DirectoryEntry(&quot;LDAP://cn=GroupName,OU=Group Folder,OU=Group Folder,DC=siteNamme,DC=com&quot;);

// For each member in the group, display their properties.
ArrayList AL = new ArrayList();

// For each members properties, pull out only their name and add it to the array
foreach (object dn in adOU.Properties[&quot;member&quot;])
{
String adUsersStrt = dn.ToString();
// Pulls out everything after the = sign
int equalMark = adUsersStrt.IndexOf(@&quot;=&quot;);
string adUsersMid = adUsersStrt.Substring(0, equalMark);
// Deletes everything after the first comma
int baseEqualMark = adUsersStrt.IndexOf(@&quot;,&quot;, equalMark + 1);
string adUsers = adUsersStrt.Substring(equalMark + 1, baseEqualMark - equalMark - 1);
// Adds the string to the Array

AL.Add(adUsers);
}
Left by Jaga on Apr 16, 2007 10:48 AM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi Jaga,

I think there may be a simpler way to do it.

Creating your directory entry binding.

Now, create a directory searcher and to a find / findall within the scope of the OU you want. You can do this pretty straight-forward, and I think I have some sample(s) of this on this blog.

That's a lot less code and would server the purpose.

HTH's...
Left by MikeH on Apr 16, 2007 7:36 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi,

I would like to find out who is the owner/editor of a group. Based on that I would like to allow the current user to edit/update a group in AD.
Left by Faltu on May 07, 2007 10:42 AM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi Faltu,

Can you elaborate a bit more on what the objective is? I'm not sure I'm following your objective. The owner of an AD object is probably 'not' what you're looking for - in the proper sense of the technology. If you can share more of what it is you're trying to do - perhaps I can be of more help.

MikeH...
Left by MikeH on May 07, 2007 5:04 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
i am new to the magic of AD.learned a lot from forums like these.pretty impressed by it.was wondering ,if i could get a username by giving the full name.

thanks

nukken tory

Left by nuke on Aug 18, 2007 1:12 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Hi Nuke,

The CN= usually will return the 'full' name that was entered for the AD account. You can search using the CN=<fullName> and try that.

Alternatively, you can search using the property 'displayName' and include the full name there.

In AD there is also a property called just 'name' and this will contain the full name if you want to search on that property.

HTH's...

MikeH...
Left by MikeH on Aug 19, 2007 4:21 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
Looks like you forgot to set Delegation for the server you are using to impersonate.


In response to:
# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries 12/22/2005 4:26 PM BillC
I've found that I have to give it my user name and password with the LDAP string even though impersonate and windows authentication are on.

Why do I always see searchResults.Properties[].Value.ToString(); when 'System.DirectoryServices.ResultPropertyValueCollection' does not contain a definition for 'Value'? Or at least thats the error I get. What gives?
Left by David Jenkins on Feb 04, 2008 3:10 PM

# re: Custom Properties in AD , Open DirectorySearcher Queries and Large LDAP Queries
Requesting Gravatar...
hi MikeH,
i learned a lot from this post, i was also facing an issue with directory entry, but now i think it will be resolved.

thanks.
----------
Ashish
Left by ashish on Oct 10, 2008 3:55 AM

Your comment:
 (will show your gravatar)


Copyright © Michael J. Hamilton, Sr. | Powered by: GeeksWithBlogs.net