The .NET Developer's Guide to Directory Services Programming

Joe Kaplan, Ryan Dunn

Mentioned 18

The first book on programming to directory services using .NET, one of the least-understood aspects of .NET application development.

More on Amazon.com

Mentioned in questions and answers.

I'm using the Active Directory Explorer from Mark Russinovich. It is a great tool.

I'm using it to navigate active directory to make sure my program that uses DirectorySearcher from .NET returns correct data.

Something happens though, when I try to search inside my program with DirectorySearcher for objectGUID, if I pass in the actual GUID as a string it doesn't return anything, where as if I use Active Directory Explorer, when I add

objectGuid with value f8d764ff-9a6a-418e-a641-b6f99661a8d5, its search clause becomes: (objectGUID=\FFd\D7\F8j\9A\8EA\A6A\B6\F9\96a\A8\D5*)

How do I do this for directorySearcher in my program, I'm guessign it's an octet string thing, but I can't figure it out.

The forums accompanying the excellent The .NET Developer's Guide to Directory Services Programming (Joe Kaplan / Ryan Dunn) is an excellent source for information like this.

Check out this thread here entitled Find the object using objectGuid property, which shows how you can convert a "regular" GUID to the S.DS "OctetString" format.

internal string ConvertGuidToOctetString(string objectGuid)
{
   System.Guid guid = new Guid(objectGuid);
   byte[] byteGuid = guid.ToByteArray();

   string queryGuid = "";

   foreach (byte b in byteGuid)
   {
       queryGuid += @"\" + b.ToString("x2");
   }

   return queryGuid; 
}

This could be slightly optimized by using a StringBuilder instead of consecutively concatenating together a string - but it seems fairly straightforward otherwise.

Hope this helps.

Marc

I have an interesting problem, I am writing a password management webpage/service and I am trying to find a way to determine when a user's password is going to expire so I can manually reset their other passwords with it and send out an email, etc.

The problem I'm having is that when trying to loop through my users I'm getting the bulk of them not having a pwdlastset attribute so I can't determine when it's going to expire.

So I guess I am looking for ideas on a good way to check for when a user's password is going to expire aside from using the pwdlastset property and calculating the time left.

Thanks a bunch.

It's actually quite a bit more complicated than you might think at first...

  • in order to know how long a password can be valid, you need to read a "domain policy" and find out that way

Then:

  • if the user has the "UF_DONT_EXPIRE_PASSWD" flag set in his "userAccountControl", his password will never expire
  • if the "pwdLastSet" value (a "ADSLargeInteger" or Int64 value, which is rather tricky to read in the first place) is 0, the user will have to change his password the next time he logs on
  • if the "pwdLastSet" value is -1, the password has never been set
  • only if none of the above are true, then the "pwdLastSet" value contains the date when the password was last set, to which you can add the "MaxPasswordAge" from the domain policy, and this will give you the date when the user's password is going to expire

Phew! Did you think it would be this tricky? :-)

Marc

PS: If you're serious about .NET based AD programming, you ought to have this book:

DevGuide

The .NET Developer's Guide to Directory Services Programming

The book contains all the goodies like determining user's password expiration dates, determining user account lockout state and much much more - highly recommended! Joe and Ryan did an outstanding job getting all this information together and explaining it so that even an average Joe programmer like myself can understand it :-)

I have a .csv file with EmployeeNumber, TelephoneNumber, IPPhone Number listed in a text file I need a way to loop thru all the records in the text file and modify the 2 phone attributes in LDAP please help. This is totally frustrating

If you're using .NET 3.5 (or you can update to it), check out the System.DirectoryServices.AccountManagement namespace - makes a lot of things a lot easier.

Read up on it: Managing Directory Security Principals in the .NET Framework 3.5 and check out all the properties surfaced by the new UserPrincipal class in .NET 3.5.

The other place I'd recommend is Richard Mueller's web site - he has lots of Excel sheets which show all the AD / LDAP attributes, where on the interactive tools you'll find those, and so forth. Highly useful!

Combine those two resources, and you should be able to do whatever it is you need to do!

