PowerShell - How to tell if two objects are identical

后端 未结 5 1508
一个人的身影
一个人的身影 2021-01-24 17:05

Let\'s say you have two objects that are identical (meaning they have the same properties and the same values respectively).

How do you test for equality?

相关标签:
5条回答
  • 2021-01-24 17:12

    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.

    0 讨论(0)
  • 2021-01-24 17:13

    I'd suggest using Compare-Object for this task:

    Function Test-Objects
    {
        Param(
        [Parameter(Mandatory,Position=0)]
        [PSCustomObject]$Obj1,
        [Parameter(Mandatory,Position=1)]
        [PSCustomObject]$Obj2
        )
    
        [Void](Compare-Object -ReferenceObject $Obj1.PSObject.Properties -DifferenceObject.PSObject.Properties $Obj2 -OutVariable 'Test')
    
        ## Tests whether they are equal, no return = success
        If (-not $Test)
        {
            $True
        }
        Else
        {
            $False
        }
    }
    

    PS C:\> $Obj1 = [PSCustomObject]@{
        Property1 = 'Value1'
        Property2 = 'Value2'
        Property3 = 'Value3'
        Property4 = 'Value4'
        Property5 = 'Value5'
    }
    PS C:\> $Obj2 = [PSCustomObject]@{
        Property1 = 'Value1'
        Property2 = 'Value2'
        Property3 = 'Value3'
        Property4 = 'Value4'
        Property5 = 'Value5'
    }
    PS C:\> Test-Objects $Obj1 $Obj2
    True
    PS C:\> $Obj2 | Add-Member -MemberType 'NoteProperty' -Name 'Prop6' -Value 'Value6'
    PS C:\> Test-Objects $Obj1 $Obj2
    False
    
    0 讨论(0)
  • 2021-01-24 17:14

    I wrote a function that checks for exact equality:

     function Global:Test-IdenticalObjects
     {
        param(
            [Parameter(Mandatory=$true)]$Object1,
            [Parameter(Mandatory=$true)]$Object2,
            $SecondRun=$false
        )
    
        if(-not ($Object1 -is [PsCustomObject] -and $Object2 -is [PsCustomObject))
        {
            Write-Error "Objects must be PsCustomObjects"
            return
        }
    
        foreach($property1 in $Object1.PsObject.Properties)
        {
            $prop1_name = $property1.Name
            $prop1_value = $Object1.$prop1_name
            $found_property = $false
            foreach($property2 in $Object2.PsObject.Properties)
            {
                $prop2_name = $property2.Name
                $prop2_value = $Object2.$prop2_name
                if($prop1_name -eq $prop2_name)
                {
                    $found_property = $true
                    if($prop1_value -ne $prop2_value)
                    {
                        return $false
                    }
                }
            } # j loop
            if(-not $found_property) { return $false }
        } # i loop
        if($SecondRun)
        {
            return $true
        } else {
            Test-IdenticalObjects -Object1 $Object2 -Object2 $Object1 -SecondRun $true
        }
     } # function
    
    0 讨论(0)
  • 2021-01-24 17:19

    If you'd like to test for equality for every object property, one at a time, in order to compare and contrast two objects and see which individual pieces are different, you can use the following function, adapted from this article on how to compare all properties of two objects in Windows PowerShell

    Function Compare-ObjectProperties {
        Param(
            [PSObject]$leftObj,
            [PSObject]$rightObj 
        )
    
        $leftProps = $leftObj.PSObject.Properties.Name
        $rightProps = $rightObj.PSObject.Properties.Name
        $allProps = $leftProps + $rightProps | Sort | Select -Unique
    
        $props = @()
    
        foreach ($propName in $allProps) {
    
            # test if has prop
            $leftHasProp = $propName -in $leftProps
            $rightHasProp = $propName -in $rightProps
    
            # get value from object
            $leftVal = $leftObj.$propName
            $rightVal = $rightObj.$propName
    
            # create custom output - 
            $prop = [pscustomobject] @{   
                Match = $(If ($propName -eq "SamAccountName" ) {"1st"} Else {
                            $(If ($leftHasProp -and !$rightHasProp ) {"Left"} Else {
                                $(If ($rightHasProp -and !$leftHasProp ) {"Right"} Else {
                                    $(If ($leftVal -eq $rightVal ) {"Same"} Else {"Diff"})
                                })
                              })
                         })
                PropName = $propName
                LeftVal = $leftVal
                RightVal = $rightVal
            }
    
            $props += $prop
        }
    
        # sort & format table widths
        $props | Sort-Object Match, PropName | Format-Table -Property `
                   @{ Expression={$_.Match}; Label="Match"; Width=6}, 
                   @{ Expression={$_.PropName}; Label="Property Name"; Width=25}, 
                   @{ Expression={$_.LeftVal }; Label="Left Value";    Width=40}, 
                   @{ Expression={$_.RightVal}; Label="Right Value";   Width=40}
    
    }
    

    And then use like this:

    $adUser1 = Get-ADUser 'Grace.Hopper' -Properties *
    $adUser2 = Get-ADUser 'Katherine.Johnson' -Properties *   
    Compare-ObjectProperties $adUser1 $adUser2
    

    Couple Interesting Notes:

    • How to Test if Element Has Property
    • How to Get Property Value by Name
    • How to Create a Custom PS Object
    • How to Create a Nested Conditional / Ternary Operator
    • How to Format Table with fixed Widths
    • Attempted to Colorize output with VT Escape Sequences or Write-PSObject, but couldn't get it to work with fixed column widths which took priority
    0 讨论(0)
  • 2021-01-24 17:27

    You can compare two PSObject objects for equality of properties and values by using Compare-Object to compare the Properties properties of both PSObjectobjects. Example:

    if ( -not (Compare-Object $obj1.PSObject.Properties $obj2.PSObject.Properties) ) {
      "object properties and values match"
    }
    else {
      "object properties and values do not match"
    }
    

    If you want it in a function:

    function Test-PSCustomObjectEquality {
      param(
        [Parameter(Mandatory = $true)]
        [PSCustomObject] $firstObject,
    
        [Parameter(Mandatory = $true)]
        [PSCustomObject] $secondObject
      )
      -not (Compare-Object $firstObject.PSObject.Properties $secondObject.PSObject.Properties)
    }
    
    0 讨论(0)
提交回复
热议问题