GroupPrincipal.Members.Remove()不适用于大型AD组

我正在使用System.DirectoryServices.AccountManagement命名空间类来管理多个组的成员身份。 这些群体控制着我们的印刷会计系统的人口,其中一些非常庞大。 我遇到了从这些大组之一中删除任何用户的问题。 我有一个测试程序来说明问题。 请注意,我正在测试的组不是嵌套的,但user.IsMemberOf()似乎也有同样的问题,而GetAuthorizationGroups()正确显示用户所属的组。 有问题的小组大约有81K成员,因为Remove()不起作用,所以它应该超过它应该有的,并且通常大约是65K左右。

我有兴趣听到有其他人遇到过这个问题并已经解决了。 我和微软有一个公开的案例,但由于呼叫中心的时差大约是17个小时,所以电话转接很慢,因此他们在我离开家之前大约一个小时才到达工作岗位。

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 ); } } } } } 

事实certificate这是GroupPrincipal.Members.Remove()代码中的一个错误,其中对于具有超过1500个成员的组,删除失败。 这已在.NET 4.0 Beta 2中得到修复。我不知道他们是否有计划将修复程序反向移植到2.0 / 3.x.

解决方法是获取底层DirectoryEntry,然后使用Invoke在IADsGroup对象上执行Remove命令。

  var entry = group.GetUnderlyingObject() as DirectoryEntry; var userEntry = user.GetUnderlyingObject() as DirectoryEntry; entry.Invoke( "Remove", new object[] { user.Path } ); 
 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; } 

这篇文章帮助我指出了正确的方向,只是想添加一些额外的信息。

它还可以直接绑定到组,您可以使用它来添加组成员。

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

另外请注意,使用标准的’member’属性,您使用用户或组的distinguishedName,但是invoke需要带有LDAP://前缀的路径,否则会引发模糊的InnerException:

 Exception from HRESULT: 0x80005000