Compare-ObjectProperty.ps1


<#PSScriptInfo
 
.VERSION 1.0.0.0
 
.GUID 32a4f2d6-b021-4a38-8b6a-d76ceef2b02d
 
.AUTHOR Jeffrey Snover
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
#>


<#
 
.DESCRIPTION
 Determine the difference in properties between two objects.
 
 NOTE - if a property's type does not have a CompareTo() function, the property is converted to a
 string for the comparison
 
.EXAMPLE
$o1= @{a1=1;a2=2;b1=3;b2=4}
PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5}
PS C:\> Compare-ObjectProperty $o1 $o2
 
InputObject SideIndicator
----------- -------------
b2 = 4 <==
b2 = 5 ==>
.EXAMPLE
$o1= @{a1=1;a2=2;b1=3;b2=4}
PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5}
PS C:\> Compare-ObjectProperty $o1 $o2 -PropertyFilter a*
 
.EXAMPLE
$o1= @{a1=1;a2=2;b1=3;b2=4}
PS C:\> $o2= @{a1=1;a2=2;b1=3;b2=5}
PS C:\> Compare-ObjectProperty $o1 $o2 -IncludeEqual
InputObject SideIndicator
----------- -------------
a1 = 1 ==
a2 = 2 ==
b1 = 3 ==
b2 = 4 <==
b2 = 5 ==>
 
#>
 
[CmdletBinding()]
param(
    [Parameter(Mandatory=$true, Position=0)]
    [object]
    ${ReferenceObject},

    [Parameter(Mandatory=$true, Position=1)]
    [object]
    ${DifferenceObject},

    #You can specify which properties to compare using a wildcard (using the -LIKE operator)
    [String]
    ${PropertyFilter}="*",

    #Don't include any properties that are different
    [switch]
    ${ExcludeDifferent},

    #Include the properties which are equal
    [switch]
    ${IncludeEqual}
    )


#region Helper Routines
function Convert-PropertyToHash
{
param([Parameter(Position=0)]$inputObject)

    if ($inputObject -eq $null)
    {
        return @{}
    }
    elseif ($inputObject -is [HashTable])
    {
        #We have to clone the hashtable because we are going to Remove Keys and if we don't
        #clone it, we'll modify the original object
        return $inputObject.clone()
    }
    else
    {
        $h = @{}
        foreach ($p in (Get-Member -InputObject $inputObject -MemberType Properties).Name)
        {
            $h.$p = $inputObject.$p
        }
        return $h
    }
}
#endregion

   
$refH  = Convert-PropertyToHash $ReferenceObject
$diffH = Convert-PropertyToHash $DifferenceObject

foreach ($p in $refH.keys |where {$_ -like $PropertyFilter})
{
    if (! ($diffH.Contains($p)) -and !($ExcludeDifferent))
    {
        Write-Output (New-object PSObject -Property @{ SideIndicator="<=="; InputObject="$p = $($refH.$p)"})
    }else
    {
        #We convert these to strings and do a string comparison because there are all sorts of .NET
        #objects whose comparison functions don't yeild the expected results.
        if ($refH.$p -AND ($refH.$p |Get-Member -MemberType Method -Name CompareTo))
        {
            $Different = $refH.$p -ne $diffH.$p
        }
        else
        {
            $Different = (""+$refH.$p) -ne (""+$diffH.$p) 
        }
        if ($Different -and !($ExcludeDifferent))
        {
            Write-Output (New-object PSObject -Property @{ SideIndicator="<=="; InputObject="$p = $($refH.$p)"})
            Write-Output (New-object PSObject -Property @{ SideIndicator="==>"; InputObject="$p = $($diffH.$p)"})
        }
        elseif ($IncludeEqual)
        {
            Write-Output (New-object PSObject -Property @{ SideIndicator="=="; InputObject="$p = $($refH.$p)"})
        }
        $diffH.Remove($p)
    }
}
if (!($ExcludeDifferent))
{
    foreach ($p in $diffH.keys|where {$_ -like $PropertyFilter})
    {
        Write-Output (New-Object PSObject -Property @{ SideIndicator="==>"; InputObject="$p = $($diffH.$p)"})
    }
}