Using WS2008 Active Directory we set up an OU and delegated full control of group objects to a site group admin vis a global group. So the site group admins are in a global group that has full control of all groups in that OU. The site group admin does not have any enhanced rights, basically a plain old user, in the domain.
Using ADUC and the AD Admin Center the site group admins can add/remove members and they can also change the groups managedBy attribute via the tools noted. In addtion, they can check the box "Manager can update membership list" and the correct ACE entry is made. So far so good!
One department though wants to put a tool up, to not have to use ADUC so I started writing some VB.Net 2010 code for them that works GREAT if the account performing the action is an admin or account operator.
I went to try the steps as a plain user and all worked well, the plain user account could even add/remove to the ACE.
The VB.Net2010 code didn't fair so well. It works 100% of the time as an Admin. But as the plain old user it always fails to add the member add/remove ace. It should be noted that the plain old user can ADD/REMOVE/CHANGE the managedBy entrywithout fail, but cannot write the ACE.
BTW, just to point out we can't make these folks admins or account operators, there are too many who would need those enhanced privileges. I'm sure I'm missing something important. The confusing part is that the plain old user, who has full control of all group objects in the OU, can perform this all day long using ADUC and AD Admin center.
Here is my code snippet:
'first it has to be cleared, using some old vb6 code'this works great
Err.Clear()
Dim objGrp = GetObject("LDAP://" & grp_found_fdn)
objGrp.PutEx(1, "managedBy", 0)
objGrp.SetInfo()
Console.WriteLine("clear managedby result: " & Err.Number())
'this works great
Err.Clear()
groupbind.Properties("managedBy").Add(usr_found_fdn)
groupbind.CommitChanges()
Console.WriteLine("add managedby result: " & Err.Number())
'start ace work
Dim currentUser
Dim objSysInfo = CreateObject("ADSystemInfo")
Dim objCurrentUser = GetObject("LDAP://" & objSysInfo.username)
Console.WriteLine("")
Console.WriteLine("objCurrentUser: " & objCurrentUser.domain)
Console.WriteLine("objCurrentUser: " & objCurrentUser.samAccountName)
Console.WriteLine("objCurrentUser: " & objCurrentUser.distinguishedname)
currentUser = objCurrentUser.distinguishedname
Console.WriteLine("CurrentUser: " & currentUser)
Dim aio = CreateObject("ADSystemInfo")
Dim domainDNS = aio.DomainDNSName
Console.WriteLine("aio.DomainDNSName: " & aio.DomainDNSName)
Dim domainShort = aio.DomainShortName
Console.WriteLine("aio.DomainShort: " & aio.DomainShortName)
Dim holder_name = aio.DomainShortName & "\" & objCurrentUser.samAccountName
Console.WriteLine("holder_name: " & holder_name)
Console.WriteLine("")
Console.WriteLine("write managedby ace start")
Console.WriteLine("")
Err.Clear()
Dim objUser = GetObject("LDAP://" & grp_found_fdn)
Console.WriteLine("objUser result: " & Err.Number)
Err.Clear()
Dim objSecurityDescriptor = objUser.Get("ntSecurityDescriptor")
Console.WriteLine("objSecurityDescriptor result: " & Err.Number)
Err.Clear()
Dim str_top_Owner = objSecurityDescriptor.Owner
Console.WriteLine("")
Console.WriteLine("str_top_Owner: " & str_top_Owner)
Console.WriteLine("")
Err.Clear()
Dim objOU2 = GetObject("LDAP://" & grp_found_fdn)
Console.WriteLine("objOU2 result: " & objOU2.adspath)
Console.WriteLine("objOU2 result: " & Err.Number)
Err.Clear()
Dim objSecurityDescriptor2 = objOU2.Get("ntSecurityDescriptor")
Console.WriteLine("objSecurityDescriptor2 result: " & Err.Number)
Err.Clear()
objSecurityDescriptor2.Owner = holder_name.ToString
Console.WriteLine("objSecurityDescriptor2.Owner: " & objSecurityDescriptor2.Owner)
Console.WriteLine("objSecurityDescriptor2.Owner result: " & Err.Number)
Err.Clear()
objOU2.Put("ntSecurityDescriptor", objSecurityDescriptor2)
Console.WriteLine("objOU2.Put(ntSecurityDescriptor: " & Err.Number)
Console.WriteLine("objOU2.Put(ntSecurityDescriptor: " & Err.Description)
Err.Clear()
objOU2.SetInfo()
Console.WriteLine("objOU2.SetInfo(): " & Err.Number)
Dim strGroup = grp_found_fdn
Dim strDomainController = grp_found_adspath
Dim strDomainNT4 = group_domain_name
Console.WriteLine("")
Console.WriteLine("strGroup: " & strGroup)
Console.WriteLine("strDomainController result: " & strDomainController)
Console.WriteLine("strDomainNT4 result: " & strDomainNT4)
Dim ldap_try
ldap_try = "LDAP://" & strDomainNT4 & "/" & strGroup
ldap_try = "LDAP://" & strGroup
Console.WriteLine("ldap try: " & ldap_try)
Err.Clear()
Dim objGroup As New DirectoryEntry(ldap_try.ToString)
Console.WriteLine("objgroup result: " & Err.Number())
Console.WriteLine("objgroup result: " & Err.Description)
Err.Clear()
Dim newAce As New AccessControlEntry
Console.WriteLine("newAce result: " & Err.Number())
Err.Clear()
Dim grpSD As SecurityDescriptor = CType(objGroup.Properties("ntSecurityDescriptor").Value, SecurityDescriptor)
Console.WriteLine("grpSD result: " & Err.Number())
Err.Clear()
Dim grpAcl As AccessControlList = CType(grpSD.DiscretionaryAcl, AccessControlList)
Console.WriteLine("grpAcl result: " & Err.Number())
Err.Clear()
newAce.Trustee = user_domain_name & "\" & user_sam_name
Console.WriteLine("newAce.Trustee result: " & Err.Number())
newAce.AccessMask = ADS_RIGHT_DS_WRITE_PROP
' newAce.AceFlags = ADS_ACEFLAG_DONT_INHERIT_ACE
newAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
newAce.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT
' newAce.AceFlags = ADS_RIGHT_WRITE_OWNER
' newAce.AceType = ADS_RIGHT_WRITE_OWNER
' newAce.Flags = ADS_RIGHT_WRITE_OWNER
'this one must stay
newAce.ObjectType = ADS_OBJECT_WRITE_MEMBERS
Err.Clear()
grpAcl.AddAce(newAce)
Console.WriteLine("grpAcl.AddAce: " & Err.Number())
Err.Clear()
grpSD.DiscretionaryAcl = grpAcl
Console.WriteLine("objGroup.SetInfo(): " & Err.Number())
Err.Clear()
objGroup.Properties("ntSecurityDescriptor").Value = grpSD
Console.WriteLine("objgroup.Properties.SetInfo(): " & Err.Number())
Err.Clear()
objGroup.CommitChanges()
Console.WriteLine("objgroup,commit(): " & Err.Number())
Console.WriteLine("objgroup commit: " & Err.Description)
Console.WriteLine("")
'the committ of the ACE only works for admins, not plain old users
Console.WriteLine("")
Console.WriteLine("write managedby ace end")
Console.WriteLine("")
'End ace work
Thanks,
Ed Ghiglieri
Ed
Ed