functions/schemaLdif/Test-FMSchemaLdif.ps1

function Test-FMSchemaLdif
{
    <#
    .SYNOPSIS
        Tests whether the configured ldif-file-based schema extension has been applied.
     
    .DESCRIPTION
        Tests whether the configured ldif-file-based schema extension has been applied.
     
    .PARAMETER Server
        The server / domain to work with.
     
    .PARAMETER Credential
        The credentials to use for this operation.
     
    .PARAMETER EnableException
        This parameters disables user-friendly warnings and enables the throwing of exceptions.
        This is less user friendly, but allows catching exceptions in calling scripts.
     
    .EXAMPLE
        PS C:\> Test-FMSchemaLdif
 
        Checks the current forest against all configured schema extension files
    #>

    
    [CmdletBinding()]
    Param (
        [PSFComputer]
        $Server,

        [PSCredential]
        $Credential,

        [switch]
        $EnableException
    )
    
    begin
    {
        $parameters = $PSBoundParameters | ConvertTo-PSFHashtable -Include Server, Credential
        $parameters['Debug'] = $false
        Assert-ADConnection @parameters -Cmdlet $PSCmdlet
        Invoke-Callback @parameters -Cmdlet $PSCmdlet
        Assert-Configuration -Type SchemaLdif -Cmdlet $PSCmdlet
        try {
            $rootDSE = Get-ADRootDSE @parameters -ErrorAction Stop
            $forest = Get-ADForest @parameters -ErrorAction Stop
        }
        catch {
            Stop-PSFFunction -String 'Test-FMSchemaLdif.Connect.Failed' -StringValues $Server -ErrorRecord $_ -EnableException $EnableException -Exception $_.Exception.GetBaseException()
            return
        }
        $parameters["Server"] = $forest.SchemaMaster
    }
    process
    {
        foreach ($schemaFile in (Get-FMSchemaLdif)) {
            $countDelta = 0
            $changes = @()

            :setting foreach ($setting in $schemaFile.Settings) {
                if (-not $setting.DistinguishedName) { continue }
                $attributeName = '{0},{1}' -f $setting.DistinguishedName, $rootDSE.schemaNamingContext

                #region Calculate deltas
                try { $adObject = Get-ADObject @parameters -Identity $attributeName -ErrorAction Stop -Properties * }
                catch {
                    $countDelta++
                    $changes += [PSCustomObject]@{
                        LdifName = $schemaFile.Name
                        LdifPath = $schemaFile.Path
                        Type = 'Missing'
                        Object  = $attributeName
                        Properties = @()
                    }
                    continue
                }

                switch ($setting.changetype)
                {
                    #region New Item Definitions
                    'add'
                    {
                        $change = [PSCustomObject]@{
                            LdifName = $schemaFile.Name
                            LdifPath = $schemaFile.Path
                            Type = 'InEqual'
                            Object  = $attributeName
                            Properties = @()
                        }
                        :prop foreach ($property in $setting.PSObject.Properties.Name) {
                            switch ($property) {
                                'DistinguishedName' { continue prop }
                                'changetype' { continue prop }
                                'schemaIDGUID' {
                                    if (($setting.$property.GuidData -join '|') -ne ($adObject.$property -join '|')) {
                                        $countDelta++
                                        $change.Properties += $property
                                    }
                                }
                                'attributeSecurityGUID' {
                                    if (($setting.$property.GuidData -join '|') -ne ($adObject.$property -join '|')) {
                                        $countDelta++
                                        $change.Properties += $property
                                    }
                                }
                                'objectCategory' {
                                    if (($setting.$property -replace '<SchemaContainerDN>',$rootDSE.schemaNamingContext) -ne ($adObject.$property -join '|')) {
                                        $countDelta++
                                        $change.Properties += $property
                                    }
                                }
                                default {
                                    foreach ($item in $setting.$property) {
                                        if ($item -notin $adObject.$property) {
                                            $countDelta++
                                            $change.Properties += $property
                                            continue prop
                                        }
                                    }
                                }
                            }
                        }
                        if ($change.Properties.Count -gt 0) {
                            $changes += $change
                        }
                    }
                    #endregion New Item Definitions

                    #region Deltas
                    'modify'
                    {
                        if ($setting.Add) {
                            $propName = $setting.Add
                            if ($setting.$propName | Where-Object { $_ -notin $adObject.$propName }) {
                                $countDelta++
                                $changes += [PSCustomObject]@{
                                    LdifName = $schemaFile.Name
                                    LdifPath = $schemaFile.Path
                                    Type = 'Missing'
                                    Object  = $attributeName
                                    Properties = @($propName)
                                }
                                continue setting
                            }
                        }
                        elseif ($setting.Replace) {
                            $propName = $setting.Replace
                            if ($setting.$propName -ne $adObject.$propName) {
                                $countDelta++
                                $changes += [PSCustomObject]@{
                                    LdifName = $schemaFile.Name
                                    LdifPath = $schemaFile.Path
                                    Type = 'InEqual'
                                    Object  = $attributeName
                                    Properties = @($propName)
                                }
                                continue setting
                            }
                        }
                        else {
                            $change = [PSCustomObject]@{
                                LdifName = $schemaFile.Name
                                LdifPath = $schemaFile.Path
                                Type = 'InEqual'
                                Object  = $attributeName
                                Properties = @()
                            }
                            :prop foreach ($property in $setting.PSObject.Properties.Name) {
                                switch ($property) {
                                    'DistinguishedName' { continue prop }
                                    'changetype' { continue prop }
                                    'schemaIDGUID' {
                                        if (($setting.$property.GuidData -join '|') -ne ($adObject.$property -join '|')) {
                                            $countDelta++
                                            $change.Properties += $property
                                        }
                                    }
                                    'attributeSecurityGUID' {
                                        if (($setting.$property.GuidData -join '|') -ne ($adObject.$property -join '|')) {
                                            $countDelta++
                                            $change.Properties += $property
                                        }
                                    }
                                    'objectCategory' {
                                        if (($setting.$property -replace '<SchemaContainerDN>',$rootDSE.schemaNamingContext) -ne ($adObject.$property -join '|')) {
                                            $countDelta++
                                            $change.Properties += $property
                                        }
                                    }
                                    default {
                                        foreach ($item in $setting.$property) {
                                            if ($item -notin $adObject.$property) {
                                                $countDelta++
                                                $change.Properties += $property
                                                continue prop
                                            }
                                        }
                                    }
                                }
                            }
                            if ($change.Properties.Count -gt 0) {
                                $changes += $change
                            }
                        }
                    }
                    #endregion Deltas
                }
                #endregion Calculate deltas


            }

            if ($countDelta -gt 0) {
                [PSCustomObject]@{
                    PSTypeName = 'ForestManagement.SchemaLdif.TestResult'
                    Type = 'InEqual'
                    ObjectType = 'SchemaLdif'
                    Identity = $schemaFile.Name
                    Changed = ($changes.Object | Select-Object -Unique)
                    Server = $forest.SchemaMaster
                    DeltaCount = $countDelta
                    Changes = $changes
                    ADObject = $null
                    Configuration = $schemaFile
                }
            }
        }
    }
}