Public/Expand-ADDynamicGroup.ps1

Function Expand-ADDynamicGroup {
    <#
    .SYNOPSIS
        Expand dynamic security group definition to describe actions to take
 
    .DESCRIPTION
        Expand dynamic security group definition to describe actions to take
 
        Takes the output of Get-ADDynamicGroup and expands this into an array of actions with the following properties:
 
            Group # The target group we will take this action on
            Account # The account we will act on for this target group
            Action # The action we will take on thie target group and account pair
            Type # If IncludeType parameter is specified, whether the account is a group or a user
            Definition # The raw input we parsed from Get-ADDynamicGroup
 
    .FUNCTIONALITY
        Active Directory
 
    .PARAMETER InputObject
        Dynamic group definition generated by Get-ADDynamicGroup
 
    .PARAMETER IncludeType
        If specified, parse the AD type for each AD account to be added or removed from the target group
 
    .EXAMPLE
        Get-ADDynamicGroup $Yaml | Expand-ADDynamicGroup
 
    .EXAMPLE
        Get-ADDynamicGroup $Yaml | Expand-ADDynamicGroup -IncludeType
 
    .LINK
        Get-ADDynamicGroup
 
    .LINK
        Invoke-ADGrouper
 
    .LINK
        about_ADGrouper
    #>

    [cmdletbinding()]
    param(
        [parameter(ValueFromPipeline= $True)]
        [PSTypeName('adgrouper.group')]
        [psobject[]]$InputObject,
        [switch]$IncludeType
    )
    begin
    {
        function Get-Params {
            param($Target, $Account)
            $Props = Get-PropertyOrder $Account
            $ThisRecurse = if($Props -contains 'Recurse') {$Account.Recurse} else {$Target.Recurse}
            $ThisExpand = if($Props -contains 'Expand') {$Account.Expand} else {$Target.Expand}

            @{
                Identity = $Account.Account
                Recurse = $ThisRecurse
                Expand = $ThisExpand
            }
        }
    }
    process
    {
        Write-Verbose "Expanding $($InputObject | Out-String)"
        foreach($Group in $InputObject)
        {
            $Excludes = New-Object System.Collections.ArrayList
            $Includes = New-Object System.Collections.ArrayList
        
            foreach($ADObject in @( $Group.Exclude | Where {$_.Account}))
            {
                $Type = $null
                $Type = Get-ADObjectClass -sAMAccountName $ADObject.Account
                if($Type)
                {
                    $Params = Get-Params -Target $Group -Account $ADObject
                    Write-Verbose "Expanding removal of $($ADObject.account) with type [$Type] and expand [$($Group.Expand)]"
                    [void]$Excludes.AddRange( @(Expand-Account @Params -Type $Type ) )
                }
                else
                {
                    Write-Warning "No type found for $($ADObject.Account) exclude, skipping"
                }
            }
            foreach($ADObject in @( $Group.Include | Where {$_.Account}))
            {
                $Type = $null
                $Type = Get-ADObjectClass -sAMAccountName $ADObject.Account
                if($Type)
                {
                    $Params = Get-Params -Target $Group -Account $ADObject
                    Write-Verbose "Expanding inclusion of $($ADObject.account) with type [$Type], expand [$($Params.Expand)], recurse [$($Params.Recurse)]"
                    [void]$Includes.AddRange( @(Expand-Account @Params -Type $Type) )
                }
                else
                {
                    Write-Warning "No type found for $($ADObject.Account) include, skipping"
                }
            }
            foreach($Query in @( $Group.IncludeQuery | Where {$_}) )
            {
                $DiscoveredAccounts = $null
                [string[]]$DiscoveredAccounts = Get-ADSIObject -Query $Query | Select -ExpandProperty sAMAccountName | Where {$_}
                if($DiscoveredAccounts.count -gt 0)
                {
                    Write-Verbose "Including $($DiscoveredAccounts.count) accounts from query [$Query]"
                    [void]$Includes.AddRange( $DiscoveredAccounts )
                }
                else
                {
                    Write-Verbose "No accounts found for IncludeQuery [$Query]"              
                }
            }
            foreach($Query in @( $Group.ExcludeQuery | Where {$_}) )
            {
                $DiscoveredAccounts = $null
                [string[]]$DiscoveredAccounts = Get-ADSIObject -Query $Query | Select -ExpandProperty sAMAccountName | Where {$_}
                if($DiscoveredAccounts.count -gt 0)
                {
                    Write-Verbose "Excluding $($DiscoveredAccounts.count) accounts from query [$Query]"
                    [void]$Excludes.AddRange( $DiscoveredAccounts )
                }
                else
                {
                    Write-Verbose "No accounts found for ExcludeQuery [$Query]"              
                }
            }
            $Excludes = $Excludes | Sort -Unique
            $Includes = $Includes | Where {$Excludes -notcontains $_} | Select -Unique
            $Existing = Expand-Account -Type Group -Identity $Group.TargetGroup -Expand
        
            $ToRemove = $Existing | Where {$Includes -notcontains $_} | Sort -Unique
            $ToAdd = $Includes | Where {$Existing -notcontains $_} | Sort -Unique
        
            if($Group.Purge -and $null -notlike $ToRemove)
            {
                foreach($Account in $ToRemove)
                {
                    [pscustomobject]@{
                        PSTypeName = 'adgrouper.action'
                        Group = $Group.TargetGroup
                        Account = $Account
                        Action = 'Remove'
                        Type = Get-ADObjectClass -sAMAccountName $Account -IncludeType $IncludeType
                        Definition = $Group
                    }
                }
            }
            foreach($Account in $ToAdd)
            {
                [pscustomobject]@{
                    PSTypeName = 'adgrouper.action'
                    Group = $Group.TargetGroup
                    Account = $Account
                    Action = 'Add'
                    Type = Get-ADObjectClass -sAMAccountName $Account -IncludeType $IncludeType
                    Definition = $Group
                }
            }
        }
    }
}