Hey, Scripting Guy! Question

Hey, Scripting Guy! Can I bind to an Active Directory account using the user’s mailNickname or their sAMAccoutName, something other than the CN?

-- MB

SpacerHey, Scripting Guy! Answer

Hey, MB. When you bind to an account in Active Directory, you need to pass GetObject the account’s ADsPath. That means you need to use a line of code similar to this:

Set objUser = GetObject(“LDAP://cn=ken myer, ou=finance, dc=fabrikam, dc=com”)

The ADsPath is actually composed of two pieces: the ADSI provider used to connect to Active Directory (LDAP://) and the distinguishedName attribute of the object you’re trying to bind to (cn=ken myer, ou=finance, dc=fabrikam, dc=com). As you can see, the common name (CN) is the first element in the distinguish name. And - for better or worse - the common name has to be the first element in the distinguished name; if it’s not, then it’s not a distinguished name.

For example, suppose you try binding to an account using the mailNickname instead:

Set objUser = GetObject(“LDAP://mailNickname=kenmyer, ou=finance, dc=fabrikam, dc=com”)

That binding string is doomed to fail: to bind directly to an object in Active Directory you need to know the object’s CN. (Actually there are some oddball exceptions; for example, you can bind to an object if you know the object’s GUID. But it’s probably safe to assume that you haven’t memorized all the GUIDs for all your users.)

But wait: don’t leave just yet. As you probably know, we Scripting Guys love to build up dramatic tension: for reasons known only to ourselves, we delight in telling people that something can’t be done, then turning right around and telling them how to do it anyway. And, to paraphrase Ronald Reagan, here we go again.

Let’s think about the situation for a moment. Why would you want to bind to an object using the mailNickname or the sAMAccountName? We’re guessing there’s one reason for that: you don’t know the user’s CN, but you do know their mailNickname or sAMAccountName. Well, why didn’t you say so? If all we have is the mailNickname we can’t directly bind to an Active Directory object. However, we can search Active Directory, find the user with that mailNickname, retrieve the user’s distinguished name (which, of course, includes the CN), and then bind to the account. The net effect is the same: we supply nothing but the mailNickname and yet we end up binding to the user account. Sweet.

Here’s a script that searches Active Directory for the user with a mailNickname of kenmyer. After finding the account the script retrieves the distinguishedName attribute for the user and then binds to the account:

On Error Resume Next

Const ADS_SCOPE_SUBTREE = 2

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 

objCommand.CommandText = _
    "SELECT distinguishedName FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user' " & _
        "AND mailNickname = 'kenmyer'" 
Set objRecordSet = objCommand.Execute

objRecordSet.MoveFirst
Do Until objRecordSet.EOF
    strDN = objRecordSet.Fields("distinguishedName").Value
    objRecordSet.MoveNext
Loop

Set objUser = GetObject("LDAP://" & strDN)
Wscript.Echo objUser.Name

We won’t explain the intricacies of searching Active Directory; if you’re looking for an explanation of what we’re doing here - and why - take a look at this month’s Tales from the Script column. For now we’ll just highlight a couple of key points.

To begin with, here’s the query that locates all the users with the mailNickname kenmyer (and because mailNicknames must be unique, there will be - at most - only one user that fits the criteria):

objCommand.CommandText = _
    "SELECT distinguishedName FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user' " & _
        "AND mailNickname = 'kenmyer'

Pretty simple, huh? All we’re doing here is returning the distinguishedName attribute for all the user accounts (WHERE objCategory = ‘user’) with the mailNickname kenmyer. When we execute this query we get back a recordset consisting of - at most - a single item. We then use this code to loop through the collection and store the user’s distinguished name in a variable named strDN:

Do Until objRecordSet.EOF
    strDN = objRecordSet.Fields("distinguishedName").Value
    objRecordSet.MoveNext
Loop

Now that we know the user’s distinguished name we can bind to the user account and then do whatever we want (in our simple example, all we do is echo back the value of the Name attribute):

Set objUser = GetObject("LDAP://" & strDN)
Wscript.Echo objUser.Name

Again, all we did was supply the mailNickname and yet we ended up binding to the user account. What if all we had was the sAMAccountName? In that case we’d modify our query and look for a user with a specified sAMAccountName rather than a specified mailNickname:

objCommand.CommandText = _
    "SELECT distinguishedName FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user' " & _
        "AND sAMAccountName = 'kenmyer'"

Hey, no need to thank us. After all, finding out ways to work around the system is what we do best!