Két objektum tulajdonságainak összehasonlítása (Compare-Property)

Gyakran adódik olyan helyzet, hogy nem egy konkrét tulajdonságra akarunk keresni, hanem két hasonló objektumot akarunk összehasonlítani és feltárni a tulajdonságaik közti különbségeket. Ugyan létezik a Compare-Object cmdlet, de ez a nevével ellentétben nem objektumokat, hanem gyűjteményeket hasonlít össze. Kellene készíteni egy Compare-Property függvényt!

A nehézség abban rejlik, hogy hogy itt nem csak háromfajta eset lehetséges az összehasonlítás során (<=, ==, =>), hanem több is, ráadásul ezek nem is teljesen egyértelműek. Természetesen a két objektum azonos nevű tulajdonságai lehetnek egyformák (==) és jelöljük a nyilakkal (<=, =>) azt, ha csak az egyikben vagy csak a másikban van meg az adott tulajdonság. Viszont, ha mindkettőben megvan ugyanaz a tulajdonság, csak más az értékük, akkor azt jelölhetjük ezzel: <>.

Kezdjük tehát összerakni ezt az összehasonlító függvényt!

function Compare-Property1 {

param(

    $referenceobject,

    $differenceobject

)

   

    $allprops = @()

    $rp = @()

    $dp = @()

    $rs = "r:"

    $ds = "d:"

 

    if($referenceobject){

        $rp = $referenceobject.psobject.Properties |

                Select-Object -ExpandProperty Name

        $allprops = @($rp)

        $rs += $referenceobject.tostring()

    }

 

    if($differenceobject){

        $dp = $differenceobject.psobject.Properties |

                Select-Object -ExpandProperty Name

        foreach($p in $dp){

            if($allprops -notcontains $p){

                $allprops += $p

            }

        }

        $ds += $differenceobject.tostring()

    }

 

    foreach($p in ($allprops | Sort-Object)){

        $ra = $referenceobject.$p

        $da = $differenceobject.$p

        $rtype = if($null -eq $ra){"NULL"}else{$ra.gettype().fullname}

        $dtype = if($null -eq $da){"NULL"}else{$da.gettype().fullname}

 

        if($null -eq $ra -and $null -ne $da){

            $equal = "=>"

        }

        elseif($null -ne $ra -and $null -eq $da){

            $equal = "<="

        }

        elseif($rtype -ne $dtype){

            $equal = "<>"

        }

        elseif($ra -is [collections.ilist]){

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da){

                $equal = "<>"

            } 

            else{

                $equal = "=="

            }

        }

        elseif($ra -is [collections.idictionary]){

            $ra = @($ra.getenumerator())

            $da = @($da.getenumerator())

 

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da -Property Key, Value){

                $equal = "<>"

            }

            else{

                $equal = "=="

            }

        }

        else{

            $equal = if($ra -eq $da){"=="}else{"<>"}

        }

 

        [pscustomobject]@{

            Property = $p

            Equal    = $equal

            $rs      = $ra

            $ds      = $da

        }

    }

}

Két paraméterünk van egyelőre, a $referenceobject és a $differenceobject. Az $allprops-ban gyűjtöm az összes tulajdonságnevet, az $rp-ben a referencia tulajdonságneveit, a $dp-ben a differenciáét. Miután a végeredményből egy táblázatot szeretnék, az egyik oszlopnévben a differencia objektumra akarok hivatkozni, ennek az oszlopnak a neve „r:”-al kezdődik, hasonlóan a másik „d:”-al, ezeket az $rs és $ds változókba rakom, amiket majd megtoldom az adott objektumok sztringesített változatával.

A tulajdonságnevek gyűjtögetése utáni foreach ciklusban végig megyek a sorba rakott összes tulajdonságon és kitalálom, hogy vajon az adott tulajdonságok értékei a két objektumban vajon milyen viszonyban vannak egymással a fenti négy lehetőség közül. Az egyformaság egyik döntő kérdése, hogy vajon egyforma típusúak-e a tulajdonság értékei? Mert ha nem, akkor nem is nagyon kell tovább vizsgálgatni őket, hanem az eredmény „<>” lesz. Így az egyes típusokat az $rtype és $dtype változókba beteszem, itt külön eset, ha valamelyik $null, hiszen a semminek nincs tulajdonsága, ezért erre én „NULL”-t teszek oda be.

