powershell

Unable to create a function to get nested groups


I am a beginner programmer in PowerHhell. I am trying to create a function that outputs all nested groups of a group. When I run the function, it gives an error:

Get-ADGroupMember : Cannot find an object with identity: "CN=John,OU=Test,OU=Company,DC=klns,DC=ado,DC=com" в "DC=klns,DC=ado,DC=com".
D:\Work\Powershell\Folder\est4.ps1:11 symbol:23
+ $GetObjects = Get-ADGroupMember $Members
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CN=John,OU=Т...C=ado,DC=com:ADGroup) [Get-ADGroupMember], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember

$Group = "LGR-Test-RWX"
function Get-NestedGroups
{
       
  $script:Groups = @()    
  $script:ADGroup = (Get-ADGroup -Identity $Group -Properties Name, Member).Member
  $script:Groups += $ADGroup

  foreach ($Members in $ADGroup)
    {
      $GetObjects = Get-ADGroupMember $Members
      $GetGroups = $GetObjects | Where-Object objectClass -eq "group"
        if ($GetGroups)
        {
          foreach ($Groups in $GetGroups.Member)
          {
              Get-NestedGroups $Groups
          }
      }
  }
    
  return ($script:Groups.Name | Sort-Object -Unique)    
}
Get-NestedGroups $Group

I can't understand why it doesn't work. Please explain what I am doing wrong. Thank you.


Solution

  • Recursion is the best way for traversing nested structures.

    This is a function I've provided as solution for a request in the module Carbon.Security, Get-CPrivilege should have an option for returning the accumelated privileges

    function Get-xEffectiveGroup {
    
        [CmdletBinding()]
        param (
            [Parameter(Mandatory)]
            [string[]]$UserPrincipalName,
    
            [switch]$Local,
    
            [switch]$Domain
        )
    
        Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    
        function Get-NestedGroups {
    
            [CmdletBinding()]
            param (
                [Parameter(Mandatory)]
                [System.DirectoryServices.AccountManagement.Principal]$Principal
            )
    
            $Groups = [System.Collections.ArrayList]@()
    
            $Principal.GetGroups() | foreach {
                $Groups.Add($_) | Out-Null
                $Groups.Add($(Get-NestedGroups -Principal $_)) | Out-Null
            }
    
            return $Groups
    
        }#end priv function
    
        $Context = New-Object System.DirectoryServices.AccountManagement.PrincipalContext(
            [System.DirectoryServices.AccountManagement.ContextType]::Domain)
    
        $UserPrincipal = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity(
            $Context, $UserPrincipalName
        )
    
        $NtDomain = (
            $userprincipal.DistinguishedName.split(',') |
                where {$_.Contains('DC')}
        )[0].split('=')[-1]
    
        [System.Collections.ArrayList]$AllPrincipals = @()
    
        if ($Domain -or -not $Local) {#get domain groups
            $AllDomainGroups = Get-NestedGroups -Principal $UserPrincipal |
                select -Unique Name |
                    where {-not [string]::IsNullOrEmpty($_.Name)} |
                        select @{l = 'Name'; e = {"$NtDomain\" + $_.Name} }
    
            if ($AllDomainGroups) {#was found
                if (($AllDomainGroups | Measure-Object).Count -eq 1) {
                    $AllPrincipals.Add($AllDomainGroups) | Out-Null
                }
                if (($AllDomainGroups | Measure-Object).Count -gt 1) {
                    $AllPrincipals.AddRange($AllDomainGroups) | Out-Null
                }
            }#end domain groups found
    
        }
    
        if ($Local -or -not $Domain) {#get local groups
            $LocalGroups = Get-LocalGroup | where {
                $ThisLocalGroup = $_
                $AllPrincipals.Name | where {
                        $ThisPrincipalName = $_
                        $ThisPrincipalName -in ($ThisLocalGroup | Get-LocalGroupMember).Name
                    }
            }
    
            if ($LocalGroups) {
                if ($LocalGroups.Count -eq 1) {#ArrayLists are faster but picky
                    [void]$AllPrincipals.Add(($LocalGroups | select Name))
                }
                else {
                    [void]$AllPrincipals.AddRange(($LocalGroups | select Name))
                }
            }
    
            $UserPrincipalGroups = Get-LocalGroup | where {
                    $ThisLocalGroup = $_
                    ($NtDomain + '\' + $UserPrincipal.SamAccountName) -in ($ThisLocalGroup | Get-LocalGroupMember).Name
                }
    
            if ($UserPrincipalGroups) {
                if ($UserPrincipalGroups.Count -eq 1) {#ArrayLists are faster but picky
                    [void]$AllPrincipals.Add(($UserPrincipalGroups | select Name))
                }
                else {
                    [void]$AllPrincipals.AddRange(($UserPrincipalGroups | select Name))
                }
            }
    
        }#end Local groups
    
        return $AllPrincipals
    
    <#
    .SYNOPSIS
        Get all groups a domain user is member of.
    
    .DESCRIPTION
        Get all groups (explicit and inherited and local) that a user principal object is member of.
    
    .PARAMETER UserPrincipalName
        Domain name as domain\account to get all groups for.
    
    .PARAMETER Local
        Only get implicit local group membership. I.e. membership through a domain group wont show.
    
    .PARAMETER Domain
        Only get domain groups.
    
    .EXAMPLE
        Get-xEffectiveGroup -UserPrincipalName domain\accountname
    
    .EXAMPLE
        Get-xEffectiveGroup -UserPrincipalName domain\accountname -Local
    
        Show all local groups where the UserPrincipalName is an implict member. Inheritied
        membership throuhg domain groups will not show.
    
    #>
    
    }