如何获取特定用户的所有AD组?

NLV*_*NLV 35 .net c# directoryservices ldap active-directory

我已经查过这篇文章了.但它没有回答我的问题.我想获取特定用户所属的所有活动目录组.

我写了以下代码.但我无法继续进行,因为我不知道如何提供过滤器以及如何访问属性.

class Program
{
    static void Main(string[] args)
    {
        DirectoryEntry de = new DirectoryEntry("LDAP://mydomain.com");
        DirectorySearcher searcher = new DirectorySearcher(de);
        searcher.Filter = "(&(ObjectClass=group))";
        searcher.PropertiesToLoad.Add("distinguishedName");
        searcher.PropertiesToLoad.Add("sAMAccountName");
        searcher.PropertiesToLoad.Add("name");
        searcher.PropertiesToLoad.Add("objectSid");
        SearchResultCollection results = searcher.FindAll();
        int i = 1;
        foreach (SearchResult res in results)
        {
            Console.WriteLine("Result" + Convert.ToString(i++));
            DisplayProperties("distinguishedName", res);
            DisplayProperties("sAMAccouontName", res);
            DisplayProperties("name", res);
            DisplayProperties("objectSid", res);
            Console.WriteLine();
        }

        Console.ReadKey();
    }

    private static void DisplayProperties(string property, SearchResult res)
    {
        Console.WriteLine("\t" + property);
        ResultPropertyValueCollection col = res.Properties[property];
        foreach (object o in col)
        {
            Console.WriteLine("\t\t" + o.ToString());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Har*_*wok 35

您应该使用System.DirectoryServices.AccountManagement.这更容易.这是一个很好的代码项目文章,为您提供此DLL中所有类的概述.

正如您所指出的,您当前的方法没有找到主要组.实际上,它比你想象的要糟糕得多.还有一些案例不起作用,例如来自另一个域的域本地组.您可以在此查看详细信息.以下是切换到使用System.DirectoryServices.AccountManagement时代码的样子.以下代码可以找到此用户分配给的直接组,其中包括主要组.

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext (ContextType.Domain, "mydomain.com"), IdentityType.SamAccountName, "username");
foreach (GroupPrincipal group in user.GetGroups())
{
    Console.Out.WriteLine(group);
}
Run Code Online (Sandbox Code Playgroud)

  • user.GetGroups()非常慢! (5认同)

小智 26

使用tokenGroups:

DirectorySearcher ds = new DirectorySearcher();
ds.Filter = String.Format("(&(objectClass=user)(sAMAccountName={0}))", username);
SearchResult sr = ds.FindOne();

DirectoryEntry user = sr.GetDirectoryEntry();
user.RefreshCache(new string[] { "tokenGroups" });

for (int i = 0; i < user.Properties["tokenGroups"].Count; i++) {
    SecurityIdentifier sid = new SecurityIdentifier((byte[]) user.Properties["tokenGroups"][i], 0);
    NTAccount nt = (NTAccount)sid.Translate(typeof(NTAccount));
    //do something with the SID or name (nt.Value)
}
Run Code Online (Sandbox Code Playgroud)

注意:这只会获得安全组

  • 这段代码比我尝试过的任何其他代码快了大约10倍(使用PrincipalContext).从大约4秒钟开始,为用户提取所有组到400毫秒.谢谢. (3认同)

cur*_*isk 25

只需查询"memberOf"属性并迭代返回,例如:

            search.PropertiesToLoad.Add("memberOf");
            StringBuilder groupNames = new StringBuilder(); //stuff them in | delimited

                SearchResult result = search.FindOne();
                int propertyCount = result.Properties["memberOf"].Count;
                String dn;
                int equalsIndex, commaIndex;

                for (int propertyCounter = 0; propertyCounter < propertyCount;
                    propertyCounter++)
                {
                    dn = (String)result.Properties["memberOf"][propertyCounter];

                    equalsIndex = dn.IndexOf("=", 1);
                    commaIndex = dn.IndexOf(",", 1);
                    if (-1 == equalsIndex)
                    {
                        return null;
                    }
                    groupNames.Append(dn.Substring((equalsIndex + 1),
                                (commaIndex - equalsIndex) - 1));
                    groupNames.Append("|");
                }

            return groupNames.ToString();
Run Code Online (Sandbox Code Playgroud)

这只是将组名称填充到groupNames字符串,管道分隔,但是当你旋转时,你可以随心所欲地做任何事情


小智 7

这是我列出特定专有名称的所有组(直接和间接)的方法:

字符串1.2.840.113556.1.4.1941指定 LDAP_MATCHING_RULE_IN_CHAIN。

此规则仅限于应用于 DN 的过滤器。这是一个特殊的“扩展”匹配运算符,它沿着对象中的祖先链一直走到根,直到找到匹配项。

在我的测试中,此方法比UserPrincipal.GetGroups()方法快 25 倍

注意:此方法或 GetGroups() 方法不会返回主要组(通常是域用户)。为了也获取主要组名称,我已经确认此方法有效。

此外,我发现这个LDAP 过滤器列表非常有用。

private IEnumerable<string> GetGroupsForDistinguishedName(DirectoryEntry domainDirectoryEntry, string distinguishedName)
{
    var groups = new List<string>();
    if (!string.IsNullOrEmpty(distinguishedName))
    {
        var getGroupsFilterForDn = $"(&(objectCategory=group)(member:1.2.840.113556.1.4.1941:={distinguishedName}))";
        using (DirectorySearcher dirSearch = new DirectorySearcher(domainDirectoryEntry))
        {
            dirSearch.Filter = getGroupsFilterForDn;
            dirSearch.PropertiesToLoad.Add("name");

            using (var results = dirSearch.FindAll())
            {
                foreach (SearchResult result in results)
                {
                    if (result.Properties.Contains("name"))
                        groups.Add((string)result.Properties["name"][0]);
                }
            }
        }
    }

    return groups;
}
Run Code Online (Sandbox Code Playgroud)


小智 6

这段代码运行得更快(两个 1.5 比我以前的版本快):

    public List<String> GetUserGroups(WindowsIdentity identity)
    {
        List<String> groups = new List<String>();

        String userName = identity.Name;
        int pos = userName.IndexOf(@"\");
        if (pos > 0) userName = userName.Substring(pos + 1);

        PrincipalContext domain = new PrincipalContext(ContextType.Domain, "riomc.com");
        UserPrincipal user = UserPrincipal.FindByIdentity(domain, IdentityType.SamAccountName, userName); // NGeodakov

        DirectoryEntry de = new DirectoryEntry("LDAP://RIOMC.com");
        DirectorySearcher search = new DirectorySearcher(de);
        search.Filter = "(&(objectClass=group)(member=" + user.DistinguishedName + "))";
        search.PropertiesToLoad.Add("cn");
        search.PropertiesToLoad.Add("samaccountname");
        search.PropertiesToLoad.Add("memberOf");

        SearchResultCollection results = search.FindAll();
        foreach (SearchResult sr in results)
        {
            GetUserGroupsRecursive(groups, sr, de);
        }

        return groups;
    }

    public void GetUserGroupsRecursive(List<String> groups, SearchResult sr, DirectoryEntry de)
    {
        if (sr == null) return;

        String group = (String)sr.Properties["cn"][0];
        if (String.IsNullOrEmpty(group))
        {
            group = (String)sr.Properties["samaccountname"][0];
        }
        if (!groups.Contains(group))
        {
            groups.Add(group);
        }

        DirectorySearcher search;
        SearchResult sr1;
        String name;
        int equalsIndex, commaIndex;
        foreach (String dn in sr.Properties["memberof"])
        {
            equalsIndex = dn.IndexOf("=", 1);
            if (equalsIndex > 0)
            {
                commaIndex = dn.IndexOf(",", equalsIndex + 1);
                name = dn.Substring(equalsIndex + 1, commaIndex - equalsIndex - 1);

                search = new DirectorySearcher(de);
                search.Filter = "(&(objectClass=group)(|(cn=" + name + ")(samaccountname=" + name + ")))";
                search.PropertiesToLoad.Add("cn");
                search.PropertiesToLoad.Add("samaccountname");
                search.PropertiesToLoad.Add("memberOf");
                sr1 = search.FindOne();
                GetUserGroupsRecursive(groups, sr1, de);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)