Előtte még attól függően, hogy a referencia vagy differencia objektum üres-e generálom a $equal változóba a „=>” vagy „<=” nyilakat. A típusok különbözőségének vizsgálata után már a következő elseif ágban már elég a referencia objektum típusára kitételeket tenni, hiszen a másik objektum is, ha már idáig eljutottunk, akkor ugyanolyan. Ha tehát egyik objektum tömbszerű ([collections.ilist]), akkor a Compare‑Object-el határozhatom meg az egyformaságukat. Ha a Compare-Object-nek van kimenete, akkor az azt jelenti, hogy nem egyforma a kettő, ha nincs kimenet, akkor egyforma.

Hasonlóan ehhez, a következő elseif-ben, ha szótárszerűek ([collections.idictionary]) az objektumok, akkor előbb tömbbé alakítom a szótárakat a GetEnumerator() metódussal és utána már szintén a Compare-Object-el hasonlítom őket össze.

A legvégén már a sima -eq operátorral hasonlítom össze őket. Kimenetként egyedi objektumokat bocsátok ki, melynek első tulajdonsága maga a vizsgált tulajdonság neve ($p), majd az összehasonlítás eredménye ($equal), majd a referencia objektum, végül a differencia objektum adott tulajdonságának értéke.

Nézzük meg működés közben is a függvényt! Ehhez kreálok két egyéni objektumot, amely rendelkezik mindenféle típusú tulajdonsággal:

$o1 = [pscustomobject]@{

    értékegyforma = 1

    értékkülönböző = "bla"

    hashegyforma = @{

        key1 = "bla"

        Key2 = "BlaBla"

    }

    hashkülönböző = @{

        keyegy = 1

        keykettő = 2

    }

    tömbegyforma = 1,2,3

    tömbkülönböző = 'a', 'b'

    kétfajtasemmi = ""

    semmi = $null

    csakitt = "szöveg"

}

 

$o2 = [pscustomobject]@{

    értékegyforma = 1

    értékkülönböző = "kakukk"

    hashegyforma = @{

        key1 = "bla"

        Key2 = "BlaBla"

    }

    hashkülönböző = @{

        keyegy = 5

        keyhárom = 3

    }

    tömbegyforma = 1,2,3

    tömbkülönböző = 'c', 'b'

    kétfajtasemmi = @()

    semmi = $null

}

Van itt minden, mint a búcsúban! Egyforma és különböző érték típusú tulajdonság, egyforma és különböző hashtábla, egyforma és különböző tömb, különböző és egyforma „semmi” és végül egy olyan tulajdonság, ami csak a referencia objektumban van. Ezeket összehasonlítva ezt kapjuk:

PS C:\> Compare-Property1 -referenceobject $o1 -differenceobject $o2

 

Property       Equal r:                 d:

--------       ----- --                 --

csakitt        <=    szöveg

értékegyforma  ==    1                  1

értékkülönböző <>    bla                kakukk

hashegyforma   ==    {key1, Key2}       {key1, Key2}

hashkülönböző  <>    {keykettő, keyegy} {keyegy, keyhárom}

kétfajtasemmi  <>                       {}

semmi          ==

tömbegyforma   ==    {1, 2, 3}          {1, 2, 3}

tömbkülönböző  <>    {a, b}             {c, b}

Az eredmény a várakozásunknak megfelelő lett! Mivel lehetne ezt még továbbfejleszteni? Vegyünk fel további paramétereket, amelyekkel lehet szűrni az eredményeket:

$includeequal : alapban az egyformákat nem jelenítjük meg, csak ha ezt a kapcsolót használjuk

$excludedifferent : alapban a különbözőket jelenítjük meg, de ezzel a kapcsolóval elrejthetjük azokat

$property : csak mely tulajdonságok között keressen

$exclude : mely tulajdonságokat hagyjon ki

Különösebben nem is magyarázom a 2. verziót, nézzük a függvényt:

