Using Active Directory in
Using Active Directory in
in .NET
By Paul D. Sheriff
Published in: CODE Magazine: 2013 - November/December
Last updated: January 3, 2022
Share
Download File
Download Code
Syntax Highlight Theme:
Published in:
Filed under:
.NET 2.0
.NET 3.0
.NET 3.5
.NET 4.0
.NET Assemblies
.NET Framework
C#
Advertisement:
Sometimes your .NET applications need to interact with Microsoft Active Directory
(AD) to authenticate users, get a list of users, retrieve groups, or determine which
users are within which AD groups. There are a few different approaches you can
use to retrieve information from your AD database within your domain.
One approach is to utilize the Lightweight Directory Access Protocol (LDAP) using
the DirectoryEntry and DirectorySearch classes under
the System.DirectoryServices namespace. Another approach is to use the
complete set of class wrappers around AD under
the System.DirectoryServices.AccountManagement namespace.
In this article, you will learn to use LDAP queries to retrieve information from your
AD database. The LDAP classes are much faster and allow you to get at almost all
of AD, whereas the wrapper classes only allow you to get at Users, Groups, and
Computer objects in AD. You will find that
the DirectoryEntry and DirectorySearcher objects are faster than the objects in
the System.DirectoryServices.AccountManagement namespace.
Advertisement
A few definitions are in order before we get into the actual code. First off, AD is a
database-based system that provides authentication, directory, policy, and other
services in a Microsoft Windows environment. LDAP is a language for querying and
modifying items within a directory service like AD database. It is important to note
that LDAP is a standard language used to query any kind of directory service. AD is
a Microsoft proprietary implementation of a directory service and, as such, has
some custom extensions on top of the LDAP standard language.
LDAP://DC=|SERVER NAME|[,DC=|EXTENSION|]
The connection string for a domain named XYZ.NET looks like the following:
LDAP://DC=XYZ,DC=net
Instead of having to know your actual domain name, you can use the following
generic code to query the LDAP server for the connection string.
LDAP://DC=pdsa,DC=net
SearchResultCollection results;
DirectorySearcher ds = null;
DirectoryEntry de = new
DirectoryEntry(GetCurrentDomainPath());
ds = new DirectorySearcher(de);
ds.Filter = "(&(objectCategory=User)(objectClass=person))";
results = ds.FindAll();
Debug.WriteLine(sr.Properties["name"][0].ToString());
What is interesting in Listing 1 is that you reference the name property using [0] .
You would think that there can only be one name, and you are correct. However,
because SearchResult is a generic object that could contain any type of AD object,
each of the properties could have more than one value. For instance, if you
retrieve a Group object from AD, one of the properties members contains an array of
member names that make up that group. Each property you retrieve needs to use
the index of 0 , or if that property is a group, you can loop through that property's
array by incrementing the index number until you reach the end of the array.
SearchResultCollection results;
DirectorySearcher ds = null;
ds = new DirectorySearcher(de);
// Full Name
ds.PropertiesToLoad.Add("name");
// Email Address
ds.PropertiesToLoad.Add("mail");
// First Name
ds.PropertiesToLoad.Add("givenname");
ds.PropertiesToLoad.Add("sn");
// Login Name
ds.PropertiesToLoad.Add("userPrincipalName");
// Distinguished Name
ds.PropertiesToLoad.Add("distinguishedName");
ds.Filter = "(&(objectCategory=User)(objectClass=person))";
results = ds.FindAll();
if (sr.Properties["name"].Count > 0)
Debug.WriteLine(sr.Properties["name"][0].ToString());
if (sr.Properties["mail"].Count > 0)
Debug.WriteLine(sr.Properties["mail"][0].ToString());
if (sr.Properties["givenname"].Count > 0)
Debug.WriteLine(sr.Properties["givenname"][0].ToString());
if (sr.Properties["sn"].Count > 0)
Debug.WriteLine(sr.Properties["sn"][0].ToString());
if (sr.Properties["userPrincipalName"].Count > 0)
Debug.WriteLine(sr.Properties["userPrincipalName"]
[0].ToString());
if (sr.Properties["distinguishedName"].Count > 0)
Debug.WriteLine(sr.Properties["distinguishedName"]
[0].ToString());
An additional property you might find useful is distinguishedName . This gives you
the full LDAP query for that particular user. This LDAP query looks similar to this.
CN=Person,CN=Bruce Jones,DC=XZY,DC=net
Notice the “if” statement in the code in Listing 2 prior to displaying any of the
properties. The reason for this is that these properties are optional within AD and
if you don't perform the check, you could get a null reference exception. You
don't need to put an if statement around the name
and distinguishedName properties because these will always be there, but you
might want to keep things consistent.
DirectorySearcher ds = null;
ds = new DirectorySearcher(de);
// Full Name
ds.PropertiesToLoad.Add("name");
// Email Address
ds.PropertiesToLoad.Add("mail");
// First Name
ds.PropertiesToLoad.Add("givenname");
ds.PropertiesToLoad.Add("sn");
// Login Name
ds.PropertiesToLoad.Add("userPrincipalName");
// Distinguished Name
ds.PropertiesToLoad.Add("distinguishedName");
return ds;
return ret;
}
}
The extension method can replace the code with all of the “if” statements to look
like the following:
SearchResultCollection results;
DirectorySearcher ds = null;
ds = BuildUserSearcher(de);
ds.Filter = "(&(objectCategory=User)(objectClass=person)(name=" +
userName + "*))";
results = ds.FindAll();
Debug.WriteLine(sr.GetPropertyValue("name"));
Debug.WriteLine(sr.GetPropertyValue("mail"));
Debug.WriteLine(sr.GetPropertyValue("givenname"));
Debug.WriteLine(sr.GetPropertyValue("sn"));
Debug.WriteLine(sr.GetPropertyValue("userPrincipalName"));
Debug.WriteLine(sr.GetPropertyValue("distinguishedName"));
DirectorySearcher ds = null;
SearchResult sr;
ds = BuildUserSearcher(de);
ds.Filter = "(&(objectCategory=User)(objectClass=person)(name=" +
userName + "))";
sr = ds.FindOne();
if (sr != null)
Debug.WriteLine(sr.GetPropertyValue("name"));
Debug.WriteLine(sr.GetPropertyValue("mail"));
Debug.WriteLine(sr.GetPropertyValue("givenname"));
Debug.WriteLine(sr.GetPropertyValue("sn"));
Debug.WriteLine(sr.GetPropertyValue("userPrincipalName"));
Debug.WriteLine(sr.GetPropertyValue("distinguishedName"));
SearchResultCollection results;
DirectorySearcher ds = null;
ds = new DirectorySearcher(de);
// Sort by name
ds.PropertiesToLoad.Add("name");
ds.PropertiesToLoad.Add("memberof");
ds.PropertiesToLoad.Add("member");
ds.Filter = "(&(objectCategory=Group))";
results = ds.FindAll();
if (sr.Properties["name"].Count > 0)
Debug.WriteLine(sr.Properties["name"][0].ToString());
if (sr.Properties["memberof"].Count > 0)
if (sr.Properties["member"].Count > 0)
Debug.WriteLine(" Members");
The code in Listing 6 shows one of the features of the SearchResult property that
I discussed earlier: the ability for a property to contain an array of additional
information. A group can be a member of another group and a group can contain
members. Specify whether you wish to retrieve these additional properties by
adding them to the PropertiesToLoad property just like you did for retrieving
additional user properties. After performing the FindAll method, all the data is
retrieved and all you have to do is to check to see if there is data within the
memberof and member arrays. Loop though the data and display all of the groups
of which this group is a member and the members of this group.
Figure 1: Create a login screen in WPF and use the AD objects to authenticate.
password)
userName, password);
results = dsearch.FindOne();
ret = true;
catch
ret = false;
return ret;
In the login window creates the following code under the Click event procedure
of the Login button.
win.Owner = this;
win.ShowDialog();
if (win.DialogResult.HasValue && win.DialogResult.Value)
MessageBox.Show("User Logged In");
else
MessageBox.Show("User NOT Logged In");
}
Because this code is called from another window within your WPF application, you
set the owner of the login screen to the current window. Call
the ShowDialog method on the login screen to have the login form displayed
modally. After the user clicks on one of the two buttons, you need to check to see
what the DialogResult property was set to. The DialogResult property is a
nullable type, and thus you first need to check to see if the value has been set.
After retrieving the result, you can now perform whatever code is appropriate for
your application.
Summary
In this article, you learned how to query Active Directory to retrieve users, groups
and even to authenticate a user. With just a few classes and some basic LDAP
queries you can quickly retrieve information from your AD database. There is
much more you can do with LDAP queries, such as adding, editing, and deleting
information in your AD. I'll leave that up to you to explore these additional topics.
You can find many blog posts and articles on the Web that discuss how to perform
these actions on AD.