PowerShell - Как определить, идентичны ли два объекта

Допустим, у вас есть два идентичных объекта (то есть они имеют одинаковые свойства и одинаковые значения соответственно).

Как вы проверяете на равенство?

пример

$obj1 & $obj2 идентичны

Вот что я попробовал:

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"

редактировать

Это не идентично

5 ответов

Решение

Вы можете сравнить два PSObject объекты на равенство свойств и значений с помощью Compare-Object сравнить Properties свойства обоих PSObjectобъекты. Пример:

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)
}

Я бы предложил использовать 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

Если вы хотите проверить на равенство для каждого свойства объекта, по одному, чтобы сравнить и сопоставить два объекта и увидеть, какие отдельные части отличаются, вы можете использовать следующую функцию, адаптированную из этой статьи о том, как сравнивать все свойства двух объектов в 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

Пара интересных заметок:

Вот функция, которую я использовал:

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

Это не часто, что я заботился о более чем MemberType, Name, TypeNameOfValue, или же Value свойств объекта.

Кроме того, обратите внимание, что если вам действительно нужно, вы можете сравнить .PSObject.Members вместо .PSObject.Properties, Это позволит сравнить свойства и методы, хотя вы сравниваете только вызовы методов, а не определения методов.

Я написал функцию, которая проверяет точное равенство:

 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
Другие вопросы по тегам