function Compare-Property2 {

param(

    $referenceobject,

    $differenceobject,

    [switch] $includeequal,

    [switch] $excludedifferent,

    [string[]] $property = "*",

    [string[]] $exclude

)

   

    $allprops = @()

    $rp = @()

    $dp = @()

    $rs = "r:"

    $ds = "d:"

 

    if($referenceobject){

        $rp = $referenceobject.psobject.Properties |

                Select-Object -ExpandProperty Name

        $allprops = @($rp)

        $rs += $referenceobject.tostring()

    }

 

    if($differenceobject){

        $dp = $differenceobject.psobject.Properties |

                Select-Object -ExpandProperty Name

        foreach($p in $dp){

            if($allprops -notcontains $p){

                $allprops += $p

            }

        }

        $ds += $differenceobject.tostring()

    }

 

    $allprops = $allprops | Where-Object {

            $pp = $_

            ($property | Where-Object {$pp -like $_}) -and !($exclude | Where-Object {$pp -like $_})

        } | Sort-Object

 

    foreach($p in ($allprops | Sort-Object)){

        $ra = $referenceobject.$p

        $da = $differenceobject.$p

        $rtype = if($null -eq $ra){"NULL"}else{$ra.gettype().fullname}

        $dtype = if($null -eq $da){"NULL"}else{$da.gettype().fullname}

 

        if($null -eq $ra -and $null -ne $da){

            $equal = "=>"

        }

        elseif($null -ne $ra -and $null -eq $da){

            $equal = "<="

        }

        elseif($rtype -ne $dtype){

            $equal = "<>"

        }

        elseif($ra -is [collections.ilist]){

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da){

                $equal = "<>"

            } 

            else{

                $equal = "=="

            }

        }

        elseif($ra -is [collections.idictionary]){

            $ra = @($ra.getenumerator())

            $da = @($da.getenumerator())

 

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da -Property Key, Value){

                $equal = "<>"

            }

            else{

                $equal = "=="

            }

        }

        else{

            $equal = if($ra -eq $da){"=="}else{"<>"}

        }

 

        if((!$excludedifferent -and $equal -ne '==') -or ($includeequal -and $equal -eq '==')){

            [pscustomobject] @{

                Property = $p

                Equal = $equal

                $rs = $referenceobject.$p

                $ds = $differenceobject.$p

            }

        }

    }

}

 Nézzük, ez hogyan működik:

PS C:\> Compare-Property2 -referenceobject $o1 -differenceobject $o2

 

Property       Equal r:                 d:

--------       ----- --                 --

csakitt        <=    szöveg

értékkülönböző <>    bla                kakukk

hashkülönböző  <>    {keykettő, keyegy} {keyegy, keyhárom}

kétfajtasemmi  <>                       {}

tömbkülönböző  <>    {a, b}             {c, b}

Ebben a 2. verzióban tehát alapban csak a különbözőségek látszanak, vegyük hozzá az egyformákat is:

PS C:\> Compare-Property2 -referenceobject $o1 -differenceobject $o2 -inc

ludeequal

 

Property       Equal r:                 d:

--------       ----- --                 --

csakitt        <=    szöveg

értékegyforma  ==    1                  1

értékkülönböző <>    bla                kakukk

hashegyforma   ==    {key1, Key2}       {key1, Key2}

hashkülönböző  <>    {keykettő, keyegy} {keyegy, keyhárom}

kétfajtasemmi  <>                       {}

semmi          ==

tömbegyforma   ==    {1, 2, 3}          {1, 2, 3}

tömbkülönböző  <>    {a, b}             {c, b}

Szűkítsük le az eredményeket az „é” vagy „t” betűkkel kezdődő tulajdonságokra, de azért a dupla „k” betűt tartalmazókat vegyük ki:

PS C:\> Compare-Property2 -referenceobject $o1 -differenceobject $o2 -inc

ludeequal -property é*, t* -exclude *kk*

 

Property      Equal        r:        d:

--------      -----        --        --

értékegyforma ==            1         1

tömbegyforma  ==    {1, 2, 3} {1, 2, 3}

tömbkülönböző <>       {a, b}    {c, b}

