Tulajdonságok kifejtése (Expand-Property)

Az előző fejezetben tárgyalt Get-Property-hez hasonló a következő Expand-Property függvény. Itt nem egy konkrét elérési útra vagyok kíváncsi, hanem ki akarom fejteni egy objektum összes tulajdonságát vagy hashtábla összes kulcsát.

Itt a függvény definíciója:

function Expand-Property {

<#

.Synopsis

   Expands all the properties or keys of the input object.

.DESCRIPTION

   Recursively dumps all properties or keys of the input object. By default it goes 1 level deep, but with the -MaxDepth parameter you can allow deep search.

   If the -Condensed switch is used, only the leaf properties are returned (properties that don't have any further properties or which are at the -MaxDepth).

.EXAMPLE

   Expand-Property -Object $PSVersionTable -MaxDepth 2 -SkipTypesAdditional system.version

 

   Expands the properties of the $PSVersionTable object down to 2 level deep, but any [system.version] type of property won't be expanded further.

.EXAMPLE

   Expand-Property -Object $PSVersionTable -MaxDepth 2 -SkipTypesAdditional system.version -Condensed

 

   Expands only the last properties in the hiararchy of properties in the $PSVersionTable object down to 2 level deep, but any [system.version] type of property won't be expanded further.

.INPUTS

   hashtables or psobjects

.OUTPUTS

   Collection of custom objects having a PropertyPath, Type, and Value properties.

#>

[cmdletbinding(PositionalBinding=$false)]

param(

    # Input object or hashtable

    $Object,

    # Maximum depth of recursion, default is 1

    [int] $MaxDepth = 1,

    [Parameter(Dontshow = $true)]$Path,

    [Parameter(Dontshow = $true)]$_currentDepth = 1,

    # Only leaf properties / keys are returned

    [switch] $Condensed,

    # .NET types that are not expanded in properties / keys

    [string[]] $SkipTypesDefault = ('System.Int*', 'System.UInt*', 'System.Double', 'System.Decimal', 'System.String', 'System.DateTime', 'System.TimeSpan', 'System.RuntimeType'),

    [string[]] $SkipTypesAdditional

)

 

if(!$Path){

    $parts = [scriptblock]::Create($MyInvocation.Line).ast.findall({$true},$true)

 

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

        if($parts[$i].ParameterName -eq 'Object'){

            $Path = $parts[$i + 1].Extent.Text

 

            if($path -notmatch '^(\$|\()'){

                $Path = "($Path)"

            }

            break

        }

    }

 

    if(!$Path){

        $Path = '$Object'

    }

}

 

   

if($null -eq $Object -or $Object -is [System.DBNull]){

    return

}

elseif($_currentDepth -gt $MaxDepth -or ($PSBoundParameters.ContainsKey('_currentDepth') -and ($SkipTypesDefault + $SkipTypesAdditional | &{process{if($Object.GetType().fullname -like $_){$_}}}))){

    [pscustomobject] @{

            PropertyPath = $Path

            Type = $(if($null -ne $Object){$Object.GetType().fullname})

            Value = $Object

        }

    return

}

 

if(!$Condensed){

    [pscustomobject]@{

        PropertyPath = $Path

        Type = $(if($null -ne $Object){$Object.GetType().fullname})

        Value = $Object

    }

}

 

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

    $keys = $Object.Keys

}

else{

    $keys = $Object.psobject.properties.name

}

   

foreach($key in $keys){

    $displayKey = $key

    if($key -match '\W'){

        $displayKey = "'$key'"

    }

 

    if($Object.$key -is [System.Collections.IList]){

        if(!$Condensed){

            [pscustomobject]@{

                PropertyPath = "$Path.$displayKey"

                Type = $(if($null -ne $Object.$key){$Object.$key.GetType().fullname})

                Value = $Object.$key

            }

        }

 

        if($_currentDepth -lt $MaxDepth){

            for($i = 0; $i -lt $Object.$key.count; $i++){

                Expand-Property -Object $Object.$key[$i] -Path ($Path + "." + $displayKey + "[$i]") -MaxDepth $MaxDepth -Condensed:$Condensed -_currentDepth ($_currentDepth + 2) -SkipTypesDefault $SkipTypesDefault -SkipTypesAdditional $SkipTypesAdditional

            }

        }

    }

    elseif($null -eq $Object.$key -or $Object.$key -is [System.DBNull]){

        [pscustomobject]@{

            PropertyPath = "$Path.$displayKey"

            Type = $(if($null -ne $Object.$key){$Object.$key.GetType().fullname})

            Value = $Object.$key

        }

    }

    else{

        Expand-Property -Object $Object.$key -Path ($Path + "." + $displayKey) -MaxDepth $MaxDepth -Condensed:$Condensed -_currentDepth ($_currentDepth + 1) -SkipTypesDefault $SkipTypesDefault -SkipTypesAdditional $SkipTypesAdditional

    }

}

}

