5

System.DirectoryServices.AccountManagement名前空間クラスを使用して、いくつかのグループのメンバーシップを管理しています。これらのグループは私たちの印刷会計システムの人口を管理しており、それらのいくつかは非常に大きいです。これらの大きなグループの1つからユーザーを削除する際に問題が発生しています。問題を説明するテストプログラムがあります。テストしているグループはネストされていませんが、user.IsMemberOf()にも同じ問題があるようですが、GetAuthorizationGroups()は、ユーザーがメンバーであるグループを正しく示していることに注意してください。問題のグループには約81Kのメンバーがいます。これは、Remove()が機能していないため、必要以上に多く、通常は約65K程度になります。

この問題を抱えて解決した他の人たちから話を聞いてみたいと思います。私はマイクロソフトのオープンケースを持っていますが、コールセンターは約17時間の時差があるため、電話のターンアラウンドは遅く、私が通常家に帰る約1時間前まで彼らは仕事に到着しません。

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

                }
            }
        }
    }
}
4

3 に答える 3

5

これはGroupPrincipal.Members.Remove()コードのバグであり、1500を超えるメンバーを持つグループの削除が失敗することが判明しました。これは.NET4.0Beta2で修正されています。修正を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[] { userEntry.Path } );
于 2009-12-11T15:33:42.803 に答える
1

この投稿は、私を正しい方向に向けるのに役立ちました。いくつかの追加情報を追加したかっただけです。

また、グループに直接バインドすることもでき、グループメンバーの追加に使用できます。

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
于 2014-08-20T10:42:30.397 に答える
0
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;
}
于 2014-02-06T18:08:37.810 に答える