LDAP_MATCHING_RULE_IN_CHAIN不适用于默认的AD组-域用户

时间:2018-11-23 18:52:20

标签: vb.net powershell active-directory ldap

在我的程序中,我需要获取用户的所有AD组。 我程序的当前版本使用System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups。

这很好,直到我们有了一个新客户,其AD更大。那里真的很慢。 (最长60秒)

现在我一直在四处看看,看到了AccountManagement易于使用但速度很慢的帖子。

我还发现LDAP_MATCHING_RULE_IN_CHAIN还应该获取用户所属的所有嵌套组。而且性能更高。

通过this链接。

但是我对AD中存在的默认组有疑问。

例如,该函数未返回“域用户”组。 他们还具有一个组“ BDOC”,该组作为成员具有“域用户”。该组也不会返回。

通过GetAuthorizationGroups可以正确返回。

我正在使用以下代码按用户获取组。

VB.NET:

Dim strFilter As String = String.Format("(member:1.2.840.113556.1.4.1941:={0})", oUserPrincipal.DistinguishedName)
Dim objSearcher As New DirectoryServices.DirectorySearcher("LDAP://" & oLDAPAuthenticationDetail.Domain & If(Not String.IsNullOrWhiteSpace(oLDAPAuthenticationDetail.Container), oLDAPAuthenticationDetail.Container, String.Empty))
objSearcher.PageSize = 1000
objSearcher.Filter = strFilter
objSearcher.SearchScope = DirectoryServices.SearchScope.Subtree
objSearcher.PropertiesToLoad.Add(sPropGuid)
objSearcher.PropertiesToLoad.Add(sPropDisplayName)


Dim colResults As DirectoryServices.SearchResultCollection = objSearcher.FindAll()

此后,我通过链接中的脚本进行了测试,是否有可能通过将过滤器中的“成员”更改为“成员”来从“域用户”组中获取所有用户。 当我将Domain Admins组放入过滤器时,它显示管理员正确。 当我将“域用户”组放入过滤器时,它什么也不返回。

Powershell:

$userdn = 'CN=Domain Users,CN=Users,DC=acbenelux,DC=local'
$strFilter = "(memberOf:1.2.840.113556.1.4.1941:=$userdn)"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://rootDSE")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://$($objDomain.rootDomainNamingContext)"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Base"
$colProplist = "name"
foreach ($i in $colPropList)
{
    $objSearcher.PropertiesToLoad.Add($i) > $nul
}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
    $objItem = $objResult.Properties
    $objItem.name
}

我不知道我在做什么错。还是可能无法使用该过滤器获取“默认组”? 那有什么好的选择呢?

1 个答案:

答案 0 :(得分:1)

默认组为奇数。它没有存储在memberOf中,甚至没有存储在组的member属性中。这就是为什么您的搜索找不到它的原因。默认组由用户的primaryGroupId确定。该属性存储组的RID(SID的最后一部分)。我知道这有点愚蠢:)

我实际上写了一篇关于某人可以成为组成员的3种方式(是3种)的文章:What makes a member a member?

我还写了一篇文章,介绍如何获取单个用户所属的所有组,以及如何说明所有3种方式:Finding all of a user’s groups

例如,这是我在该文章中输入的C#代码,该代码有关如何查找用户的主要组的名称(给定DirectoryEntry)。将其转换为VB.NET并不难:

private static string GetUserPrimaryGroup(DirectoryEntry de) {
    de.RefreshCache(new[] {"primaryGroupID", "objectSid"});

    //Get the user's SID as a string
    var sid = new SecurityIdentifier((byte[])de.Properties["objectSid"].Value, 0).ToString();

    //Replace the RID portion of the user's SID with the primaryGroupId
    //so we're left with the group's SID
    sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
    sid = sid + de.Properties["primaryGroupId"].Value;

    //Find the group by its SID
    var group = new DirectoryEntry($"LDAP://<SID={sid}>");
    group.RefreshCache(new [] {"cn"});

    return group.Properties["cn"].Value as string;
}

您很正确,AccountManagement名称空间使事情变得容易,但有时确实确实具有糟糕的性能。我不再使用它了。我发现DirectoryEntry / DirectorySearcher使您可以更好地控制代码向AD发出呼叫的频率。

我一直想写一篇有关用DirectoryEntry编写高性能代码的文章,但是我还没有解决。

更新:因此,如果您需要用户的嵌套组(包括通过主要组的成员资格),则可以先找到主要组,然后执行LDAP_MATCHING_RULE_IN_CHAIN搜索具有两个用户和主要组作为成员:

 (|(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}))

更新::如果要在搜索中包括Authenticated Users(编辑DC的{​​{1}}部分):

distinguishedName

请注意,您还可以使用用户的 (|(member:1.2.840.113556.1.4.1941:=CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=domain,DC=com)(member:1.2.840.113556.1.4.1941:={userDN})(member:1.2.840.113556.1.4.1941:={primaryGroupDN}) 属性来查找用户的所有身份验证组。 tokenGroups属性是一个构造属性,因此只有在您明确要求时才使用它(使用DirectoryEntry.RefreshCache()或在搜索中将其添加到DirectorySearcher.PropertiesToLoad

需要注意的是,tokenGroups是SID的列表,而不是tokenGroups,但是您可以使用distinguishedName语法的SID直接绑定到对象。