Nézzünk pár példát a felhasználására! Elsőként vegyük elő újra azt a $Ticket hashtáblát, amit már korábban használtunk:

$ticket = @{

    Number = "REQ1234"

    Approver = @{

        Name = "Tibor Soós"

        EmployeeId = 99123

        Manager = @{

            Name = "Ferenc Főnök"

            EmployeeID = 87871

        }

    }

    items = @(

        @{

            Number = "RITM332211"

            Description = "Valami jó"

            ItemCost = @{

                Price = 1234

                Currency = "HUF"

            }

        }, @{

            Number = "RITM332212"

            Description = "Ingyenes"

            ItemCost = $null

        }

    )

}

Ha nincs meg a forráskódunk, de a $Ticket megvan és megnézzük azt, akkor nem annyira látjuk át, hogy mi is van benne:

PS C:\> $ticket

 

Name                           Value

----                           -----

Number                         REQ1234

items                          {System.Collections.Hashtable, System.Colle...

Approver                       {EmployeeId, Name, Manager}

Itt jön jól az Expand-Property függvényünk:

PS C:\> Expand-Property -Object $ticket

 

PropertyPath     Type                         Value

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

$ticket          System.Collections.Hashtable {Number, items, Approver}

$ticket.Number   System.String                REQ1234

$ticket.items    System.Object[]              {System.Collections.Hashtabl...

$ticket.Approver System.Collections.Hashtable {EmployeeId, Name, Manager}

Az első próbálkozás nem javít túl sokat, de engedjük a tulajdonságok / kulcsok bejárását nagyobb mélységben:

PS C:\> Expand-Property -Object $ticket -MaxDepth 100

 

PropertyPath                        Type                         Value

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

$ticket                             System.Collections.Hashtable {Number, ...

$ticket.Number                      System.String                REQ1234

$ticket.items                       System.Object[]              {System.C...

$ticket.items[0]                    System.Collections.Hashtable {ItemCost...

$ticket.items[0].ItemCost           System.Collections.Hashtable {Price, C...

$ticket.items[0].ItemCost.Price     System.Int32                 1234

$ticket.items[0].ItemCost.Currency  System.String                HUF

$ticket.items[0].Number             System.String                RITM332211

$ticket.items[0].Description        System.String                Valami jó

$ticket.items[1]                    System.Collections.Hashtable {ItemCost...

$ticket.items[1].ItemCost

$ticket.items[1].Number             System.String                RITM332212

$ticket.items[1].Description        System.String                Ingyenes

$ticket.Approver                    System.Collections.Hashtable {Employee...

$ticket.Approver.EmployeeId         System.Int32                 99123

$ticket.Approver.Name               System.String                Tibor Soós

$ticket.Approver.Manager            System.Collections.Hashtable {Name, Em...

$ticket.Approver.Manager.Name       System.String                Ferenc Főnök

$ticket.Approver.Manager.EmployeeID System.Int32                 87871

Látható, hogy a függvény bejárta a teljes hierarchiát és minden szinten kiírja, hogy mi az adott szint elérési útja (PropertyPath oszlop), mi az ottani adat típusa (Type) és értéke (Value). Ráadásul a PropertyPath alatti bármelyik elérési utat ki tudjuk másolni és végrehajtva megkapjuk azt az értéket, amit a Value oszlopban látunk:

PS C:\> $ticket.items[0].Description

Valami jó

A fenti lista némileg redundáns információt tartalmaz, hiszen például nem kellene nekünk feltétlenül a legelső találat ($ticket), vagy a $ticket.items, hiszen az ezek alatti, legvégső tulajdonságok / kulcsok alapján is nagyjából felépíthető lenne az eredeti objektum. Ha ezekre a redundáns infókra nincs szükségünk, akkor kihagyhatjuk őket a -Condensed kapcsoló használatával:

PS C:\> Expand-Property -Object $ticket -MaxDepth 100 -Condensed

 

PropertyPath                        Type          Value

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

$ticket.Number                      System.String REQ1234

$ticket.items[0].ItemCost.Price     System.Int32  1234

$ticket.items[0].ItemCost.Currency  System.String HUF

$ticket.items[0].Number             System.String RITM332211

$ticket.items[0].Description        System.String Valami jó

$ticket.items[1].ItemCost

$ticket.items[1].Number             System.String RITM332212

$ticket.items[1].Description        System.String Ingyenes

$ticket.Approver.EmployeeId         System.Int32  99123

$ticket.Approver.Name               System.String Tibor Soós

$ticket.Approver.Manager.Name       System.String Ferenc Főnök

$ticket.Approver.Manager.EmployeeID System.Int32  87871

Itt már csak a legszükségesebb sorokat kaptuk meg.

Nézzünk még egy példát! Itt a $PSVersionTable automatikus változót vizsgálom:

PS C:\> Expand-Property -Object $PSVersionTable -MaxDepth 100

 

PropertyPath                                            Type

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

$PSVersionTable                                         System.Collections...

$PSVersionTable.PSVersion                               System.Version

$PSVersionTable.PSVersion.Major                         System.Int32

$PSVersionTable.PSVersion.Minor                         System.Int32

$PSVersionTable.PSVersion.Build                         System.Int32

$PSVersionTable.PSVersion.Revision                      System.Int32

$PSVersionTable.PSVersion.MajorRevision                 System.Int16

$PSVersionTable.PSVersion.MinorRevision                 System.Int16

$PSVersionTable.PSEdition                               System.String

$PSVersionTable.PSCompatibleVersions                    System.Version[]

$PSVersionTable.PSCompatibleVersions[0]                 System.Version

$PSVersionTable.PSCompatibleVersions[0].Major           System.Int32

$PSVersionTable.PSCompatibleVersions[0].Minor           System.Int32

$PSVersionTable.PSCompatibleVersions[0].Build           System.Int32

$PSVersionTable.PSCompatibleVersions[0].Revision        System.Int32

$PSVersionTable.PSCompatibleVersions[0].MajorRevision   System.Int16

$PSVersionTable.PSCompatibleVersions[0].MinorRevision   System.Int16

Megvágtam a kimenetet, mert a nagyon sok verziószám típusú tulajdonság, ami itt megtalálható, nagyon hosszúvá teszi ezt a listát, hiszen minden verziószámnak van külön Major, Minor, Build, Revision, stb. tulajdonsága. Ha ezeket nem akarom látni, akkor kikapcsolhatom ezen típus kifejtését a -SkipTypeAdditional paraméter használatával:

PS C:\> Expand-Property -Object $PSVersionTable -MaxDepth 100 -SkipTypesAdditional 'system.version'

 

PropertyPath                              Type                         Value

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

$PSVersionTable                           System.Collections.Hashtable {PS...

$PSVersionTable.PSVersion                 System.Version               5.1...

$PSVersionTable.PSEdition                 System.String                Des...

$PSVersionTable.PSCompatibleVersions      System.Version[]             {1....

$PSVersionTable.PSCompatibleVersions[0]   System.Version               1.0

$PSVersionTable.PSCompatibleVersions[1]   System.Version               2.0

$PSVersionTable.PSCompatibleVersions[2]   System.Version               3.0

$PSVersionTable.PSCompatibleVersions[3]   System.Version               4.0

$PSVersionTable.PSCompatibleVersions[4]   System.Version               5.0

$PSVersionTable.PSCompatibleVersions[5]   System.Version               5.1...

$PSVersionTable.BuildVersion              System.Version               10....

$PSVersionTable.CLRVersion                System.Version               4.0...

$PSVersionTable.WSManStackVersion         System.Version               3.0

$PSVersionTable.PSRemotingProtocolVersion System.Version               2.3

$PSVersionTable.SerializationVersion      System.Version               1.1...

Így már jóval rövidebb lett a lista. A függvénydefinícióban látható, hogy a -SkipTypesDefault alatt már jónéhány olyan típus van, amit nem fejt ki a függvény, ezt lehet bővíteni a -SkipTypeAdditional-lal. Persze a default listát is felül lehet bírálni, de én azt nem javaslom.

Amúgy annak ellenére, hogy például a [system.datetime] típus benne van az alap listában, mégis kifejtésre kerül, ha az nem egy objektum tulajdonságában van, hanem direktben adjuk input objektumként:

PS C:\> Expand-Property -Object (get-date)

 

PropertyPath           Type                                          Value

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

(get-date)             System.DateTime                               2025....

(get-date).DisplayHint Microsoft.PowerShell.Commands.DisplayHintType DateTime

(get-date).DateTime    System.String                                 2025....

(get-date).Date        System.DateTime                               2025....

(get-date).Day         System.Int32                                  29

(get-date).DayOfWeek   System.DayOfWeek                              Tuesday

(get-date).DayOfYear   System.Int32                                  210

(get-date).Hour        System.Int32                                  17

(get-date).Kind        System.DateTimeKind                           Local

(get-date).Millisecond System.Int32                                  45

(get-date).Minute      System.Int32                                  27

(get-date).Month       System.Int32                                  7

(get-date).Second      System.Int32                                  44

(get-date).Ticks       System.Int64                                  63889...

(get-date).TimeOfDay   System.TimeSpan                               17:27...

(get-date).Year        System.Int32                                  2025



Word To HTML Converter