I've been meaning to blog this for a couple of weeks now. I was approached by Gagik with a query about ADSI scripting. Fortunately, I've certainly done a fair bit with ADSI given my background. The problem Gagik was having was adding a user to a group. This in itself is pretty common thing to want to do. The original code I was sent was attempting to update the "memberOf" attribute of a user object to add a group. This in itself appears to be a very reasonable assumption of how to perform this. Unfortunately complicated by the fact that the memberOf property is multivalued and the lack of methods on IADSUser, but reasonable indeed:
Here's a sanitised version of the sample code I was sent:
Const ADS_PROPERTY_APPEND = 3intAccValue = 512Dim objUserSet objUser = objContainer.GetObject("user", "CN=UserName")objUser.PutEx ADS_PROPERTY_APPEND, "memberOf", _ Array("CN=MyGroup,OU=My_OU,DC=domain,DC=com")objUser.SetInfo
This was failing with the error "The server is unwilling to process the request".
Under the covers, Active Directory uses a two-way linkage between users and groups. Hence, if you were to be able to update the memberOf attribute for a user in this way, the multi-valued member attribute of the group would also be updated with the DN of the user account. You can see this for yourself if you run up ADSIEdit.msc and play around in Active Directory Users and Computers.
Given Active Directory has this linkage, the solution to the problem is, as many such problems are solved, to turn it on its head. Rather than update the user object, update the group object. ADSI and AD between them are clever enough to ensure the consistency between the matching user/group attributes are kept intact. There is also one other significant advantage with this mechanism, as the IADSGroup object exposed by ADSI has an "Add" method for just this purpose. Some of the complications in the original code arise directly as the IADSUser object doesn't expose the attribute or provide a method directly.
This is the code I proposed (which works flawlessly) using the LDAP ADSI provider.
set objGroup = GetObject("LDAP://CN=MyGroup,ou=My_OU,DC=domain,DC=Com")objGroup.Add("LDAP://CN=UserName,ou=MY_OU,DC=domain,DC=Com")
A lot easier. Gagik had been trying to get the old code to work for some time without success, so he was very happy! For more information, see this link on MSDN. Of course, don't forget dsmod group and the -addmbr parameter would also do the trick...