PowerShell - 如何判断两个对象是否相同

PowerShell - How to tell if two objects are identical

提问人:Kellen Stuart 提问时间:11/30/2017 最后编辑:Kellen Stuart 更新时间:10/16/2019 访问量:15469

问:

假设您有两个相同的对象(这意味着它们分别具有相同的属性和相同的值)。

你如何测试平等?

$obj1 & $obj2是相同的

enter image description here

这是我尝试过的:

if($obj1 -eq $obj2)
{
    echo 'true'
} else {
    echo 'false'
}
# RETURNS "false"

if(Compare-Object -ReferenceObject $obj1 -DifferenceObject $obj2)
{
    echo 'true'
} else {
    echo 'false'
}
# RETURNS "false"

编辑

这并不相同

enter image description here

PowerShell 对象 if 语句 条件语句 相等

评论

0赞 Maximilian Burszley 11/30/2017
否则使用,它只会告诉您差异。否则,如果没有回报,则表示成功。Compare-Object -IncludeEqual
0赞 Kellen Stuart 11/30/2017
@TheIncorrigible1不完全是我想要的。如果我将属性添加到 ,仍将返回$obj1-IncludeEqual$true
0赞 Maximilian Burszley 11/30/2017
检查我的答案。它应该按照您的预期工作。
2赞 Bill_Stewart 11/30/2017
不要发布图片输出。使用代码格式并将输出粘贴为文本。
1赞 Bill_Stewart 12/1/2017
@KolobCanyon我没有对你的问题投反对票。也许其他人因为您使用图片而不是粘贴输出文本而投了反对票?(不过,不是我;我认为这是个好问题。

答:

2赞 Maximilian Burszley 11/30/2017 #1

我建议用于此任务:Compare-Object

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赞 Kellen Stuart 11/30/2017
假设你这样做......如果运行上面的代码,它仍然认为等于 ,即使它们不是。我刚刚测试过$obj1 | Add-Member -NotePropertyName 'NewProperty' -NotePropertyValue 'NewValue'$obj1$obj2
0赞 Thomas Glaser 11/30/2017
Compare-Object 用于比较 - 这是不可靠的。例如,使用 - 它说它们是平等的。请参见:stackoverflow.com/a/18346380/1244910ToString()$obj1 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; }; $obj2 = [pscustomobject] @{ 'c' = '6'; 'b' = 7; }
0赞 Maximilian Burszley 12/1/2017
@KolobCanyon 这在事实上是错误的。在我的测试(v2、v5)中,它工作正常。
0赞 Bill_Stewart 12/1/2017
为什么你可以简单地写?if (-not $Test) { $true } else { $false }-not $Test
0赞 Maximilian Burszley 12/1/2017
@Bill_Stewart我太专注于他的问题示例,但你是绝对正确的
5赞 Bill_Stewart 11/30/2017 #2

您可以通过比较两个对象的属性来比较两个对象的属性和值是否相等。例:PSObjectCompare-ObjectPropertiesPSObject

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

如果要在函数中使用它:

function Test-PSCustomObjectEquality {
  param(
    [Parameter(Mandatory = $true)]
    [PSCustomObject] $firstObject,

    [Parameter(Mandatory = $true)]
    [PSCustomObject] $secondObject
  )
  -not (Compare-Object $firstObject.PSObject.Properties $secondObject.PSObject.Properties)
}
-1赞 Kellen Stuart 11/30/2017 #3

我编写了一个函数来检查精确相等:

 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

评论

1赞 Bill_Stewart 12/1/2017
1) 不推荐范围 ID。 2) 大量不必要的工作和开销;一个就可以了(见我的答案)。global:Compare-Object
0赞 Bacon Bits 12/1/2017 #4

这是我使用的功能:

function Test-ObjectEquality {
    param(
        [Parameter(Mandatory = $true)]
        $Object1,
        [Parameter(Mandatory = $true)]
        $Object2
    )

    return !(Compare-Object $Object1.PSObject.Properties $Object2.PSObject.Properties)
}

例子:

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

我当然相信这可能会错过一些东西;但是,如果查看其中的内容,则可以看到对象上每个属性的比较内容:Properties

PS C:\> $obj1.PSObject.Properties | Select-Object -First 1


MemberType      : NoteProperty
IsSettable      : True
IsGettable      : True
Value           : 5
TypeNameOfValue : System.String
Name            : a
IsInstance      : True

我很少关心对象的属性,而不是 、 、 或。MemberTypeNameTypeNameOfValueValue

另外,请注意,如果您确实需要,您可以比较而不是 .这将比较属性和方法,尽管你只比较方法调用,而不是方法定义。.PSObject.Members.PSObject.Properties

1赞 KyleMit 9/6/2018 #5

如果要一次测试一个对象属性的相等性,以便比较和对比两个对象并查看哪些单独的部分不同,则可以使用以下函数,该函数改编自本文,了解如何在 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}

}

然后像这样使用:

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

几个有趣的笔记