2011-06-24 7 views
5

ウェブアプリケーションでは、特定のグループのメンバーであるユーザーのSAMアカウントのリストを表示することを検討しています。多くの場合、グループには500人以上のメンバーがいる可能性があり、応答性の高いページが必要です。C#でActive Directory内のグループメンバーのリストを手早く取得する

約500人のメンバーで構成されているグループでは、グループのメンバー全員にsamアカウントのリストを取得するのに7〜8秒かかります。より速い方法がありますか?私は、Active Directory管理コンソールがそれを1秒以内に実行することを知っています。

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
System.DirectoryServices.DirectoryEntry de = (System.DirectoryServices.DirectoryEntry)grp.GetUnderlyingObject(); 
List<string> lst = new List<string>(); 
foreach (string sDN in de.Properties["member"]) 
{ 
    System.DirectoryServices.DirectoryEntry deMember = new System.DirectoryServices.DirectoryEntry("LDAP://" + sDN); 
    lst.Add(deMember.Properties["samAccountName"].Value.ToString()); 
} 

答えて

0

あなたはLDAPクエリを試してみました

1)

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
List<string> lst = grp.Members.Select(g => g.SamAccountName).ToList(); 

2)

PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 
GroupPrincipal grp = GroupPrincipal.FindByIdentity(pcRoot, "MyGroup"); 
PrincipalSearchResult<Principal> lstMembers = grp.GetMembers(true); 
List<string> lst = new List<string>(); 
foreach (Principal member in lstMembers) 
{ 
    if (member.StructuralObjectClass.Equals("user")) 
    { 
     lst.Add(member .SamAccountName); 
    } 
} 

3):

は、私はいくつかの方法を試してみましたか?ページの一番下には、メンバーを取得するグループを列挙するためのC#の例があります。 MSDN BOL

using System; 
using System.DirectoryServices; 

namespace ADAM_Examples 
{ 
class EnumMembers 
{ 
    /// <summary> 
    /// Enumerate AD LDS groups and group members. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     DirectoryEntry objADAM;     // Binding object. 
     DirectoryEntry objGroupEntry;    // Group Results. 
     DirectorySearcher objSearchADAM;   // Search object. 
     SearchResultCollection objSearchResults; // Results collection. 
     string strPath;       // Binding path. 

     // Construct the binding string. 
     strPath = "LDAP://localhost:389/OU=TestOU,O=Fabrikam,C=US"; 
     Console.WriteLine("Bind to: {0}", strPath); 
     Console.WriteLine("Enum: Groups and members."); 

