c# - 递归地获取 Active Directory 组的成员,即包括子组

标签 c# active-directory active-directory-group

在 Active Directory 中给定这样一个组:

MainGroup
  GroupA
    User1
    User2
  GroupB
    User3
  User4

我可以使用如下代码轻松确定 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);
    }
}

我想知道是否有类似的方法来获取属于某个组或其任何子组的所有用户,即在 MainGroup 的示例中获取 User1、User2、User3 和 User4。

获取所有用户的明显方法是递归查询每个子组,但我想知道是否有更简单的方法来做到这一点。

使用与 memberOf:1.2.840.113556.1.4.1941: 过滤器相同的方法,但是使用域根而不是用户作为搜索基础是不可行的,因为查询需要太多long(可能它为域中的所有用户递归地计算所有组成员资格,并检查他们是否是给定组的成员)。

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

最佳答案

以防万一这可能使其他人受益:这是我最终得到的解决方案。这只是一个递归搜索,有一些额外的检查以避免检查同一个组或用户两次,例如如果 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]);
            }
        }
    }

}

关于c# - 递归地获取 Active Directory 组的成员,即包括子组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3665487/

相关文章:

c# - 避免 aspnet_compiler 运行 PreApplicationStart 方法

c# - 将 WinForm 捕捉到编程

linux - ldapsearch - 动态组中的用户

c# - 如何格式化 C# 字符串以换行以适应特定的列宽?

c# - 如何使用 ASP.NET Core Web API 传输/接收原始字节数组?

c# - 我想设置 "Password Must Change at Next Login"标志

c# - 使用应用程序池标识会导致异常和事件日志

excel - 如何在 VBA 中管理从 ADsDSOObject 提供程序检索的日期对象?

azure - Azure Active Directory 中的所有人、所有用户和经过身份验证的用户

c# - 根据 AD 组成员身份限制对 WPF View 的访问