PowerShell自定义对象隐藏属性类型

ffvjumwh  于 2022-11-10  发布在  Shell
关注(0)|答案(1)|浏览(131)

背景:

我有一个PSCustomObject,它是通过... | convertfrom-json转换JSON数组而创建的。该对象有许多其他属性值对象(基本上它是许多PSCustomObject的集合)。根据对对象的了解,我知道它至少包含三种不同类型的对象(类型意味着具有不同属性的PSCustomObject)。

问题:

当运行Get-Members I时,只有两个对象类型及其成员,第三个对象类型根本没有列出。我知道还有第三种对象类型,因为我可以选择仅在该对象中可用的属性。

注意:

我曾经遇到过一个类似的问题,一些成员只有在$object | select...方法中首先被调用时才会出现在get-member的结果中,否则他们就不会出现。我当时也没弄明白。当前的问题不是相同的,但可能是相关的,因为我尝试了$object | select...的方法,但没有帮助。

注2:

我确实注意到,当尝试发布可重复的代码时,我只得到一个对象类型的回报,而不是从invoke-restmethod获得的两个对象类型,这让我的问题变得更加严重,这里发生了什么,为什么一些对象类型被返回,而另一些对象类型没有返回。

示例:

Get-Members结果示例

$res.address_objects.ipv4 | gm       

   TypeName: Selected.System.Management.Automation.PSCustomObject
Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
host        NoteProperty System.Management.Automation.PSCustomObject <snip>
name        NoteProperty string name=<snip>
uuid        NoteProperty string uuid=<snip>
zone        NoteProperty string zone=<snip>

   TypeName: System.Management.Automation.PSCustomObject
Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
name        NoteProperty string name=<snip>
network     NoteProperty System.Management.Automation.PSCustomObject <snip>
uuid        NoteProperty string uuid=<snip>

如您所见,这里有两种对象类型,它们都有一些不同的属性名称。

示例:

示例Json,我将其转换为对象。

摘自@Jawad的回答。
请注意:此示例不是我的代码的完全副本,因为我的psobject是invoke-restmethod自动将json转换为对象的结果。

$json = @"
{
  "address_objects": {
    "ipv4": [{
        "host": "hostValue",
        "name": "hostName",
        "uuid": "value",
        "zone": "thisZone"
     },
     {
        "name": "NewName",
        "network": "newNetwork",
        "uuid": "thisUuid"
     },
     {
        "name": "NewName",
        "range": "newrange",
        "uuid": "thisUuid"
     }]
  }
}
"@ | ConvertFrom-Json

运行Get-member时预期输出:

$json.address_objects.ipv4 | gm       

   TypeName: Selected.System.Management.Automation.PSCustomObject
Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
host        NoteProperty System.Management.Automation.PSCustomObject <snip>
name        NoteProperty string name=<snip>
uuid        NoteProperty string uuid=<snip>
zone        NoteProperty string zone=<snip>

   TypeName: System.Management.Automation.PSCustomObject
Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
name        NoteProperty string name=<snip>
network     NoteProperty System.Management.Automation.PSCustomObject <snip>
uuid        NoteProperty string uuid=<snip>

   TypeName: System.Management.Automation.PSCustomObject
Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
name        NoteProperty string name=<snip>
range     NoteProperty System.Management.Automation.PSCustomObject <snip>
uuid        NoteProperty string uuid=<snip>

基本上,有三个截然不同的psCustomObject,因此get-member应该会将它们全部列出。

编辑#1:

感谢评论者的编辑,他们是正确的,所以我添加了一个可重现的样本,并澄清了我所询问的问题。我还没有深入剖析给出的答案。

efzxgjgh

efzxgjgh1#

Get-Member在设计上列出了其输入对象中的不同类型。
然而,**[pscustomobject]示例的问题是Get-Member无法将它们识别为不同的类型即使它们具有不同的属性


# Send 3 [pscustomobject] instances with distinct properties to Get-Member

