2011-06-24 60 views
5

在Web应用程序中,我们正在寻找显示特定组成员的用户的sam帐户列表。在许多情况下,组可能拥有500个或更多成员,我们需要该页面具有响应能力。使用C#获取Active Directory中组成员列表的快速方法

约500名成员组成的团队需要7-8秒才能获得该组所有成员的sam帐户列表。有更快的方法吗?我知道Active Directory管理控制台不到一秒钟就完成了。

我已经尝试了一些方法:

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)

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查询?该页面的底部有一个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

这与我的问题中的例3类似,需要记录时间的部分是通过成员属性中的每个项目进行交互。 – Jeremy

+0

必须爱匈牙利符号,从一个原始示例 –

5

我的一个同事使用各种活动目录检索方法时,曾与查询时间类似的问题。他最终将信息缓存在数据库中,每晚刷新一次,然后访问数据库。

考虑到用户帐户不会经常改变的事实,这对他来说是一个可以接受的折中方案。根据您的使用情况,这可能会也可能不会被接受。

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

一些古体剩余的主要原因之一,这是因为AccountManagement的表现很差。真正获得AD搜索性能的唯一方法是下移到DirectoryServices库。笨重的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; 
} 
相关问题