以递归方式获取Active Directory组的成员,即包括子组

Pao*_*sco 7 c# active-directory active-directory-group

在Active Directory中给出这样的组:

MainGroup
  GroupA
    User1
    User2
  GroupB
    User3
  User4
Run Code Online (Sandbox Code Playgroud)

我可以轻松确定User3是否是MainGroup或其任何子组的成员,代码如下:

using System;
using System.DirectoryServices;

static class Program {
    static void Main() {
        DirectoryEntry user = new DirectoryEntry("LDAP://CN=User3,DC=X,DC=y");
        string filter = "(memberOf:1.2.840.113556.1.4.1941:=CN=MainGroup,DC=X,DC=y)";
        DirectorySearcher searcher = new DirectorySearcher(user, filter);
        searcher.SearchScope = SearchScope.Subtree;
        var r = searcher.FindOne();
        bool isMember = (r != null);
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有类似的方法来获取作为组或其任何子组成员的所有用户,即在MainGroup的示例中获取User1,User2,User3和User4.

获取所有用户的显而易见的方法是递归查询每个子组,但我想知道是否有更简单的方法.

使用与memberOf:1.2.840.113556.1.4.1941:过滤器相同的方法,但使用域根而不是用户作为搜索库是不可行的,因为查询花费的时间太长(可能它会为域中的所有用户递归计算所有组成员资格并检查它们是否存在是特定组的成员).

获取组中所有成员(包括其子组)的最佳方法是什么?

Pao*_*sco 18

以防这可能会让其他人受益:这是我最终解决的问题.它只是一个递归搜索,有一些额外的检查以避免两次检查同一组或用户,例如,如果groupA是groupB的成员,groupB是groupA的成员,或者用户是多个组的成员.

using System;
using System.DirectoryServices;
using System.Collections.Generic;

static class Program {

    static IEnumerable<SearchResult> GetMembers(DirectoryEntry searchRoot, string groupDn, string objectClass) {
        using (DirectorySearcher searcher = new DirectorySearcher(searchRoot)) {
            searcher.Filter = "(&(objectClass=" + objectClass + ")(memberOf=" + groupDn + "))";
            searcher.PropertiesToLoad.Clear();
            searcher.PropertiesToLoad.AddRange(new string[] { 
                "objectGUID",
                "sAMAccountName",
                "distinguishedName"});
            searcher.Sort = new SortOption("sAMAccountName", SortDirection.Ascending);
            searcher.PageSize = 1000;
            searcher.SizeLimit = 0;
            foreach (SearchResult result in searcher.FindAll()) {
                yield return result;
            }
        }
    }

    static IEnumerable<SearchResult> GetUsersRecursively(DirectoryEntry searchRoot, string groupDn) {
        List<string> searchedGroups = new List<string>();
        List<string> searchedUsers = new List<string>();
        return GetUsersRecursively(searchRoot, groupDn, searchedGroups, searchedUsers);
    }

    static IEnumerable<SearchResult> GetUsersRecursively(
        DirectoryEntry searchRoot,
        string groupDn,
        List<string> searchedGroups,
        List<string> searchedUsers) {
        foreach (var subGroup in GetMembers(searchRoot, groupDn, "group")) {
            string subGroupName = ((string)subGroup.Properties["sAMAccountName"][0]).ToUpperInvariant();
            if (searchedGroups.Contains(subGroupName)) {
                continue;
            }
            searchedGroups.Add(subGroupName);
            string subGroupDn = ((string)subGroup.Properties["distinguishedName"][0]);
            foreach (var user in GetUsersRecursively(searchRoot, subGroupDn, searchedGroups, searchedUsers)) {
                yield return user;
            }
        }
        foreach (var user in GetMembers(searchRoot, groupDn, "user")) {
            string userName = ((string)user.Properties["sAMAccountName"][0]).ToUpperInvariant();
            if (searchedUsers.Contains(userName)) {
                continue;
            }
            searchedUsers.Add(userName);
            yield return user;
        }
    }

    static void Main(string[] args) {
        using (DirectoryEntry searchRoot = new DirectoryEntry("LDAP://DC=x,DC=y")) {
            foreach (var user in GetUsersRecursively(searchRoot, "CN=MainGroup,DC=x,DC=y")) {
                Console.WriteLine((string)user.Properties["sAMAccountName"][0]);
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)