通过嵌套的AD组查找用户和AD组关系

时间:2014-02-17 04:19:00

标签: powershell security active-directory nested active-directory-group

基本上,在我们的环境中,我们有很多安全组。嵌套在其他组中的安全组等。因此,找到设置适用于用户的原因是真正的PITA,因为其中一个嵌套组可能是也可能不是

的一部分。

例如如果将用户添加到组X,他们会突然在Citrix中发布已发布的应用程序。 Citrix已配置为安全组Y.尝试查找X和Y之间的链接非常耗时,但可以自动完成。

我想创建一个脚本,您输入用户和结束安全组(上面的组Y),脚本输出将用户连接到最终组的中间组。如果这是有道理的吗?

这样的事情:

function get-grouprelationship($username, $knownsecuritygroup)
{
    $getallgroups = get-adgroupmember $knownsecuritygroup | where-object {$_.ObjectClass -eq "Group" | select-object SamAccountName | foreach-object {get-adgroupmember $_.SamAccountName}
}

(以上变量占用您的组,并循环遍历该组的所有成员,打印其成员)

$usergroups = (get-aduser -identity $username -Properties memberof | select-object memberof).memberof

(以上获取用户所在的所有群组)

$usergroups1 = $usergroups.split(",")
$usergroups2 = $usergroups1[0]
$usergroups3 = $usergroups2.substring(3)

(上面很好地格式化了文本)

if ($usergroups3 -contains $groupname){write-host "$username is directly in $groupname}

从这里开始,我非常困难,因为我基本上需要嵌套多个for循环,具体取决于每组中有多少组。然后做一个条件检查

if ($groupname -eq $currentgroup){write-host "connected by $groupname and $currentgroup}

我也坚持使用$getallgroups变量,因为它只检查1级。然后它需要另外一个foreach循环,其中需要另外一个等等。

由于没有先前的编码经验,我真的很难想到实现目标的简单方法。

编辑:

我在这里找到了这个脚本 - script。下面基本上有效,除了它是详细的方式:

import-module activedirectory
$username = read-host "What's their username?"
Function RecurseUsersInGroup {
    Param ([string]$object = "", [int]$level = 0)
    $indent = "-" * $level

    $x = Get-ADObject -Identity $object -Properties SamAccountName

    if ($x.ObjectClass -eq "group") {
        Write-Host "# $($x.SamAccountName)"

        $y = Get-ADGroup -Identity $object -Properties Members

        $y.Members | %{
            $o = Get-ADObject -Identity $_ -Properties SamAccountName

            if ($o.ObjectClass -eq "user" -and $o.SamAccountName -eq $username) {
                Write-Host "-> $($o.SamAccountName)"
            } elseif ($o.ObjectClass -eq "group") {
                RecurseUsersInGroup $o.DistinguishedName ($level + 1)
            }
        }
    } else {
        Write-Host "$($object) is not a group, it is a $($x.ObjectClass)"
    }
}
$thegroup = read-host "What's the Group?"
RecurseUsersInGroup (get-adgroup $thegroup).DistinguishedName

工作正常,但似乎输出每个安全组,反对连接的安全组。当然,这是朝着正确方向迈出的一步!如果我找到了来源,我也会发布信用证。

1 个答案:

答案 0 :(得分:1)

下面的版本并不简单(可能写得更简洁,但我希望脚本至少是半可读的),但它会搜索该组并返回Active Directory组对象对于找到该组的分支的每个组。

function Get-GroupConnection
{
    [CmdletBinding()]
    PARAM (
        $Username,
        $GroupName
    )

    $User = Get-AdUser -Identity $Username -Properties MemberOf
    if (-Not ($User))
    {
        return;
    }

    $SearchedGroups = @()

    function Find-GroupBranches
    {
        [CmdletBinding()]
        PARAM (
            $GroupNameList,
            $SearchForGroupName
        )

        $ADGroups = $GroupNameList | Foreach { Get-ADGroup -Identity $_ -Properties MemberOf }

        foreach($group in $ADGroups)
        {
            Write-Verbose "Testing if either '$($Group.SamAccountName)' or '$($Group.DistinguishedName)' are equal to '$SearchForGroupName'"
            if ($Group.SamAccountName -eq $SearchForGroupName -OR $Group.DistinguishedName -eq $SearchForGroupName)
            {
                Write-Verbose "Found $($Group.DistinguishedName)"
                Write-Output $Group
                return
            }
        }

        Write-Verbose "No match in current collection, checking children"
        foreach ($currentGroup in $ADGroups)
        {
            if ($SearchedGroups -Contains $currentGroup.DistinguishedName)
            {
                Write-Verbose "Already checked children of '$($currentGroup.DistinguishedName)', ignoring it to avoid endless loops"
                continue
            }
            $SearchedGroups += $currentGroup.DistinguishedName

            if ($currentGroup.MemberOf)
            {
                Write-Verbose "Checking groups which $($currentGroup.DistinguishedName) is member of"

                $foundGroupInTree = Find-GroupBranches -GroupNameList $currentGroup.MemberOf -SearchForGroupName $SearchForGroupName
                if ($foundGroupInTree)
                {
                    Write-Output $currentGroup
                    Write-Output $foundGroupInTree
                    break
                }
            }
            else
            {
                Write-Verbose "$($currentGroup.DistinguishedName) is not member of any group, branch ignored"
            }
        }
    }

    Write-Verbose "Searching immediate group membership"
    Find-GroupBranches -GroupNameList $User.MemberOf -SearchForGroupName $GroupName
}

Get-GroupConnection -Username MyUser -GroupName SubSubGroup -Verbose

关于如何搜索的说明。

给出以下Active Directory结构:

MyUser
    Domain Admins
        AnotherSubGroup
    Other Group
    DirectMemberGroup
        Domain Admins (same group as MyUser is direct member of, above)
            AnotherSubGroup (which is of course the same as above too)
        SubGroup
            SubSubGroup
    Some Other Group

如果我们搜索MyUser和'SubSubGroup'之间的连接,脚本将首先搜索MyUser用户的直接成员资格,即'Domain Admins','Other Group','DirectMemberGroup'和'Some Other Group'。这些都不匹配我们搜索的'SubSubGroup',所以它开始检查'child'groups。

'Domain Admins'是'AnotherSubGroup'的成员,但是与'SubSubGroup'不匹配。 'AnotherSubGroup'不是任何组的成员,因此忽略该分支。

'其他组'不是任何组的成员,因此忽略该分支。

'DirectMemberGroup'是其他组的成员,因此它会遍历这些组。它已经为子项检查了“域管理员”,因此跳过该组以避免陷入循环搜索。因此,它检查'子组'。

'SubGroup'与'SubSubGroup'不匹配,因此它会检查'SubGroup'所属的组。 'SubGroup'是'SubSubGroup'的成员,因此它会检查该组。

'SubSubGroup'匹配'SubSubGroup',因此将被选为匹配。

在上面的示例中,输出组对象将是通向“SubSubGroup”组的分支,按以下顺序:

DirectMemberGroup
SubGroup
SubSubGroup

注意此方法将返回它在用户和组之间找到的第一个连接。例如,如果“其他组”组也是“SubSubGroup”的成员,则不会更改上面提到的输出和搜索过程。