     // Get the AD LDS object. 
     try 
     { 
      objADAM = new DirectoryEntry(strPath); 
      objADAM.RefreshCache(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Bind failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     // Get search object, specify filter and scope, 
     // perform search. 
     try 
     { 
      objSearchADAM = new DirectorySearcher(objADAM); 
      objSearchADAM.Filter = "(&(objectClass=group))"; 
      objSearchADAM.SearchScope = SearchScope.Subtree; 
      objSearchResults = objSearchADAM.FindAll(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Search failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     // Enumerate groups and members. 
     try 
     { 
      if (objSearchResults.Count != 0) 
      { 
       foreach(SearchResult objResult in objSearchResults) 
       { 
        objGroupEntry = objResult.GetDirectoryEntry(); 
        Console.WriteLine("Group {0}", 
         objGroupEntry.Name); 
        foreach(object objMember 
         in objGroupEntry.Properties["member"]) 
        { 
         Console.WriteLine(" Member: {0}", 
          objMember.ToString()); 
        } 
       } 
      } 
      else 
      { 
       Console.WriteLine("Results: No groups found."); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("Error: Enumerate failed."); 
      Console.WriteLine("   {0}", e.Message); 
      return; 
     } 

     Console.WriteLine("Success: Enumeration complete."); 
     return; 
    } 
} 

}

+0

これは私の質問では似ていますが、ログ時間を取る部分がメンバープロパティの各項目を介在しています。 – Jeremy

+0

は、ハンガリーの表記が好きでなければならず、元の例の古い古文 –

5

鉱山の同僚、さまざまなActive Directoryの検索方法を使用している場合、クエリの時間と同様の問題がありました。彼はデータベース内の情報をキャッシュして夜間にリフレッシュしてから、代わりにデータベースにアクセスしました。

ユーザーアカウントで頻繁に変更されないという事実を考慮すると、これは彼にとって許容される妥協点でした。あなたの使用状況によっては、これは受け入れられるかもしれません。

4

ADSIを使用した再帰的検索(ネストされたグループの検索ユーザー)です。

static void Main(string[] args) 
{ 
    /* Connection to Active Directory 
    */ 
    string sFromWhere = "LDAP://SRVENTR2:389/dc=societe,dc=fr"; 
    DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "societe\\administrateur", "test.2011"); 

    /* To find all the users member of groups "Grp1" : 
    * Set the base to the groups container DN; for example root DN (dc=societe,dc=fr) 
    * Set the scope to subtree 
    * Use the following filter : 
    * (member:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=X) 
    */ 
    DirectorySearcher dsLookFor = new DirectorySearcher(deBase); 
    dsLookFor.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=Grp1,OU=MonOu,DC=societe,DC=fr)(objectCategory=user))"; 
    dsLookFor.SearchScope = SearchScope.Subtree; 
    dsLookFor.PropertiesToLoad.Add("cn"); 
    dsLookFor.PropertiesToLoad.Add("samAccountName"); 

    SearchResultCollection srcUsers = dsLookFor.FindAll(); 

    /* Just show each user 
    */ 
    foreach (SearchResult srcUser in srcUsers) 
    { 
    Console.WriteLine("{0}", srcUser.Path); 
    Console.WriteLine("{0}", srcUser.Properties["samAccountName"][0]); 
    } 

    Console.ReadLine(); 
} 
+1

は、これを上書きする主な理由の1つは、AccountManagementのパフォーマンスが低いためです。実際にAD検索のパフォーマンスを得る唯一の方法は、DirectoryServicesのlibに移動することです。 Clunky APIが本当に速い –

1

あなたの最初のオプションと同様に

 PrincipalContext pcRoot = new PrincipalContext(ContextType.Domain) 

     GroupPrincipal mygroup = new GroupPrincipal(pcRoot); 

     // define the principal searcher, based on that example principal 

     PrincipalSearcher ps = new PrincipalSearcher(mygroup); 

     ps.QueryFilter = new GroupPrincipal(pcRoot) { SamAccountName = "Name of your group Case Sensitive" }; 

     List<UserPrincipal> users = new List<UserPrincipal>(); 
     // loop over all principals found by the searcher 

     GroupPrincipal foundGroup = (GroupPrincipal)ps.FindOne(); 

foreach (UserPrincipal u in foundGroup.Members) 
        { 
         users.Add(u); 

        } 
//OR 
List<string> lst = foundGroup.Members.Select(g => g.SamAccountName).ToList();//this will only get the usernames not the user object or UserPrincipal 
0

....それはどんな速くなるかどうかわからない、これを試してみてくださいしかし、私は、リストからHashSetのを作成しました。グループが大きければ大きいほど、メンバーシップを確認するまでに時間がかかります。しかし、成功したメンバーシップクエリーと成功しなかったメンバーシップクエリーについては一貫しています。大規模なグループを反復するには、アカウントがメンバーでない場合は3倍の時間がかかりますが、この方法は毎回同じです。

using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain)) 
using(GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "groupName")) 
{ 
    List<string> members = group.GetMembers(true).Select(g => g.SamAccountName).ToList(); 
    HashSet<string> hashset = new HashSet<string>(members, StringComparer.OrdinalIgnoreCase); 

    if(hashset.Contains(someUser) 
     return true; 
}