Update: if you cannot update to .NET 3.5 (which is really just like a service pack on top of .NET 2....), you would have to do the following steps:

  • import the CSV into a List<CSVRecord> - I'd use the free FileHelpers library to do that; your CSVRecord would hold the three fields in your CSV file
  • create a DirectorySearcher class based on your search root (your domain or a sub-container thereof); find the correct LDAP search filter to find your user by EmployeeId

  • loop over the entries in your list, and for each entry

    • search the directory for that user
    • if found: grab the DirectoryEntry from your SearchResult and update the two attributes
    • call .CommitChanges() on that DirectoryEntry

I don't think there's any other way, really, to do this - there's no magic way to select all users at once, or update them all at once.

Update #2:
Here are some resources you can check out:

and the ultimate book on the subject:

Joe Kaplan / Ryan Dunn: The .NET Developer's Guide to Directory Services Programming

alt text

is there a way to find and update the contacts in Active Directory? I'm building a sample C# .NET application to achieve this task. I would appreciate any code.

Of course, you can do it in System.DirectoryServices.

I think what you really need is to learn how to use System.DirectoryServices. If you don't have a good book yet, I recommend this one.

It's not that hard, really. You just need to master two classes, DirectoryEntry and DirectorySearcher. DirectoryEntry is representing a LDAP object on the LDAP server. Assuming you have sufficient permissions, you can make changes on any LDAP object, including the contact object using DirectoryEntry. Each LDAP object has a number of attributes. TWo important attributes you need to know are objectCategory and objectClass. For the contact object, the objectCategory should be person and objectClass should be contact. You may also like to check the "targetAddress" attribute on the contact object, which stores the email address. There are a bunch of Exchange extended attributes on contact object. You probably like to check each of them one by one. To browse the objects on LDAP server, you can use a tool like AD Explorer or ADSI Edit

To do a search, you need to provider four things to DirectorySearcher.

  1. Search root
  2. LDAP search filter
  3. Search Scope
  4. Returned attributes

If your machine is already joined to a domain and you are logging in as a domain user, here is a sample on how to list out all contacts in your domain.

DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
string domainContext = rootDSE.Properties["defaultNamingContext"].Value as string;
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://" + domainContext);
using (DirectorySearcher searcher = new DirectorySearcher(
    searchRoot, 
    "(&(objectCategory=person)(objectClass=contact))", 
    new string[] {"targetAddress"}, 
    SearchScope.Subtree))
{
    foreach (SearchResult result in searcher.FindAll())
    {
        foreach (string addr in result.Properties["targetAddress"])
        {        
           Console.WriteLine(addr);
        }
        Console.WriteLine(result.Path);
    }
}

The first three lines are to help you to find the correct LDAP path to the root of your domain. It works only if you are logging in as a domain user. If you know the correct LDAP path of your domain, you can just feed it into DirectoryEntry directly.

I put all four parameters into DirectorySearcher. When you are getting familiar with Directory Services programming, you can skip some of them and .NET will provide a default value for you.

The result returned from DiectorySearcher is SearchResult. Note that SearchResult always return a collection of objects to you even though targetAddress is not a multivalue attribute. It's because some of the attributes on the LDAP object may be multi-value.

Another important information you can get from SearchResult is the Path. You can create a DirectoryEntry object using this Path later. To update your contact object, you need to use its Properties method and CommitChanges method.

DirectoryEntry de = new DirectoryEntry(result.Path);
de.Properties["targetAddress"].Value = "SMTP:jane.doe@foo.bar";
de.CommitChanges();

Finally, you can actually easily find a lot of online tutorial on both DirectorySearcher and DirectoryEntry. Try google it.

I've been thrust into the deep end with Active Directory (I'm a web developer, go fig) I have a user that I've changed first/last name on but the Full Name hasn't changed which is causing issues with sharing off a BCM database. How do I refresh it so the Full Name is updated.

I have no idea how AD works but for some reason the higher ups have decided it's my job.

Any help would be really appreciated.

Are you on .NET 3.5 ? If so, go check out this MSDN article: Managing Directory Security Principals in the .NET Framework 3.5.

Check out this CodeProject article: Howto: (Almost) Everything In Active Directory via C#

Check out this list of Code Samples for System.DirectoryServices on MSDN.

If you're serious about Active Directory Programming in C# or VB.NET, go buy this book:

The .NET Developer's Guide to Directory Services Programming

alt text

Updating the "full name" (really: DisplayName) should be as easy as (on .NET 3.5):

PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "yourDomain");

UserPrincipal up = UserPrincipal.FindByIdentity(ctx, "(your user name)");

if (up != null)  // we found the user
{
   up.DisplayName = "new display name for your user";
   up.Save();
}

That's it! :-)

Mind you : you need to pass in the NetBIOS domain name (e.g. "MICROSOFT") - not a DNS-style name (microsoft.com) to the constructor of the PrincipalContext.

Hope this helps!

Marc

UPDATE for .NET 2.0:

Here's the code if you're running on .NET 2.0 and need to update the "displayName" for a user, given his "SAMAccountName" (his username without the domain, basically):

// set the root for the search
DirectoryEntry root = new DirectoryEntry("LDAP://dc=yourcompany,dc=com");

// searcher to find user in question
DirectorySearcher ds = new DirectorySearcher(root);

// set options
ds.SearchScope = SearchScope.Subtree;
ds.Filter = string.Format("(&(sAMAccountName={0})(objectCategory=Person))", yourUserName);

// do we find anyone by that name??
SearchResult result = ds.FindOne();

if (result != null)
{
    // if yes - retrieve the full DirectoryEntry for that user
    DirectoryEntry userEntry = result.GetDirectoryEntry();

    // set the "displayName" property to the new value
    userEntry.Properties["displayName"].Value = yourNewUserFullName;

    // save changes back to AD store
    userEntry.CommitChanges();
}

Could anybody help me to list Some Good Sites that are describing about Complete AD Operations. thanks in advance.

I am a Database guy and dotnet novice who needs help with below UseCase

I am using LINQ to populate the DB but I am not sure how to insert/update ActiveDirectory using LINQ any sample code for doing that.

Most code samples on Google show how to query ActiveDirectory but not CRUD operations

There's a "Linq-to-AD" project on CodePlex:

http://www.codeplex.com/LINQtoAD

That should hopefully do what you're looking for! So far, I've only ever seen it used to query the AD, however - don't know if it helps with inserting data.

If that doesn't help - check out these other resources:

If you're on .NET 3.5, go check out this MSDN article: Managing Directory Security Principals in the .NET Framework 3.5.

Otherwise check out this CodeProject article: Howto: (Almost) Everything In Active Directory via C#

Check out this list of Code Samples for System.DirectoryServices on MSDN.

If you're serious about Active Directory Programming in C# or VB.NET, go buy this book:

The .NET Developer's Guide to Directory Services Programming

alt text

Hope this helps!

Marc

I'd like to write a .net program to update active directory data in an existing field, or extend the schema to add a new field.

Does anyone know the best way to go about this?

To update a field, you new up a DirectoryEntry for the object you want to update, set the property (look in the Properties collection) to its new value, then call CommitChanges() to save the changes for good. And watch out for multi-valued properties.

I don't know if I would recommend extending the schema programmatically though. I'd rather play it safe and have the IT admins use the Active Directory Schema MMC snap-in or ldifde instead. Anyhow, Microsoft has a sample on schema programming here And if you must, you should practice with ADAM no matter whichever way you go.

IMHO, this is the definitive book on AD programming using .NET: The .NET Developer's Guide to Directory Services Programming

How can I get a list of computers and their properties from Active Directory using VB.Net and Visual Studio 2008?

Working with Active Directory, even with the help of the DirectorySearcher class, is no mean feat. It is not a task to be taken lightly. If you haven't done it before, I'd read up on it before attempting to do so.

I highly recommend The .NET Developer's Guide to Directory Services Programming.

That being said, the classes in the DirectoryServices namespace do some of the work for you, but certainly nowhere near enough of it.

I am writing code to track changes in an AD instance using Active Directory DirSync.

I want to be able to write automated tests for this code. Rather than setting up a full AD instance, with all the accompanying complexity, it seemed like a good idea to me to run my tests against Active Directory Lightweight Directory Services. From that page:

Because AD LDS uses the same programming model and provides virtually the same administration experience as AD DS, it can be a good fit for developers who are staging and testing various Active Directory-integrated applications.