A harmadik verzióban vezessünk be egy újabb szűrési lehetőséget, ahol elrejtjük a „semmit” tartalmazó sorokat. Semmi szerepelhet az egyik objektumnál, vagy mindkettőnél, vegy lehet olyan is, hogy pont a semmiket tartalmazó sorokat akarjuk megjeleníteni. Itt a „semmi” nem csak a tényleges $null-t, hanem az üres sztringet, üres tömböt, üres hashtáblát és a [system.dbnull]-t is jelentheti. Azaz az új paraméter legyen az, hogy $hide, ennek lehetséges értékei lehetnek: 'None', 'Empty', 'NonEmpty', 'BothEmpty', alapban az értéke ’None’, azaz nem rejtünk el semmit. Ezt a kiterjesztett „semmit” ki kell számolni, úgyhogy a függvényünk ezekkel a részekkel bővül, plusz még kiszűröm az AliasProperty típusú tulajdonságokat, valamint a „=>” és „<=” eredményeket rendelem azokhoz az esetekhez, ahol az egyik tulajdonság ezen kiterjesztett „semmi”, de a másik nem az:

function Compare-Property3 {

param(

    $referenceobject,

    $differenceobject,

    [switch] $includeequal,

    [switch] $excludedifferent,

    [string[]] $property = "*",

    [string[]] $exclude,

    [ValidateSet('None','Empty','NonEmpty','BothEmpty')] $hide = 'None'

)

 

    $allprops = @()

    $rp = @()

    $dp = @()

    $rs = 'r:'

    $ds = 'd:'

 

    if($null -ne $referenceobject){

        $rp = $referenceobject.psobject.Properties |

                Where-Object {$_.membertype -ne 'AliasProperty'} |

                    Select-Object -ExpandProperty Name

        $allprops = @($rp)

        $rs = "r:" + $referenceobject.tostring()

    }

 

    if($null -ne $differenceobject){

        $dp = $differenceobject.psobject.Properties |

                Where-Object {$_.membertype -ne 'AliasProperty'} |

                    Select-Object -ExpandProperty Name

        foreach($p in $dp){

            if($allprops -notcontains $p){

                $allprops += $p

            }

        }

        $ds = "d:" + $differenceobject.tostring()

    }

 

    $allprops = $allprops | Where-Object {

            $pp = $_

            ($property | Where-Object {$pp -like $_}) -and !($exclude | Where-Object {$pp -like $_})

        } | Sort-Object

 

    foreach($p in $allprops){

        $ra = $referenceobject.$p

        $da = $differenceobject.$p

        $raempty = $null -eq $ra -or

                    '' -eq $ra -or

                    (($ra -is [collections.ilist] -or $ra -is [Collections.IDictionary]) -and $ra.count -eq 0) -or

                    $ra -is [System.DBNull]

        $daempty = $null -eq $da -or

                    '' -eq $da -or

                    (($da -is [collections.ilist] -or $da -is [Collections.IDictionary]) -and $da.count -eq 0) -or

                    $ra -is [System.DBNull]

        $rtype = if($null -eq $ra){"NULL"}else{$ra.gettype().fullname}

        $dtype = if($null -eq $da){"NULL"}else{$da.gettype().fullname}

 

        if($hide -eq 'Empty' -and ($raempty -or $daempty)){

            continue

        }

        elseif($hide -eq 'BothEmpty' -and $raempty -and $daempty){

            continue

        }

        elseif($hide -eq 'NonEmpty' -and (!$raempty -or !$daempty)){

            continue

        }

 

        if(($raempty -and !$daempty) -or ($dp -contains $p -and $rp -notcontains $p)){

            $equal = "=>"

        }

        elseif((!$raempty -and $daempty) -or ($rp -contains $p -and $dp -notcontains $p)){

            $equal = "<="

        }

        elseif($rtype -ne $dtype){

            $equal = "<>"

        }

        elseif($ra -is [collections.ilist]){

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da){

                $equal = "=="

            }

            else{

                $equal = "<>"

            }

        }

        elseif($ra -is [collections.idictionary]){

            $ra = @($ra.GetEnumerator())

            $da = @($da.GetEnumerator())

            if(Compare-Object -ReferenceObject $ra -DifferenceObject $da -Property Key, Value){

                $equal = "<>"

            }

            else{

                $equal = "=="

            }

        }           

        else{

            $equal = if($ra -eq $da){"=="}else{"<>"}

        }

 

        if((!$excludedifferent -and $equal -ne '==') -or ($includeequal -and $equal -eq '==')){

            [pscustomobject] @{

                Property = $p

                Equal = $equal

                $rs = $referenceobject.$p

                $ds = $differenceobject.$p

            }

        }

    }

}

 És akkor nézzünk néhány példát ennek a paraméternek a használatára is:

