在 PowerShell 中迭代 PSObject 属性

我有这样的 PSObject(来自 XML) :

bool : {IsActive, ShowOnB2C, ShowOnB2B, IsWebNews}
str  : {id, ProductId, GroupName, Unit...}
int  : {ProductIdNumeric, Prices_SalesOne, Prices_Treater, Prices_B2C...}
arr  : {EnvironmentBrands, Catalogs, NavisionLevels}
long : long

我希望在不使用属性名(例如 bool)的情况下迭代这些属性。

我试着像这样索引对象:

$document[0]

但是这没有给我任何东西,但是它也不会引起任何错误。

Select-Object的工作,但然后我必须使用属性名称,我不想这样。

$documents | Select-Object bool,str

ForEach不迭代属性。

$documents | ForEach {
$_.name
}

返回 doc,这是包含 bool、 int 和字符串的标记(XML)的名称。

98256 次浏览

使用隐藏属性 PSObject可以做到这一点:

$documents.PSObject.Properties | ForEach-Object {
$_.Name
$_.Value
}

这对于某些包含“ NoteProperties”(属性类型为 NoteProperty)的 PowerShell 创建的对象(PSObjects)不起作用。

有关涵盖所有属性类型 的方法,请参见此答案。

Stej 提到过一样,有一个带有 -MemberType参数的 Get-Member cmdlet,您可以使用:

$documents | Get-Member -MemberType Property | ForEach-Object {
$_.Name
}

我更喜欢使用 foreach来遍历 PowerShell 对象:

foreach($object_properties in $obj.PsObject.Properties)
{
# Access the name of the property
$object_properties.Name


# Access the value of the property
$object_properties.Value
}

一般来说,foreach的性能高于 Foreach-Object

是的,实际上 foreachForeach-Object在引擎盖下是不同的。

Get-Member 可能也需要 NoteProperty。

$documents | Get-Member -membertype property,noteproperty |
Foreach name

编辑: 类型“属性”似乎是一个更通用的概括

$documents | get-member -type properties | % name

编辑: 删除所有值:

$obj = ls test.ps1
$obj | Get-Member -Type properties | foreach name |
foreach { $_ + ' = ' + $obj.$_ }


Attributes = Normal
CreationTime = 06/01/2019 11:29:03
CreationTimeUtc = 06/01/2019 15:29:03
Directory = /Users/js
DirectoryName = /Users/js
Exists = True
Extension = .ps1
FullName = /Users/js/test.ps1
IsReadOnly = False
LastAccessTime = 06/05/2019 23:19:01
LastAccessTimeUtc = 06/06/2019 03:19:01
LastWriteTime = 06/01/2019 11:29:03
LastWriteTimeUtc = 06/01/2019 15:29:03
Length = 55
Name = test.ps1

没有“ | foreach name”的替代方法,需要额外的括号:

$obj | Get-Member -Type properties |
foreach { $_.name + ' = ' + $obj.($_.name) }

另一种方法是创建一个更容易使用的数组,并且可能对从 json 转换的对象有好处:

$a = '{ prop1:1, prop2:2, prop3:3 }' | convertfrom-json
$a


prop1 prop2 prop3
----- ----- -----
1     2     3


$a.PSObject.Properties | select name,value


name  value
----  -----
prop1     1
prop2     2
prop3     3

我使用以下命令枚举属性并将它们放在表中:

$Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap

我围绕这个问题编写了以下函数,它也会遍历嵌套属性。

function Enumerate-ObjectProperties {
param (
[psobject] $Object,
[string] $Root
)


Write-Output $($Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap | Out-String)


foreach ($Property in $Object.PSObject.Properties) {
# Strings always have a single property "Length". Do not enumerate this.
if (($Property.TypeNameOfValue -ne 'System.String') -and ($($Object.$($Property.Name).PSObject.Properties))) {
$NewRoot = $($($Root + '.' + $($Property.Name)).Trim('.'))
Write-Output "Property: $($NewRoot)"
Enumerate-ObjectProperties -Object $($Object.$($Property.Name)) -Root $NewRoot
}
}
}


Enumerate-ObjectProperties $YourObject

然而,请记住,一些对象的构造有些典型,在这个意义上,他们有“循环”在他们的嵌套。引用父对象的子属性。 例如:

Get-Date 'somebogusdata'
Enumerate-ObjectProperties $Error[0]

这将创建一个循环。 当然,您可以添加一个“ deep”参数来添加一个深度计数器,指定您只想到达某个深度。 看起来像这样:

$script:Level = 1
function Enumerate-ObjectProperties {
    param (
        [psobject] $Object,
        [int32] $Depth = 1,
[string] $Root
    )


    Write-Output $($Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap | Out-String)


    foreach ($Property in $Object.PSObject.Properties) {
        # Strings always have a single property "Length". Do not enumerate this.
        if (($Property.TypeNameOfValue -ne 'System.String') -and ($($Object.$($Property.Name).PSObject.Properties)) -and ($Level -le $Depth)) {
            $NewRoot = $($($Root + '.' + $($Property.Name)).Trim('.'))
            $Level++
Write-Output "Property: $($NewRoot) (Level: $Level)"
            Enumerate-ObjectProperties -Object $($Object.$($Property.Name)) -Root $NewRoot
$Level--
        }
    }
}


Enumerate-ObjectProperties -Object $Error[0] -Depth 2