9

我正在使用以下代码来获取我域中组的成员:

  Dim de As New DirectoryEntry("LDAP://" & GroupDN)

  For Each user As String In CType(de.Properties("member"), IEnumerable)

          GroupCollection.Add(Username, Username)

  Next

我的问题是,当 GroupDN(组的专有名称)是“ CN=Domain Users,CN=Users,DC=Mydomain,DC=local ”时,For...Each 循环不执行,当我检查手动属性语句,它的计数为零。这似乎适用于我域中的所有其他组,但“域用户”组应该包含所有人,并且似乎不包含任何人。

我已经检查过了,该组在我的 Windows AD 工具中正确列出了每个人。我在这里有什么明显的遗漏吗?附带说明一下,是否有更好的方法来获取组的所有成员?

4

2 回答 2

11

除非您更改用户的主要组 id,否则用户不会存储在域用户组的成员属性中,而是使用主要组 id 设置为域用户 RID 的事实来确定域用户中的成员身份。正常情况是Domain Users成员属性为空;它需要您对默认的 Active Directory 实现进行一些更改才能避免这种情况。

Domain Users 组使用基于用户“主要组 ID”的“计算”机制来确定成员资格,并且通常不将成员存储为多值链接属性。如果用户的主要组发生更改,则他们在 Domain Users 组中的成员资格将写入该组的链接属性并且不再计算。这对于 Windows 2000 是正确的,对于 Windows Server 2003 并没有改变。

参考

于 2009-02-08T04:02:06.857 回答
0

公认的答案是绝对正确的。默认情况下,每个(用户)对象都513在属性primarygroupid中设置,这是域用户 sid的固定“尾部” 。但是:这可以更改,并且可以在那里配置所有其他组,所以我们不能依赖它。

这是一个如何获取group members无论如何的示例方法(不管默认值是保留还是更改)。在对活动目录组的成员进行任何查询后,我都会调用这样的方法。在此示例中,我得到了一个可分辨名称数组作为结果。但是所有其他属性都是可能的,只需将它们添加到dSearcher.PropertiesToLoad.Add(...)并修改结果即可。

我知道,这是一个关于 VB 的问题,我希望它易于移植。


    using System.DirectoryServices;
    using System.Security.Principal;


    public static string[] GetMembersDnByPrimaryGroupId(string domainName, SecurityIdentifier sidOfGroupToGetMembersByPrimaryGroupId)
    {
        // In a single domain environement the domain name is probably not needed, but
        // we expect a multy domain environement
        if (string.IsNullOrWhiteSpace(domainName) || sidOfGroupToGetMembersByPrimaryGroupId == null)
        {
            throw new ArgumentNullException($"Neither domainName nor sid may be null / blank: DomainName: { domainName }; sid: { sidOfGroupToGetMembersByPrimaryGroupId }");
            //<----------
        }

        List<string> membersDnResult = new List<string>();
        // Get the last segment of the group sid, this is what is stored in the "primaryGroupId"
        string groupSidTail = sidOfGroupToGetMembersByPrimaryGroupId.Value.Split('-').Last();
        string path = $"LDAP://{ domainName }";
        DirectoryEntry dEntry = new DirectoryEntry(path);

        SearchResultCollection adSearchResult = null;
        DirectorySearcher dSearcher = new DirectorySearcher(dEntry);

        // For this example we need just the distinguished name but you can add
        // here the property / properties you want
        dSearcher.PropertiesToLoad.Add("distinguishedName");

        // set the filter to primarygroupid
        dSearcher.Filter = $"(&(primarygroupid={ groupSidTail }))";

        // May die thousand deaths, therefore exception handling is needed. 
        // My exception handling is outside of this method, you may want
        // to add it here
        adSearchResult = dSearcher.FindAll();

        // Get the domains sid and check if the domain part of the wanted sid
        // fits the domain sid (necesarry in multy domain environments)
        byte[] domainSidBytes = (byte[])dEntry.Properties["objectSid"].Value;
        SecurityIdentifier domainSid = new SecurityIdentifier(domainSidBytes, 0);
        if (sidOfGroupToGetMembersByPrimaryGroupId.AccountDomainSid != domainSid)
        {
            throw new ArgumentException($"Domain sid of the wanted group { sidOfGroupToGetMembersByPrimaryGroupId.AccountDomainSid } does not fit the sid { domainSid } of the searched through domain \"{ domainName }\"");
            //<----------
        }

        // We found entries by the primarygroupid
        if (adSearchResult.Count > 0)
        {
            foreach (SearchResult forMemberByPrimaryGroupId in adSearchResult)
            {
                // Every AD object has a distinguishedName, therefore we acess "[0]" 
                // wihtout any further checking
                string dn = forMemberByPrimaryGroupId.Properties["distinguishedName"][0].ToString();
                membersDnResult.Add(dn);
            }
        }

        return membersDnResult.ToArray();
    }

于 2020-12-25T17:26:37.763 回答