Functions/Compare-PSObjects.ps1

function Compare-PSObjects {
<#
.SYNOPSIS
    Compares two objects property by property.
.DESCRIPTION
    The result will only contain missing and/or value differens from master object. Output object is populated with property names with two child properties - 'Ref' and 'Diff'.
    The 'Ref' property contains the Reference data and the 'Diff' property has the Difference data. If the Difference object is missing the property the value will be $null.
 
    Output object is null if all data in Reference object is present in the Difference objeect, but we do not care if the Difference object has more properties.
.PARAMETER Reference
    The source object, or master object if you will
.PARAMETER Difference
    The target object in the comparison
.EXAMPLE
     
    $a = New-Object psobject -Prop ([ordered] @{ One = 1; Two = 2; Three = 3})
    $b = New-Object psobject -Prop ([ordered] @{ One = 1; Two = 2})
   
    Compare-PSObjects $a $b
 
    Three
    -----
    @{Ref=3; Diff=}
 
.EXAMPLE
    This will create a JSON output according to missing items in the .\badcopy.json file
 
    Compare-PSObjects -Reference (Get-Content -raw ".\template.json" | ConvertFrom-Json) -Difference (Get-Content -raw ".\badcopy.json" | ConvertFrom-Json) | ConvertTo-Json -Depth 10
   
.OUTPUTS
    [PSCustomObject]
 
#>


    [CmdletBinding(SupportsShouldProcess = $False)]
    param (
        [Parameter(Mandatory)]
        [PSObject]$Reference,
        [Parameter(Mandatory)]
        [PSObject]$Difference
    )
    begin {
        #Write-Verbose -Message "Starting [$($MyInvocation.Mycommand)]"
    }

    process {
        #Hashtable
        $Result=[ordered]@{}
        

        #Custom object from Json-File
        foreach($property in $Reference.psobject.properties.name) {            
            Write-Verbose ("Property: " + $property)

            if ($Reference.$property.GetType().Name -match "Object$") {
                Write-Verbose ("Recurse: " + $Reference.$property + " [" + $Reference.$property.GetType().Name +"]")
                $diff=$null
                $diff=Compare-PSObjects -Reference $Reference.$property -Difference $Difference.$property -Verbose:$VerbosePreference
                if ($diff) {
                    $Result.Add($property,$diff)
                }
            } else {    
                if ($Reference.$property.count -eq 1) {            
                    if ($Reference.$property -ne $Difference.$property) {
                        $Result.Add("$property",[PSCustomObject]@{Ref=$Reference.$property;Diff=$Difference.$property})
                    }                    
                } else {
                    $PropertyDiffs=@()
                    for ($n=0;$n -lt $Reference.$property.count ; $n++) {                        
                        if ($Reference.$property[$n].GetType().Name -match "Object$") {
                            if (!$Difference.$property[$n]) {
                                $PropertyDiffs+=[PSCustomObject]@{Ref=$Reference.$property[$n];Diff=$null}
                            } else {
                                Write-Verbose ("Recurse: $property[$n] [" + $Reference.$property[$n].GetType().Name +"]")                            
                                $PropertyDiffs+=Compare-PSObjects -Reference $Reference.$property[$n] -Difference $Difference.$property[$n] -Verbose:$VerbosePreference
                            }
                        } else {                            
                            if (!$Difference.$property -or !$Difference.$property[$n]) {
                                $PropertyDiffs+=[PSCustomObject]@{Ref=$Reference.$property[$n];Diff=$null}
                            } else {
                                if ($Reference.$property[$n] -ne $Difference.$property[$n]) {
                                    $PropertyDiffs+=[PSCustomObject]@{Ref=$Reference.$property[$n];Diff=$Difference.$property[$n]}
                                }
                            }
                        }
                    }
                    if ($PropertyDiffs.Count -gt 0) {$Result.Add("$property",$PropertyDiffs)}
                }
            }
        }

        #Return PSCustomObject from Hashtable
        if ($Result.Count -gt 0) {return [pscustomobject]$Result}
    }

    end {
        #Write-Verbose -Message "Ending [$($MyInvocation.Mycommand)]"
    }

}