How Can I Add a User to a Group If I Don’t Know the Distinguished Name of That User?
Hey, Scripting Guy! How can I add a user to an Active Directory group if I don’t know the distinguished name of that user?
Hey, VO. You know, if we wanted to take the easy way out here we’d just tell you, “Sorry, but if you don’t know the distinguished name of the user you can’t add that user to an Active Directory group.”
Note. If you want to get technical, even the distinguished name isn’t good enough: you really need to know the ADsPath of the user (a value similar to this: LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com). But we’ll let that slide; after all, if you do have the distinguished name (cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com) then you can generate the ADsPath just by sticking LDAP:// on the front.
In other words, if we just wanted to dismiss this question without even trying, pointing out that this simply can’t be done, well, we’d be well within our rights to do so; after all, it can’t be done. But you know what? That would be taking the easy way out. And when have you ever known the Scripting Guys to take the easy way out?
OK, true: we forgot about that. And that. That other time? Well, that wasn’t really our fault; we did the best we could. The entire month of July? Come on, it was summer, for crying out loud; everyone takes the easy way out during the summer. And – well, OK, we get the point. But this time we absolutely will not take the easy way out. No way.
Well, OK. But at least we’ll answer your question.
Let’s recap the situation here. We want to add a user to an Active Directory group. To do that we need to know the ADsPath for the user. However, we don’t know the ADsPath for the user. Our prospects for success here seem kind of bleak, don’t they?
Nah. You say you don’t know the ADsPath for the user? That’s fine; we’ll just go out and find the ADsPath for the user:
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 ADsPath FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user' " & _ "AND samAccountName = 'kenmyer'" Set objRecordSet = objCommand.Execute objRecordSet.MoveFirst Do Until objRecordSet.EOF strADsPath = objRecordSet.Fields("ADsPath").Value Set objGroup = GetObject("LDAP://cn=Finance Managers,ou=Finance,dc=fabrikam,dc=com") objGroup.Add(strADsPath) objRecordSet.MoveNext Loop
What we’re doing here is assuming that you know something about the user in question. (Admittedly if you don’t know anything about the user then it’s going to be a bit more difficult to locate that user and add him or her to a group.) For example, even though you don’t know the user’s distinguished name there’s a very good chance that you know his or her samAccountName (which, for all intents and purposes, is just the user’s logon name). Therefore, all we have to do is search Active Directory for a user with that particular samAccountName (a good attribute to search for, by the way, because samAccountNames must be unique within a domain). After we locate the user we can grab his or her ADsPath. And once we have the ADsPath we can add that user to an Active Directory group.
That’s exactly what we do in our script. At the risk of taking the easy way out (heaven forbid!) we won’t explain the ins and outs of searching Active Directory in any detail today; if you need more information take a look at our two-part series Dude, Where’s My Printer? About all we will do is point out that this is the query we use to search the fabrikam.com domain (‘LDAP://dc=fabrikam,dc=com’) for a user (objectCategory=’user’) that has a logon name of kenmyer (samAccountName = ‘kenmyer’):
objCommand.CommandText = _ "SELECT ADsPath FROM 'LDAP://dc=fabrikam,dc=com' WHERE objectCategory='user' " & _ "AND samAccountName = 'kenmyer'"
When we execute this query (using the Execute method) we’ll get back a recordset containing the ADsPath of each and every user who has the samAccountName kenmyer. Because samAccountNames must be unique in the domain, that recordset will contain – at most – just one item: the ADsPath of the user we want to add to the group.
That’s great, except for one thing: now that we have a recordset what do we do with it? Well, to begin with, we set up a Do Until loop that runs until we’ve looped through all the records in our recordset; in other words until the recordset’s EOF (end-of-file) property is True. (And yes, we need to set up a loop like this even though we’ll never have more than one record in the recordset.) Inside that loop we use this line of code to grab the value of the user’s ADsPath and store it in a variable named strADsPath:
strADsPath = objRecordSet.Fields("ADsPath").Value
Once we have the ADsPath we can then add the user to the group. That’s a task that requires two lines of code: one line to bind to the group account in Active Directory; the other to call the Add method and add the new group member, making sure we pass the ADsPath of the user to the Add method. In other words:
Set objGroup = GetObject("LDAP://cn=Finance Managers,ou=Finance,dc=fabrikam,dc=com") objGroup.Add(strADsPath)
After adding the user to the group we call the MoveNext method to advance to the next record in the recordset. Because we don’t have a next record in our recordset that causes us to exit the loop, which in turn brings the script to a close. The net result? The user gets added to the group, and without us doing very much beyond writing a few lines of code, most of which is boilerplate code for searching Active Directory.
In all fairness, we should add that, at least when it comes to being lazy and not trying very hard, the Scripting Guys are mere amateurs compared to some people. Several years ago the Scripting Guy who writes this column came home to find that his cable TV was no longer working. When he called the cable company (which has since gone out of business) he was told that the cable had been shut off because he hadn’t paid his bill.
“I’m positive we paid the bill,” said the Scripting Guy, “Let me get the checkbook and –“
“Would that be check number 1895, dated July 14th?” interrupted the cable guy.
“Yes,” said the Scripting Guy. “How did you know that?”
“I’m looking at the check right now,” said the cable guy. “Apparently we received it about three weeks ago. However, Marcie has been on vacation since then so it’s just been sitting on her desk. I was supposed to enter all these checks into the computer, but I haven’t gotten around to it.”
“So you shut off our cable for non-payment of our bill even though you received our payment three weeks ago?” asked the Scripting Guy.
“Yeah. Kind of funny, isn’t it?”
Well, not really. What was funny was when the cable guy said it would take an additional three weeks to restore service.
“Wait a minute,” said the Scripting Guy who writes this column. “It takes three weeks to restore existing service, yet you can activate a brand-new account in a week?”
“These things take time,” replied the cable guy, who paused for a moment and then added, “There: I just flipped the switch and your cable has been restored. Try not to let this happen again, OK?”
Now that was a company who knew about taking the easy way out!