functions/GroupMembership/Test-LdsGroupMembership.ps1

function Test-LdsGroupMembership {
    <#
    .SYNOPSIS
        Test whether the group memberships are in their desired state.
     
    .DESCRIPTION
        Test whether the group memberships are in their desired state.
     
    .PARAMETER Server
        The LDS Server to target.
     
    .PARAMETER Partition
        The Partition on the LDS Server to target.
     
    .PARAMETER Credential
        Credentials to use for the operation.
     
    .PARAMETER Delete
        Undo everything defined in configuration.
        Allows rolling back after deployment.
     
    .EXAMPLE
        PS C:\> Test-LdsGroupMembership -Server lds1.contoso.com -Partition 'DC=fabrikam,DC=org'
         
        Test whether the group memberships are in their desired state for 'DC=fabrikam,DC=org' on lds1.contoso.com
    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true)]
        [string]
        $Server,

        [Parameter(Mandatory = $true)]
        [string]
        $Partition,

        [PSCredential]
        $Credential,

        [switch]
        $Delete
    )
    
    begin {
        Update-LdsConfiguration -LdsServer $Server -LdsPartition $Partition
        $ldsParam = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Partition, Credential
        $ldsParamLight = $ldsParam | ConvertTo-PSFHashtable -Remap @{ Partition = 'SearchBase' }

        $members = @{ }
        $ldsObjects = @{ }
    }
    process {
        foreach ($configurationSets in $script:content.groupmembership.Values | Group-Object { $_.Group }) {
            Write-PSFMessage -Level Verbose -Message "Processing group memberships of {0}" -StringValues $configurationSets.Name
            $groupObject = Get-ADGroup @ldsParamLight -LDAPFilter "(name=$($configurationSets.Name))" -Properties *
            if (-not $groupObject) {
                Write-PSFMessage -Level Warning -Message "Group not found: {0}! Cannot process members" -StringValues  $configurationSets.Name
                continue
            }
            $ldsObjects[$groupObject.DistinguishedName] = $groupObject

            #region Determine intended members
            $intendedMembers = foreach ($entry in $configurationSets.Group) {
                # Read from Cache
                if ($members["$($entry.Type):$($entry.Member)"]) {
                    $members["$($entry.Type):$($entry.Member)"]
                    continue
                }

                # Read from LDS Instance
                $ldsObject = Get-ADObject @ldsParamLight -LDAPFilter "(&(objectClass=$($entry.Type))(name=$($entry.Member)))" -Properties *
                
                # Not Yet Created
                if (-not $ldsObject) {
                    Write-PSFMessage -Level Warning -Message 'Unable to find {0} {1}, will be unable to add it to group {2}' -StringValues $entry.Type, $entry.Member, $entry.Group
                    continue
                }

                $members["$($entry.Type):$($entry.Member)"] = $ldsObject
                $ldsObjects[$ldsObject.DistinguishedName] = $ldsObject
                $ldsObject
            }
            #endregion Determine intended members

            #region Determine actual members
            $actualMembers = foreach ($member in $groupObject.Members) {
                if ($ldsObjects[$member]) {
                    $ldsObjects[$member]
                    continue
                }

                try { $ldsObject = Get-ADObject @ldsParam -Identity $member -Properties * -ErrorAction Stop }
                catch {
                    Write-PSFMessage -Level Warning -Message "Error resolving member of {0}: {1}" -StringValues $configurationSets.Name, $member -ErrorRecord $_
                    continue
                }
                $ldsObjects[$ldsObject.DistinguishedName] = $ldsObject
                $ldsObject
            }
            #endregion Determine actual members
        
            #region Compare and generate changes
            $toAdd = $intendedMembers | Where-Object DistinguishedName -NotIn $actualMembers.DistinguishedName | ForEach-Object {
                [PSCustomObject]@{
                    PSTypename = 'AdLdsTools.Change.GroupMembership'
                    Action     = 'Add'
                    Member     = $_.Name
                    Type       = $_.ObjectClass
                    DN         = $_.DistinguishedName
                    Group      = $configurationSets.Name
                }
            }
            if ($Delete) { $toAdd = @() }

            $toRemove = $actualMembers | Where-Object {
                (-not $Delete -and $_.DistinguishedName -NotIn $intendedMembers.DistinguishedName) -or
                ($Delete -and $_.DistinguishedName -in $intendedMembers.DistinguishedName)
            } | ForEach-Object {
                [PSCustomObject]@{
                    PSTypename = 'AdLdsTools.Change.GroupMembership'
                    Action     = 'Remove'
                    Member     = $_.Name
                    Type       = $_.ObjectClass
                    DN         = $_.DistinguishedName
                    Group      = $configurationSets.Name
                }
            }

            $changes = @($toAdd) + @($toRemove) | Remove-PSFNull | Add-Member -MemberType ScriptMethod -Name ToString -Value {
                '{0} -> {1}' -f $this.Action, $this.Member
            } -Force -PassThru
            #endregion Compare and generate changes

            if ($changes) {
                New-TestResult -Type GroupMemberShip -Action Update -Identity $groupObject.Name -ADObject $groupObject -Configuration $configurationSets -Change $changes
            }
        }
    }
}