I have run my code against our real AD instance, and it does indeed track changes. However, when I run it against the AD LDS instance I created, the DirSync search always returns 0 results.

What I want to know, but have failed to find out so far from documentation, is whether ADLDS actually supports DirSync. If it does, then it will be worth me investing time to figure out what I am doing wrong. But if it simply doesn't support DirSync that will be a waste of time.

Citing sources for your answer either way would be much appreciated, but at the end of the day I'd rather have an answer with no sources that no answer at all.

ADAM did. I haven't been able to verify if AD LDS does.

If you're doing a lot of work in the System.DirectoryServices space, I recommend The .NET Developer's Guide to Directory Services Programming. It's worth every penny and is even available on Kindle. If you check out pp.172-173, there are some possible issues, including what client you're using and your access rights, where they note that "By default [..] no ADAM security principal will have the DS-Replication-Get-Changes control access right by default. This will have to be added to a group or user using a tool such as ADAM's version of dsacls.exe. (Note, you should've had the same issue against AD but there you would just have used the UI to grant the access right. Or more likely, your domain admins did it for you?). There is sample code on p.174.

I've found many posts on how to return the current user's AD information in an InfoPath Form - but I require a list of AD Users.

Furthermore, this is to be accomplished in a browser-enabled form accessed within a MOSS website.

Is there an AD webservice that can be used to return this info?

No, there' no web service available for AD out of the box that I'm aware of. However, it would be relatively simple to create one yourself.

There's a number of places to get started, if you're interested:

Book on .NET Directory Services Programming

Unfortunately, nothing is really "ready-made" - just plug it in and use it :-(

Marc

My company uses ActiveDirectory, and naturally the IT department wants to maintain control over it and not give control to other users. I'm developing an ASP.NET app (for internal use only) using an SQL Server 2008 database.

My question is, how can I BEST use the .NET namespaces and SQL Server to manage access to the app within the organization at the application (or possibly DB) level? I would like the user to be authorized based on their network username as provided by ActiveDirectory.

On a side note, I would also like to access their AD contact information.

From my understanding I can use the ActiveDirectoryMembershipProvider class or Domain Services in the System.DirectoryServices namespace. There's also LDAP which apparently is another possibility. I'm having a hard time making sense of it all, and much less which is the best option and how to implement it. Can anyone provide me with some direction and possibly some simple sample code?

UPDATE: Sorry, I forgot to mention I'm using VB.NET as my code source as it's company standard.

Much obliged! ;)

Here's a quick code snippet that started me on my never ending journey with Active Directory and ASP.NET. It's from a little test page that I put a text box and plugged in a LAN ID and it returns all the AD fields available.

    Protected Sub btnSearchUserDetails_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSearchUserDetails.Click
    Dim Entry1 As New System.DirectoryServices.DirectoryEntry("LDAP://DC=ent,DC=foo,DC=bar,DC=corp", "yourID", "yourPassword")
    Dim search As New DirectorySearcher(Entry1)
    search.Filter = [String].Format("(SAMAccountName={0})", txtSearchUser.Text)

    Dim result As SearchResult = search.FindOne()
    Dim user As DirectoryEntry = result.GetDirectoryEntry()
    PrintDirectoryEntryProperties(user)
    End Sub

Private Sub PrintDirectoryEntryProperties(ByVal entry As System.DirectoryServices.DirectoryEntry)


    'loop through all the properties and get the key for each prop


    lblPropList.Text = "<table>"
    For Each Key As String In entry.Properties.PropertyNames
        Dim sPropertyValues As String = [String].Empty
        'now loop through all the values in the property;
        'can be a multi-value property
        For Each Value As Object In entry.Properties(Key)
            sPropertyValues += Convert.ToString(Value) + ";<br>"
        Next
        'cut off the separator at the end of the value list
        sPropertyValues = sPropertyValues.Substring(0, sPropertyValues.Length - 5)
        'now add the property info to the property list

            lblPropList.Text += "<tr><td>" & Key & "</td><td>" & sPropertyValues & "</td></tr>"

    Next
    lblPropList.Text += "</table>"

End Sub

To get the AD login ID of the currently authenticated user Request.ServerVariables("LOGON_USER") and Httpcontext.Current.User.Identity.Name are going to be your friends. Keep in mind that the LOGON_USER variable is not populated if you use the Allow Anonymous security to access the ASP page.