[pscustomobject] @{ one = 1; two = 2; three = 3 },
[pscustomobject] @{ four = 4; five = 5 },
[pscustomobject] @{ six = 6; seven = 7 } | Get-Member

下面的代码意外地只生成一个Single输出对象,仅显示First[pscustomobject]示例的成员:

TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
one         NoteProperty int one=1
three       NoteProperty int three=3
two         NoteProperty int two=2

Get-Member仅通过类型的(完整)类型名称区分类型,如隐藏示例属性.pstypenames的第一个元素(.pstypenames[0]**)所示,不考虑给定示例的特定属性。

默认情况下,[pscustomobject]示例的类型名称为System.Management.Automation.PSCustomObject
请注意,默认情况下,.pstypenames[0]包含与.GetType().FullName相同的类型名称,但是可以插入“虚构的”名称[2],这就是由Select-Object cmdlet创建的[pscustomobject]示例所发生的情况(请参见底部部分)。

解决方法

注意:以下代码适用于Display输出(考虑到Get-Member输出通常用于视觉检查,因此应该可以)。

[pscustomobject] @{ one = 1; two = 2; three = 3 },
[pscustomobject] @{ four = 4; five = 5 },
[pscustomobject] @{ six = 6; seven = 7 } |
  Group-Object { "$($_.psobject.Properties.Name)" } | ForEach-Object {
    Get-Member -InputObject $_.Group[0] | Out-Host
  }
  • Group-Object用于使用已计算的属性(通过为每个输入对象求值的脚本块({ ... })),根据属性名称列表对输入对象进行分组。
  • $_.psobject.Properties.Name生成所有属性名称的数组,"$(...)"将其转换为空格分隔的列表。
  • 然后通过ForEach-Object处理每个组,将每个组的第一个示例($_.Group[0])直接传递给Get-Member
  • 为了确保单个Get-Member调用产生单独的Display输出,使用Out-Host;如果没有它,Display输出将错误地建议包含所有不同类型的属性的单个输入类型。

如果您只对所有输入对象的不同*属性名称列表感兴趣**:


# This yields the sorted array of all unique property names, across all

# input objects:

# 'five', 'four', 'one', 'seven', 'six', 'three', 'two'

[pscustomobject] @{ one = 1; two = 2; three = 3 },
[pscustomobject] @{ four = 4; five = 5 },
[pscustomobject] @{ six = 6; seven = 7 } |
  ForEach-Object { $_.psobject.Properties.Name } | Sort-Object -Unique

至于你的症状
请注意,您的第一个Get-Member输出块提到了一个不同类型名称:Selected.System.Management.Automation.PSCustomObject

Selected.前缀表示对象是通过Select-Object cmdlet创建的。虽然这样的对象在技术上也是[pscustomobject]示例,但修改后的类型名称会导致Get-Member将其视为不同的类型。

下面是一个简化的例子:

$obj = [pscustomobject] @{ one = 1; two = 2 }
$obj, ($obj | Select-Object -Property *) | Get-Member

这会产生以下结果;请注意,属性是如何相同的,而只有类型名称不同:

TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
one         NoteProperty int one=1
two         NoteProperty int two=2

   TypeName: Selected.System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
one         NoteProperty int one=1
two         NoteProperty int two=2

但是,请注意,就像所有类型名为System.Management.Automation.PSCustomObject[pscustomobject]示例一样,即使具有不同的属性,所有类型名为Selected.System.Management.Automation.PSCustomObject的示例也是如此。也就是说,由于共享相同的固定类型名称,Select-Object创建的[pscustomobject]示例也将被同等对待。
[1]例如,1, 2, 3 | Get-Member只列出一个类型,System.Int32,因为所有输入对象都具有该类型;相比之下,1, 'foo', 2 | Get-Member列出两个类型,System.Int32System.String(但不是System.Int32Again)。
[2]分配任意类型名称的功能是PowerShell ETS(扩展类型系统)的一部分-请参阅about_types.ps1xml

相关问题