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

耶希

背景:

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

问题:

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

注意:

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

笔记2:

我确实在尝试发布可重现的代码时注意到,我只得到一种对象类型的回报,而不是从那里得到的两种invoke-restmethod,这使我的问题变得更大,这是怎么回事,为什么有些对象类型被返回而有些却没有。

例:

获取成员结果示例

$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是a的结果,该结果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>

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

编辑#1:

由于评论者的编辑,它们是正确的,因此我添加了可复制的示例并阐明了我的要求。我尚未深入剖析给出的答案。

mklement0

Get-Member通过设计列出了其输入对象中的不同类型。[1]

但是,实例的问题[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

以下内容意外地仅产生一个输出对象,仅显示第一个 [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][pscustomobject]例如,在Select-Objectcmdlet创建的实例中会发生这种情况(请参阅底部)。


解决方法

注意:以下操作适用于显示输出(应该很好,因为该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调用产生单独的显示输出Out-Host没有它,显示输出将错误地建议一个包含所有不同类型的属性单一输入类型。

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

# 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-Objectcmdlet创建的尽管从技术上讲,这样的对象也是一个[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

但是请注意,就像所有[pscustomobject]具有类型名称的实例System.Management.Automation.PSCustomObject一样,即使它们具有不同的属性也是如此,所有具有的实例也是如此Selected.System.Management.Automation.PSCustomObject也就是说,由于共享相同的固定类型名称Select-Object创建的[pscustomobject]实例也都被视为相同。


[1]例如,1, 2, 3 | Get-Member仅列出一种类型System.Int32,因为所有输入对象都具有该类型。相比之下,1, 'foo', 2 | Get-Member列出2种,System.Int32System.String(而不是System.Int32 再次)。

[2]分配任意类型名称的功能是PowerShell的ETS(扩展类型系统)的一部分-请参见about_types.ps1xml

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章