# encoding: ascii
# api: powershell
# title: Get-GroupStructure
# description: This simple function exports the structure of nested groups in a similar way as folder and file structures are usually presented.
# version: 0.1
# type: function
# author: DollarUnderscore
# license: CC0
# function: Get-GroupStructure
# x-poshcode-id: 5538
# x-archived: 2016-05-17T16:15:02
# x-published: 2016-10-24T11:06:00
#
# It is also a part of another really simple powershell form that end users can use to export members of Active Directory groups.
# It requires the Active Directory module to run.
# Blog post with a link the PowerShell form is available at:
# http://dollarunderscore.azurewebsites.net/?p=3601
# Edit: missed something in the comment based help. Sorry…
#
#========================================================================
# Created By: Anders Wahlqvist
# Website: DollarUnderscore (http://dollarunderscore.azurewebsites.net)
#========================================================================

function Get-GroupStructure
{
    <#
    .SYNOPSIS
    This cmdlets exports the structure of nested groups and users.

    .DESCRIPTION
    This cmdlets exports the structure of nested groups and users, in a simliar way
    as file structures are presented.

    It requires the Active Directory module to run.

    .EXAMPLE
    Get-GroupStructure -GroupName "Domain Admins"

    .PARAMETER GroupName
    Specify the name of the "root group".

    .PARAMETER GroupPath
    Set the "start level" of the returned string. Mostly used internally, you can safely ignore this.

    #>

    param ([string] $GroupPath = '',
           [string] $GroupName)

    $GroupMembers = @()
    $GroupMembers += Get-ADGroupMember $GroupName | Sort-Object objectClass -Descending

    $LoopCount = @($GroupPath -split " \\ " | Where-Object { $_ -eq $GroupName })

    if ($LoopCount.Count -ge 2) {
        Write-Error "Nested group loop detected. Group: $GroupName"
        return;
    }

    if ($GroupPath -eq '') {
        $GroupPath = "$GroupName \ "
    }

    if ($GroupMembers.Count -eq 0) {
        Write-Output $GroupPath
    }

    foreach($GroupMember in $GroupMembers) {
        
        Remove-Variable DrilledDownGroupPath, UserPath -ErrorAction SilentlyContinue

        if ($GroupMember.objectClass -eq 'group') {
            $DrilledDownGroupPath = $GroupPath + "$($GroupMember.name) \ "
            Get-GroupStructure -GroupPath $DrilledDownGroupPath -GroupName $GroupMember.name
        }
        else {
            $UserPath = "$GroupPath$($GroupMember.Name) ($($GroupMember.SamAccountName))"
            Write-Output $UserPath
        }
    }
}
