Как рекурсивно перебирать свойства объекта?

Я начал переписывать свой ежедневный отчет VMware, чтобы использовать Get-View, а не соответствующие команды PowerCLI, где это возможно, из соображений производительности. Одно небольшое неудобство заключается в том, что возвращаемые объекты представления часто имеют много свойств, многие из которых сами являются объектами. Некоторые свойства вложены в четыре или более уровней.

Итак, я пытаюсь создать функцию, которая будет выводить все свойства объекта вместе с полным путем к этому свойству. Затем его можно передать по конвейеру в Where-Object, чтобы упростить поиск определенных свойств. Итак, чтобы найти свойство, относящееся к Host в объекте VMware.Vim.VirtualMachine, хранящемся в $ v, я бы набрал что-то вроде:

Get-Properties -Object $v | ? {$_ -match "Host"}

И в идеале это должно вернуть список всех вложенных свойств $ v, которые содержат слово «Host».

Как я могу это сделать?


person KevinD    schedule 20.02.2013    source источник


Ответы (1)


Возможно, есть более простой способ сделать это, но вот что я придумал:

function Get-Properties($Object, $MaxLevels="5", $PathName = "`$_", $Level=0)
{
    <#
        .SYNOPSIS
        Returns a list of all properties of the input object

        .DESCRIPTION
        Recursively 

        .PARAMETER Object
        Mandatory - The object to list properties of

        .PARAMETER MaxLevels
        Specifies how many levels deep to list

        .PARAMETER PathName
        Specifies the path name to use as the root. If not specified, all properties will start with "."

        .PARAMETER Level
        Specifies which level the function is currently processing. Should not be used manually.

        .EXAMPLE
        $v = Get-View -ViewType VirtualMachine -Filter @{"Name" = "MyVM"}
        Get-Properties $v | ? {$_ -match "Host"}

        .NOTES
            FunctionName : 
            Created by   : KevinD
            Date Coded   : 02/19/2013 12:54:52
        .LINK
            http://stackoverflow.com/users/1298933/kevind
     #>

    if ($Level -eq 0) 
    { 
        $oldErrorPreference = $ErrorActionPreference
        $ErrorActionPreference = "SilentlyContinue"
    }

    #Initialize an array to store properties
    $props = @()

    # Get all properties of this level
    $rootProps = $Object | Get-Member -ErrorAction SilentlyContinue | Where-Object { $_.MemberType -match "Property"} 

    # Add all properties from this level to the array.
    $rootProps | ForEach-Object { $props += "$PathName.$($_.Name)" }

    # Make sure we're not exceeding the MaxLevels
    if ($Level -lt $MaxLevels)
    {

        # We don't care about the sub-properties of the following types:
        $typesToExclude = "System.Boolean", "System.String", "System.Int32", "System.Char"

        #Loop through the root properties
        $props += $rootProps | ForEach-Object {

                    #Base name of property
                    $propName = $_.Name;

                    #Object to process
                    $obj = $($Object.$propName)

                    # Get the type, and only recurse into it if it is not one of our excluded types
                    $type = ($obj.GetType()).ToString()

                    # Only recurse if it's not of a type in our list
                    if (!($typesToExclude.Contains($type) ) )
                    {

                        #Path to property
                        $childPathName = "$PathName.$propName"

                        # Make sure it's not null, then recurse, incrementing $Level                        
                        if ($obj -ne $null) 
                        {
                            Get-Properties -Object $obj -PathName $childPathName -Level ($Level + 1) -MaxLevels $MaxLevels }
                        }
                    }
    }

    if ($Level -eq 0) {$ErrorActionPreference = $oldErrorPreference}
    $props
}

При запуске с помощью команды

Get-Properties -Object $v | ? {$_ -match "Host" }

он возвращается

$_.Capability.HostBasedReplicationSupported
$_.Client.CertificateError.Method.DeclaringType.Assembly.HostContext
$_.Client.CertificateError.Method.Module.Assembly.HostContext
$_.Client.CertificateError.Method.ReflectedType.Assembly.HostContext
$_.Client.CertificateError.Method.ReturnType.Assembly.HostContext
$_.Client.ServiceContent.HostProfileManager
$_.Client.ServiceContent.HostProfileManager
$_.Client.ServiceContent.HostProfileManager.Type
$_.Client.ServiceContent.HostProfileManager.Value
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Hardware.Device.Backing.HostPointingDevice
$_.Config.Tools.SyncTimeWithHost
$_.Guest.HostName
$_.Guest.IpStack.DnsConfig.HostName
$_.Guest.Net.DnsConfig.HostName
$_.Runtime.Host
$_.Runtime.Host
$_.Runtime.Host.Type
$_.Runtime.Host.Value
$_.Summary.Guest.HostName
$_.Summary.QuickStats.HostMemoryUsage
$_.Summary.Runtime.Host
$_.Summary.Runtime.Host
$_.Summary.Runtime.Host.Type
$_.Summary.Runtime.Host.Value

Учитывая, что объект VMware.Vim.VirtualMachine имеет 5087 вложенных свойств, это гораздо более простой способ найти то, что вы ищете. Надеюсь, это поможет кому-то другому.

person KevinD    schedule 20.02.2013