I'll go back through some of my notes and try to find some of the resources that I used that ended up being the most helpful for me. Off the top of my head, I can tell you that the book "The .NET Developer's Guide to Directory Services Programming" (Amazon) was used daily by me.

Our user store is an LDAP server called eDirectory. How do you change user passwords using System.DirectoryServices.Protocols?

There is a code example for both user changing password and administrative password change using System.DirectoryServices.Protocols in the book the .net developer's guide to directory services programming. I assume that I can't paste the code example here for copyright reasons but I can recommend buying the book if you are interested working with System.DirectoryServices.Protocols and System.DirectoryServices.

How can I access AD from machines not on the domain. I have an app which needs to run on some machines which are part of the domain and some which are not.

I assume I have to present a valid login token from the machine which is not in the domain, however the username and password must be.

What book is recommended for .net and AD

The best .NET programming book for Active Directory / LDAP in my opinion is The .NET Developer's Guide to Directory Services Programming by Joe Kaplan and Ryan Dunn. Excellent read, very broad, very deep, very complete. Highly recommended!

Marc

I have the following code inside my asp.net mvc web application :-

PrincipalContext(ContextType.Domain, ADServerName, "OU=ComanyNAMe,OU=Users", "username", "password"))

I know that the second parameter represents the AD server name , search,, and the username and password. But what is ContextType.Domain, and from where its value is being initiated ? Thnaks

It's an enumeration from System.DirectoryServices.AccountManagement namespace. It specifies the type of store to which the principal belongs, according to MSDN

To create a specific principal instance (PrincipalContext) you have to specify its first parameter that gives meaning to other params (name, container etc.). Without such discriminator the constructor would not know what refers to. As documentation states you can refer to:

  • ApplicationDirectory - The application directory store. This represents the AD LDS store.
  • Domain - The domain store. This represents the AD DS store.
  • Machine - The computer store. This represents the SAM store.

You can look at an example of managing active directory using PrincipalContext here. Or for more comprehensive explanation you can read this book.

I need to fetch account details which are newly created in active directory less than 30 mins. I have to do this periodically.

I am thinking to use search filters for getting these details. But i have no idea how to use search filters while searching in AD.

Can any one tell me how can i get details of new accounts.

Thanks,
Narendra

If you're familiar with .NET you could write a simple C# or VB application and leverage the Directory Services namespace that is provided as a .NET library.

Joe Kaplan and Ryan Dunn wrote a good book covering Directory Services called The .NET Developer's Guide to Directory Services Programming and they have a compainion website with samples from the book that you can leverage called Directory Programming .NET

I've spent a couple of days pulling my hair out with various snippets of code and methods so I'm going to start afresh and make this an open question as I'm not experienced enough with vb to have a preference how I accomplish the task (although the simpler and more efficient the better, obviously).

I am running my vb.net framework 3.5 application on a workstation in a Windows AD domain and I want to query AD and find the OU path or Distinguished Name of a computer for which I have the hostname. How can I do this?

Follow this approach:

  1. Use LDP.exe (comes with Windows) or some other LDAP tool to determine your LDAP filter. When you've got a working LDAP filter, you're half-way there. What are you using?

  2. Then start fiddling in C# or VB.NET. What code have you tried? I'm a C#-er. I can probably help but it would be quicker if I had something to start with.

  3. Buy this book: The .NET Developer's Guide to Directory Services Programming. It's worth every penny. It now appears to be available on Kindle so you can be reading it within minutes with the Kindle app. By the time you've finished it, you'll be answering questions on this site, instead of asking them. :-)

Passthrough authentication in my web server application written in C# is performing extremely poorly; successful login events take as long as 10 or 15 seconds using the System.DirectoryServices.AccountManagmeent API.

I would like to switch to using System.DirectoryServices.Protocols and fast binding as described in this MSDN article Using Fast Bind, but it is bereft of any details or code samples.

Can you point me to or provide examples of .NET code doing fast bind user authentication with s.ds.p? I have been very unsuccessful googling.

Joe Kaplan's book .NET Developer's Guide to Directory Services Programming has some examples as well, that can be found here.