Here's the function I used:
function Test-ObjectEquality {
param(
[Parameter(Mandatory = $true)]
$Object1,
[Parameter(Mandatory = $true)]
$Object2
)
return !(Compare-Object $Object1.PSObject.Properties $Object2.PSObject.Properties)
}
Examples:
PS C:\> $obj1 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
True
PS C:\> $obj2 = [psobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = New-Object -TypeName PSObject -Property @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
True
PS C:\> $obj2 = [pscustomobject] @{ 'c' = '6'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 8; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; c = 8 };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = '7'; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
I certainly believe it's possible for this to miss things; however, if you look at what's in Properties you can see what's being compared for every property on an object:
PS C:\> $obj1.PSObject.Properties | Select-Object -First 1
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : 5
TypeNameOfValue : System.String
Name : a
IsInstance : True
It's not often that I've cared about more than the MemberType, Name, TypeNameOfValue, or Value of an object's properties.
Also, note that if you really need to, you can compare .PSObject.Members instead of .PSObject.Properties. That will compare properties and methods, although you're only comparing the method calls and not the method definitions.