GroupPrincipal.Members.Remove() doesn't work with a large AD group

与世无争的帅哥 提交于 2019-12-10 14:36:03

问题


I'm using the System.DirectoryServices.AccountManagement namespace classes to manage the membership of several groups. These groups control the population of our print accounting system and some of them are very large. I'm running into a problem removing any user from one of these large groups. I have a test program that illustrates the problem. Note that the group I'm testing is not nested, but user.IsMemberOf() also seems to have the same problem, whereas GetAuthorizationGroups() correctly shows the groups a user is a member of. The group in question has about 81K members, which is more than it should have since Remove() isn't working, and will normally be about 65K or so.

I'd be interested to hear from other people who have had this problem and have resolved it. I've got an open case with Microsoft, but the turn around on the call is slow since the call center is about 17 hours time difference so they don't arrive for work until about an hour before I usually leave for home.

using (var context = new PrincipalContext( ContextType.Domain ))
{
    using (var group = GroupPrincipal.FindByIdentity( context, groupName ))
    {
        using (var user = UserPrincipal.FindByIdentity( context, userName ))
        {
            if (user != null)
            {
                var isMember = user.GetAuthorizationGroups()
                                   .Any( g => g.DistinguishedName == group.DistinguishedName );
                Console.WriteLine( "1: check for membership returns: {0}", isMember );
                if (group.Members.Remove( user ))
                {
                    Console.WriteLine( "user removed successfully" );
                    group.Save();
                }
                else
                {
                    // do save in case Remove() is lying to me
                    group.Save();
                    Console.WriteLine( "user remove failed" );
                    var isStillMember = user.GetAuthorizationGroups()
                                            .Any( g => g.DistinguishedName == group.DistinguishedName );
                    Console.WriteLine( "2: check for membership returns: {0}", isStillMember );

                }
            }
        }
    }
}

回答1:


Turns out this is a bug in the GroupPrincipal.Members.Remove() code in which remove fails for a group with more than 1500 members. This has been fixed in .NET 4.0 Beta 2. I don't know if they have plans to back port the fix into 2.0/3.x.

The work around is to get the underlying DirectoryEntry, then use Invoke to execute the Remove command on the IADsGroup object.

 var entry = group.GetUnderlyingObject() as DirectoryEntry;
 var userEntry = user.GetUnderlyingObject() as DirectoryEntry;
 entry.Invoke( "Remove", new object[] { user.Path } );



回答2:


This post helped point me in the right direction, just wanted to add some addition info.

It also works binding directly to the group, and you can use it for adding group members.

using (var groupEntry = new DirectoryEntry(groupLdapPath))
{
    groupEntry.Invoke("remove", new object[] { memberLdapPath });
    groupEntry.Invoke("add",    new object[] { memberLdapPath });
}

Also be aware, with the standard 'member' attribute, you use the user or group distinguishedName, but invoke requires the path with LDAP:// prefix, otherwise it throws a vague InnerException:

Exception from HRESULT: 0x80005000



回答3:


public bool RemoveUserFromGroup(string UserName, string GroupName)
{
   bool lResult = false;
   if (String.IsNullOrEmpty(UserName) || String.IsNullOrEmpty(GroupName)) return lResult;
   try
   {
      using (DirectoryEntry dirEntry = GetDirectoryEntry())
      {
         using (DirectoryEntry dirUser = GetUser(UserName))
         {
            if (dirEntry == null || dirUser == null)
            {
               return lResult;
            }
            using (DirectorySearcher deSearch = new DirectorySearcher())
            {
               deSearch.SearchRoot = dirEntry;
               deSearch.Filter = String.Format("(&(objectClass=group) (cn={0}))", GroupName);
               deSearch.PageSize = 1000;
               SearchResultCollection result = deSearch.FindAll();
               bool isAlreadyRemoved = false;
               String sDN = dirUser.Path.Replace("LDAP://", String.Empty);
               if (result != null && result.Count > 0)
               {
                  for (int i = 0; i < result.Count; i++)
                  {
                     using (DirectoryEntry dirGroup = result[i].GetDirectoryEntry())
                     {
                        String sGrDN = dirGroup.Path.Replace("LDAP://", String.Empty);
                        if (dirUser.Properties[Constants.Properties.PROP_MEMBER_OF].Contains(sGrDN))
                        {
                           dirGroup.Properties[Constants.Properties.PROP_MEMBER].Remove(sDN);
                           dirGroup.CommitChanges();
                           dirGroup.Close();
                           lResult = true;
                           isAlreadyRemoved = true;
                           break;
                        }
                     }
                     if (isAlreadyRemoved)
                        break;
                  }
               }
            }
         }
      }
   }
   catch
   {
      lResult= false;
   }
   return lResult;
}


来源:https://stackoverflow.com/questions/1860772/groupprincipal-members-remove-doesnt-work-with-a-large-ad-group

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!