PS C:\> Compare-Property3 -referenceobject $o1 -differenceobject $o2 -incl

udeequal -hide Empty

 

Property       Equal                 r:                 d:

--------       -----                 --                 --

értékegyforma  ==                     1                  1

értékkülönböző <>                   bla             kakukk

hashegyforma   ==          {key1, Key2}       {key1, Key2}

hashkülönböző  <>    {keykettő, keyegy} {keyegy, keyhárom}

tömbegyforma   <>             {1, 2, 3}          {1, 2, 3}

tömbkülönböző  ==                {a, b}             {c, b}

Itt a „-hide Empty” opciót választottam, és így az eredményből ki is maradtak azok a sorok, ahol az egyik vagy másik tulajdonság „semmi” volt. A következő példában meg pont azokat rejtem el, ahol egyik sem „semmi”:

PS C:\> Compare-Property3 -referenceobject $o1 -differenceobject $o2 -incl

udeequal -hide NonEmpty

 

Property      Equal r: d:

--------      ----- -- --

kétfajtasemmi <>       {}

semmi         ==

Az utolsó verzió - szintén 2 év múlva - a következő:

function Compare-Property {

<#

.Synopsis

   Compares properties of objects or keys of hashtables.

.DESCRIPTION

   This function compares properties of two objects or keys of two hashtables recursively and returns a set of custom objects describing the differences.

.EXAMPLE

    $f1 = Get-Item C:\Windows\notepad.exe; $f2 = Get-Item C:\Windows\System32\notepad.exe; Compare-Property -ReferenceObject $f1 -DifferenceObject $f2

 

    This expression compares the properties of 2 notepad.exe files and returns all properties that are different.

.EXAMPLE

   $f1 = Get-Item C:\Windows\notepad.exe; $f2 = Get-Item C:\Windows\System32\notepad.exe; Compare-Property -ReferenceObject $f1 -DifferenceObject $f2 -IncludeEqual -ExcludeDifferent -Exclude PS*

 

   In this example we compare the properties of the two notepad.exe file objects, exclude the properties that are different but include properties that are equal. We also exclude all properties whose name start with PS.

.EXAMPLE

    Compare-Property -ReferenceObject @{Name = 'First'; Number = 1; Array = 1,2; RefEmpty = $null} -DifferenceObject @{Name = 'Second'; Number = 2; Array = 2,3; DiffEmpty = @()} -Hide Empty -NameProperty Name -Exclude Name

 

    In this example we compare the keys of two hashtables. We exclude those properties that contain 'empty' values ($null, empty array, empty hashtables, System.DBNull) in either input objects.

    We also include in the column names the content of the Name property of the respective hashtables, but exclude the Name property from the differences.

.INPUTS

   hashtable or psobject

.OUTPUTS

   Collection of custom objects having a Property, Relation and 'r:<reference object ID>', 'd:<difference object ID>' properties.

#>

[cmdletbinding()]

param(

    # The reference object or hashtable

    [Parameter(Mandatory = $true)] [AllowNull()][psobject] $ReferenceObject,

    # The difference object or hashtable

    [Parameter(Mandatory = $true)] [AllowNull()][psobject] $DifferenceObject,

    # Include equal properties/keys in the result

    [switch] $IncludeEqual,

    # Exclud differences from the result

    [switch] $ExcludeDifferent,

    # Include properties/keys to compare

    [string[]] $Property = "*",

    # Exclude properties/keys to compare

    [string[]] $Exclude,

    # Use this property or the result of executing the scriptblock as the name for the objects

    [ValidateScript({$_ -is [string] -or $_ -is [scriptblock]})] [psobject] $NameProperty,

    # Hide certain type of empty properties

    [string] [ValidateSet('None','Empty','NonEmpty','BothEmpty')] $Hide = 'None',

    [Parameter(Dontshow = $true)][int] $_Depth = 1,

    # Maximum depth of recursion, default is 5

    [int] $MaxDepth = 5

)

 

    $equal = $null

    $rObjName = ''

    $dObjName = ''

 

    if($null -eq $ReferenceObject -and $null -eq $DifferenceObject){

        $rObjName = '$null'

        $dObjName = '$null'

        $equal = "=="

    }

    elseif($null -eq $ReferenceObject -or $null -eq $DifferenceObject){

        if($null -eq $ReferenceObject){

            $rObjName = '$null'

            $equal = "=>"

        }

        else{

            $dObjName = '$null'

            $equal = "<="

        }

    }

    elseif($ReferenceObject.GetType().FullName -ne $DifferenceObject.GetType().FullName -and $PSBoundParameters.ContainsKey('_Depth')){

        $equal = "<>"

    }

    elseif($ReferenceObject -is [scriptblock] -and $PSBoundParameters.ContainsKey('_Depth')){

        if($ReferenceObject.ToString() -eq $DifferenceObject.tostring()){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

    elseif($ReferenceObject -is [datetime] -and $PSBoundParameters.ContainsKey('_Depth')){

        if($ReferenceObject -eq $DifferenceObject){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

    elseif($ReferenceObject.gettype().fullname -in 'System.RuntimeType', 'System.Reflection.RuntimeAssembly'){

        return

    }

    elseif($ReferenceObject -is [System.IO.FileSystemInfo] -and $PSBoundParameters.ContainsKey('_Depth')){

        if($ReferenceObject.fullname -eq $DifferenceObject.fullname){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

    elseif($ReferenceObject -is [string]){

        if($ReferenceObject -eq $DifferenceObject){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

    elseif($ReferenceObject -as [double] -and $DifferenceObject -as [double]){

        if($ReferenceObject -eq $DifferenceObject){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

    elseif($ReferenceObject -is [system.collections.ilist]){

        if($ReferenceObject.psbase.count -ne $DifferenceObject.psbase.count){

            $equal = "<>"

        }

        else{

            $equal = "=="

            for($i = 0; $i -lt $ReferenceObject.psbase.count; $i++){

                $diff = Compare-Property -ReferenceObject $ReferenceObject[$i] -DifferenceObject $DifferenceObject[$i] -_Depth ($_Depth + 1)

                if($diff){

                    $equal = "<>"

                    break

                }

            }

        }

    }

 

    if($NameProperty){

        if($NameProperty -is [string]){

            if(!$rObjName){

                $rObjName = $ReferenceObject.$NameProperty

            }

            if(!$dObjName){

                $dObjName = $DifferenceObject.$NameProperty

            }

        }

        else{

            if(!$rObjName){

                $rObjName = $ReferenceObject | &{process{ & $NameProperty}}

            }

            if(!$dObjName){

                $dObjName = $DifferenceObject | &{process{ & $NameProperty}}

            }

        }

    }

    else{

        if(!$rObjName){

            $rObjName = $ReferenceObject.tostring()

        }

        if(!$dObjName){

            $dObjName = $DifferenceObject.tostring()

        }

    }

    $rs = "r:" + $rObjName

    $ds = "d:" + $dObjName

 

    if(!$equal -and $MaxDepth -lt $_Depth){

        if($ReferenceObject.tostring() -eq $DifferenceObject.ToString()){

            $equal = "=="

        }

        else{

            $equal = "<>"

        }

    }

   

    if($equal){

        if($equal -ne '=='){

            [pscustomobject] @{   

                Property = "<value>"

                Relation = $equal   

                $rs = $ReferenceObject

                $ds = $DifferenceObject

            }   

        }

    }

    else{

        if($ReferenceObject -is [hashtable] -or $ReferenceObject -is [System.Collections.Specialized.OrderedDictionary]){

            $ReferenceObject = [pscustomobject] $ReferenceObject

            $DifferenceObject = [pscustomobject] $DifferenceObject

        }

 

        if($NameProperty){

            if($NameProperty -is [string]){

                $rObjName = $ReferenceObject.$NameProperty

                $dObjName = $DifferenceObject.$NameProperty

            }

            else{

                $rObjName = $ReferenceObject | &{process{ & $NameProperty}}

                $dObjName = $DifferenceObject | &{process{ & $NameProperty}}

            }

        }

        else{

            $rObjName = $ReferenceObject.tostring()

            $dObjName = $DifferenceObject.tostring()

        }

        $rs = "r:" + $rObjName

        $ds = "d:" + $dObjName

 

        $rp = $referenceobject.psobject.Properties |   

                &{process{ if($_.membertype -ne 'AliasProperty'){$_}}} |   

                    Select-Object -ExpandProperty Name

 

        $allprops = @($rp)  

 

        $dp = $differenceobject.psobject.Properties |

                &{process {if($_.membertype -ne 'AliasProperty'){$_}}} |

                    Select-Object -ExpandProperty Name

       

        foreach($p in $dp){   

            if($allprops -notcontains $p){

                $allprops += $p

            }

        }

 

        $allprops = $allprops | &{process {

                $pp = $_

                if(($Property | &{process {if($pp -like $_){$_}}}) -and !($Exclude | &{process{if($pp -like $_){$_}}})) {$_}

            }} | Sort-Object

 

        foreach($p in $allprops){       

            if($rp -contains $p -and $dp -contains $p){

                $ra = $ReferenceObject.$p

                $da = $DifferenceObject.$p

 

                $diff = Compare-Property -ReferenceObject $ra -DifferenceObject $da -Property $Property -Exclude $Exclude -_Depth ($_Depth + 1)

                if($diff){

                    $equal = "<>"

                }

                else{

                    $equal = "=="

                }

            }

            elseif($rp -contains $p){

                $equal = "<="

                $ra = $ReferenceObject.$p

                $da = $null

            }

            else{

                $equal = "=>"

                $da = $DifferenceObject.$p

                $ra = $null

            }

 

            $raempty = $null -eq $ra -or

                        '' -eq $ra -or

                        (($ra -is [collections.ilist] -or $ra -is [Collections.IDictionary]) -and $ra.count -eq 0) -or

                        $ra -is [System.DBNull]

 

            $daempty = $null -eq $da -or   

                        '' -eq $da -or   

                        (($da -is [collections.ilist] -or $da -is [Collections.IDictionary]) -and $da.count -eq 0) -or

                        $ra -is [System.DBNull]

 

            if((!$Excludedifferent -and $equal -ne '==') -or ($includeequal -and $equal -eq '==')){   

                $dummy = 0

                if(($Hide -eq 'BothEmpty' -and $raempty -and $daempty) -or

                    ($Hide -eq 'Empty' -and ($raempty -or $daempty)) -or

                    ($Hide -eq 'NonEmpty' -and (!$raempty -or !$daempty))){

                    continue

                }

                

                [pscustomobject] @{   

                    Property = $p   

                    Relation = $equal   

                    $rs = $ra

                    $ds = $da

                }   

            }

        }

    }

}

 

Ebben a verzióban a következő változtatások történtek:

Az összehasonítás 2 hashtábla esetén is működik úgy, mintha a kulcsok tulajdonságok lennének.

Ha két összehasonlítandó tulajdonság szintén objektum, akkor az összehasonlítás rekurzívan történik erre a két tulajdonságra maximum -MaxDepth szintig. Ehhez bekerült egy rejtett paraméter $_Depth a rekurzió mélységének nyilvántartására.

Scriptblock típusú objektumok összehasonlításánál egyszerűen a sztring reprezenációjukat hasonlítom össze.

Fájlrendszer objektumot tartalmazó tulajdonságok összehasonlításánál a FullName tulajdonságok kerülnek összehasonlításra.

Dátum-időt tartalmazó tulajdonságok összehasonlításánál ezek közvetlenül lesznek összehasonlítva, nem rekurzívan.

A Where-Object cmdleteket lecseréltem a &{process{if(<cond>){$_}}} szerkezetekre teljesítmény okokból.

 

Íme egy példa a rekurzióra:

$o1 = [pscustomobject]@{

    hashkülönböző = @{

        keyegy = @{

            key1 = 1

            Key2 = 2

        }

    }

}

 

$o2 = [pscustomobject]@{

    hashkülönböző = @{

        keyegy = @{

            key1 = 1

            Key2 = 3

        }

    }

}

A fenti két objektum összehasonlítása:

PS C:\> Compare-Property -ReferenceObject $o1 -DifferenceObject $o2

 

Property      Relation r:       d:

--------      -------- --       --

hashkülönböző <>       {keyegy} {keyegy}

Látható, hogy annak ellenére, hogy minkét objektumnak a hashkülönböző tulajdonságában ugyanolyan kulcsokkal rendelkező hastábla tulajdonságuk van, de mivel a belső keyegy hastábla értékei különbözőek, mégsem tekinthetők egyformának.



Word To HTML Converter