我正在使用以下代码来获取我的域中组的成员:
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 =域用户,CN =用户,DC = Mydomain,DC =本地”时,For ... Each循环不执行,当我手动检查属性语句时,它的计数为零。这似乎适用于我的域中的每个其他组,但“域用户”组应该包含所有人,并且它似乎包含任何人。
我已经检查过了,该小组在我的Windows AD工具中正确列出了所有人。我有什么明显的遗漏吗?另外,有没有更好的方法来获得一个小组的所有成员?
答案 0 :(得分:9)
除非您更改用户的主要组ID,否则用户不会存储在Domain Users组的成员属性中,而是使用主要组ID设置为域用户RID以确定成员身份的事实。域用户。正常情况是Domain Users成员属性为空;它需要您对默认的Active Directory实现进行一些更改,但事实并非如此。
Domain Users组使用 基于“计算”机制 用户的“主要组ID” 确定会员资格而不是 通常将成员存储为 多值链接属性。如果 用户的主要组已更改, 他们在Domain Users中的会员资格 组被写入链接 该组的属性是否定的 更长的计算。这是真的 Windows 2000并没有改变 Windows Server 2003。
答案 1 :(得分:0)
accepted answer 是绝对正确的。默认情况下,每个(用户)对象都在属性 primarygroupid 中设置了 513
,这是 Domain Users 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();
}