in

ASP.NET Weblogs

Brian Desmond's Blog

Inherits Network.Admin
Implements IOneManBand

System.DirectoryServices & CDOEXM

Well, I haven't posted here recently because I've been a busy sysadmin & haven't had time to touch my copy of Visual Studio.Net. A new project, writing an Intranet for Payton's teachers and students has cropped up, and, I've been doing some new stuff.

Namely, I've gotten to learn the joys of programming an Exchange Server with .Net. It's not what I'd call joyous with good old VB6, and it isn't any better with .Net (though System.DirectoryServices is a bit easier).

I figure somebody else might find some of the stuff I've been up to a bit interesting/useful, so, I'm going to be posting code and explanations over the next week or so. I can't say precisely what I'm doing as this is getting syndicated on BrianDesmond.com, and, kids from Payton read there, and, whatever it is I'm working on is slated to be a surprise.

I write all my code for Payton in VB.Net, so, that's what the samples are going to be in. I thought I'd start off with a simple one ... how to find a user with DirectorySearcher.

There are two things that we need in order to successfully and efficiently search for our user. Number one is a search root. I keep all my user accounts under one OU in the domain, Accounts, so, that's my search root. If your accounts are under multiple OUs, you could set your search root to the domain. Lets assume they're all in/under one OU for this.

Dim searchRoot as new DirectoryEntry(“LDAP://OU=Accounts,DC=MyDomain,DC=local“)
Dim searcher as New DirectorySearcher(searchRoot)

When you define an LDAP path, the thing to remember is to go from the bottom to the top (I consider the deepest OU to be the bottom, and the topmost piece to be the end of my domain name). When you define a domain, you have to do a DC= for each subdomain. This is quite a bit, so, I keep this, and a lot of other LDAP strings in the snippets section of my VS toolbox (if you weren't aware, you can drag text onto the toolbox and it will be saved as a code snippet). A side note about LDAP paths, if you need to use a comma in the name of an element (e.g. if you wanted to access container Smith, Jane), you have to escape the comma with a \, so it'd be CD=Smith\, Jane.

Moving along, part two of using a directorysearcher object is defining an LDAP filter. LDAP Filters are actually pretty easy to write, though they take a bit of getting used to, and you have to know the names of attributes in AD (you can look up the whole AD schema in the Platform SDK). A quick explanation of how to write a filter:

The and operator is &, the or operator is |, and the not operator is !. If you want to AND a bunch of stuff together, you do (&(criteria1)(criteria2)(criteriaN)). Likewise, to or a bunch of stuff together, you do (|(criteria1)(criteria2)(criteria3)). You can also use wildcards like *. So, let's write our filter to find a specific username:

searcher.Filter = “(&(objectCategory=person)(sAMAccountName=brian))”

This filter tells the DirectorySearcher to look for objects of category Person with attribute sAMAccountName=Brian (sAMAccountName is your preWin2000 logon, aka your username). The objectCategory part isn't actually necessary, but, it speeds the search up greatly, as the DirectorySearcher doesn't even touch computers or anything else other than Person objects.

So, we've got the two major pieces done here. Just have to run the search, and do something with the result. I'm going to write the rest of the code below and explain from there:

Dim searchRoot as new DirectoryEntry(“LDAP://OU=Accounts,DC=MyDomain,DC=local“)
Dim searcher as New DirectorySearcher(searchRoot)
searcher.Filter = “(&(objectCategory=person)(sAMAccountName=brian))”

Dim result as DirectoryEntry = searcher.FindOne.GetDirectoryEntry

So, we've not retrieved the result and stored it in a DirectoryEntry object called result. If we were looking for or could possible get more than one result, we'd use the FindAll function of DirectorySearcher, and then loop through it (the FindAll function returns a collection of type SearchResultCollection, which contains SearchResult objects). This particular query guaranetees only one result as the sAMAccountName attribute must be unique to the domain. The GetDirectoryEntry method of the SearchResult type returns the underlying DirectoryEntry representing the result.

Now that we have a result, we can access the user's properties. Let's look up the user's first and last name:

Dim firstName as String = CType(result.Properties(”givenName”).Value, String)
Dim lastName as String = CType(result.Properties(”sn”).Value, String)

The first name of a user is stored in the givenName attribute, and the lastname, or surname of a user is stored in the sn attribute. These are actually LDAP specs, AD follows them. The .Value property of a DirectoryEntry property is of type object, as there are quite a few different datatypes in AD, so you're going to need to know what you're accessing, unless you use late binding.

That's just a simple System.DirectoryServices example. I'm sure there is someone out there that can benefit from it. Tomorrow (or next time), I'll post an example of how to create a contact object in AD. This is actually all leading up to something ... after the contact object has been created, we can setup email forwarding for a user's Exchange mailbox. I'm leading towards this, and after that, I'm not sure what is next - probably more CDO/AD, depends what I decide to write the code for next.

Published Dec 27 2003, 11:18 PM by bdesmond
Filed under: ,

Comments

No Comments

Leave a Comment

(required)  
(optional)
(required)  
Add