Bookmark and Share BitCoin Donate: 13t8gAWVpHP2ddxMp88d1NFpZjnFJC6UwK

Active Directory C# example code

Table of Contents

Introduction

When it comes to programmatically accessing Microsoft's Active Directory a lot of people seem to have quite a difficult time tying all the pieces together to accomplish exactly what they want to. There are so many technologies available for communicating with LDAP that many programmers end up with a mix between COM+ ADSI calls and .NET class calls mixed into their code. ADSI code is so difficult to understand and follow that the creator of that code usually owns it for the entirety of it's lifecycle since no one else wants to support it.

This article attempts to tie together the most commonly used elements involved in Active Directory Management in the simplest, most clean manner possible. I interact with Active Directory in nearly all of my applications (web & forms) and I have had to solve a lot of integration issues for many customers. When I was starting out with this technology I had a lot of growing pains so this is an attempt to help those programmers who may have a need to interact with the Directory but do not want to have to become experts in the issue. However, certain rudimentary knowledge and concepts are required in order to utilize the code. You must be familiar with such terms as: distinguishedName, ldap paths, fully qualified domain names, object attributes (single string & multi-string), and general knowledge of ldap schemas.

Background

There is a great collection of sample code available on MSDN's website for the v1.1 System.DirectoryServices assembly but there seems to be a void when it comes to the new functionality available in the v2.0 System.DirectoryServices.ActiveDirectory assembly. Since this article's original publishing, Generics have gained widespread acceptance and I encourage anyone borrowing from this resource to replace the archaic ArrayList collections with List<T> or appropriate generic collections.

Points of Concern

In order to communicate with Active Directory one must take into account network security, business rules, and technological constraints. If you're using Active Directory code from an ASP.NET page you must ensure that the code has the appropriate level of permission to access and interact with the directory. For development purposes or proof of concept you can enable impersonation at the ASP.NET level (in web.config) and the IIS level and if the IIS server and the directory domain controller reside on the same machine this will work. However, if these entities are not co-located on the same server (as they never are in production) you can wrap the code around an impersonation class (such as the Zeta Impersonator which will execute the Directory calls under the token of the impersonated user. It's strongly recommended that you do not do this for security reasons unless absolutely necessary.. The authorized method for granting the ASP.NET application permission to the directory is by way of either a privileged IIS Application Pool running under the identity of a service account or by way of a COM+ entity running under the identity of a service account.

If you plan on running this code from a desktop assembly then you're going to want to ensure that your machine is attached to a domain and can communicate with that domain. The impersonation is not necessary if the user running the code has sufficient privileges on the domain.

Running Code in Batch Processes

It is also important to note that if you plan on running this code from an ASP.NET page in batch, ASP.NET will time out on you if you try to run batch processes from it's primary thread. There are several things to consider in this scenario but be aware that for example, if you're creating x number of accounts through an ASP.NET application (or performing any batch operation in general) that you must plan to use queues, a back-end scheduler, or some other mechanism outside the scope of the page itself to prevent timing out during your processes. As with any ASPNET design, it's never a good idea to use ASPNET itself for anything but the "View" part of the solution. The best architecture would queue tasks into a SQL database or something to that effect and then a back-end windows service or similar application would pick up the tasking and perform the actual Directory operations.

This is typically how I engineer Active Directory management solutions for customers.

A Note on Method Parameters

You will notice that most of the methods require the same parameters. Rather than identify each time I will outline them now:

  • friendlyDomainName: the non qualified domain name (contoso - NOT contoso.com)
  • ldapDomain: the fully qualified domain such as contoso.com or dc=contoso,dc=com
  • objectPath: the fully qualified path to the object: CN=user, OU=USERS, DC=contoso, DC=com(same as objectDn)
  • objectDn: the distinguishedName of the object: CN=group, OU=GROUPS, DC=contoso, DC=com
  • userDn: the distinguishedName of the user: CN=user, OU=USERS, DC=contoso, DC=com
  • groupDn: the distinguishedName of the group: CN=group,OU=GROUPS,DC=contoso,DC=com

A Note on System.DirectoryServices.DirectoryEntry

You'll notice in all the samples that we're binding directly to the directoryEntry and not specifying a server or credentials. If you do not want to use an impersonation class you can send credentials directly into the DirectoryEntry constructor. The impersonation class is helpful for those times when you want to use a static method and don't want to go through the trouble of creating a DirectoryContext object to hold these details. Likewise you may want to target a specific domain controller.

Target Specific Domain Controllers or Credentials

Everywhere in the code that you see: LDAP://you can replace with LDAP://MyDomainControllerNameOrIpAddress as well as everywhere you see a DirectoryEntry class being constructed you can send in specific credentials as well. This is especially helpful if you need to work on an Active Directory for which your machine is not a member of it's forest or domain or you want to target a DC to make the changes to.