PowerShell自定义对象混淆

4

我正在编写一个脚本,尝试输出两个不同的自定义对象; 一个接着一个,但是遇到了问题。为了简化,我将所有代码都剥离到最少:

$beep = new-object -TypeName PSObject
$beep | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "beep1"
$beep | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "beep1"
$beep

$boop = new-object -TypeName PSObject
$boop | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "boop1"
$boop | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "boop1"
$boop

当我运行这个程序时,它似乎将对象合并在一起。当我执行get-member时,它似乎只显示一个对象。为什么会这样呢?
在我要完成的代码中,一个对象是类似上面的自定义对象,但另一个对象是selected.system.int32。当我尝试输出这两个对象时,只有第一个对象被输出。如果我改变顺序,情况依然如此,只输出第一个对象。我做错了什么或者是我没有理解到位?
@JamesQ - 我猜我感到困惑的是当我执行以下操作时:
$beep = new-object -TypeName PSObject
$beep | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "beep1"
$beep | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "beep1"
$beep | get-member

$boop = new-object -TypeName PSObject
$boop | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "boop1"
$boop | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "boop1"
$boop | 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()
Entry1      NoteProperty System.String Entry1=beep1
Entry2      NoteProperty System.String Entry2=beep1
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
Entry1      NoteProperty System.String Entry1=boop1
Entry2      NoteProperty System.String Entry2=boop1

我试图将问题简化,但我觉得我把它弄得太模糊了...

我正在尝试重复使用一些代码:

function Get-NetworkConfig($computerName) {
  Get-WmiObject Win32_NetworkAdapter -Filter 'NetConnectionStatus=2' |
    ForEach-Object {
      $result = 1 | Select-Object Name, IP, MAC
      $result.Name = $_.Name
      $result.MAC = $_.MacAddress
      $config = $_.GetRelated('Win32_NetworkAdapterConfiguration') 
      $result.IP = $config | Select-Object -expand IPAddress
      $result
    }
}

然后在同一脚本中,有类似这样的内容:

function Get-ComputerInfo($computerName) {
    $operatingSystem = Get-WMIObject -computername $computerName win32_operatingsystem
    $computerInfo = new-object -TypeName PSObject
    $computerInfo | Add-Member -MemberType NoteProperty -Name "Computer Name" -Value ("$computerName")
    $computerInfo | Add-Member -MemberType NoteProperty -Name "Operating System" -Value ("$operatingSystem.Caption")
    $computerInfo
}

$computerNames = $args
foreach ($computerName in $computerNames) {
    Get-ComputerInfo($computerName)
    Get-NetworkConfig($computerName)
}

只有get-computerinfo的输出被显示了,然后是一堆空白行,而get-networkconfig本应该输出信息。

如果我交换命令的顺序,那么第一个函数得到输出,但第二个函数只会输出空白行。

为什么我不能像这样依次调用两个函数呢?


1
很大程度上取决于您尝试如何显示对象。我运行了上面的代码,并像预期的那样获得了两个不同的对象。 Get-Member 一次只处理一个对象,因此我不理解您关于“显示一个对象”的说法。尝试运行此命令的不同排列组合,以确信您拥有多个对象:Write-Output "beep Entry1 = $($Beep.Entry1)" - JamesQMurphy
如果你想要输出两个值,请尝试使用 return $beep, $boop - user847990
如果你从存储在CSV文件中的数据进行import-csv操作,你会得到一个PSCustomObjects数组。离题了,但无论如何都值得学习。你可能想要尝试一下将$beep和$boop制作成一个数组。 - Walter Mitty
2个回答

7
当我做Get-Member时,似乎只显示一个对象。 Get-Member 显示关于输入集合中的不同类型的信息,这意味着报告每种类型的第一次出现,并跳过后续出现。在您的情况下,两个输入对象都是类型为[System.Management.Automation.PSCustomObject]的对象,因此Get-Member将仅报告一个共享类型。
例如,1,2 | Get-Member报告有关System.Int32的信息一次。
一个对象类似于上面的自定义对象,但另一个是Selected.System.Int32。当我尝试输出它们中的一个时,只有第一个输出。
PowerShell 的默认输出格式化程序默认隐式使用 Format-Table 来处理具有最多 4 个属性的自定义对象。 如果您输出多个拥有不同类型的对象,并且第一个对象默认为隐式的 Format-Table 输出,则该第一个对象的类型独自决定在生成的表中要显示哪些属性(列) 注意:如果第一个对象的类型恰好与之相关联的格式数据(由Get-FormatData报告)不同,后续对象可以通过隐式的 Format-List 格式进行打印。 如果后续对象没有任何与第一个对象相同的属性,则它们只会打印一个空行; 如果它们具有一些相同的属性,则仅打印这些属性; 忽略任何额外的属性。 然而,重要的是要注意这只是一个显示问题:所有输出的对象仍然存在; 如果您将输出发送到另一个命令以进行进一步处理而不是直接发送到控制台,则它们都将出现。
这里有一个简单的例子:
PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 }
    
one two
--- ---
  1   2
 

请注意,第二个自定义对象由于既没有属性.one也没有属性.two,因此结果只是一行空白。
您可以通过对每个对象使用显式格式化命令来解决该问题以输出:每个对象都应用的显式格式化命令
PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 } |
      ForEach-Object { Format-Table -InputObject $_ }

one two
--- ---
  1   2



three
-----
    3

与单独输出命令相同的方法:
[pscustomobject] @{ one = 1; two = 2 } | Format-Table
[pscustomobject] @{ three = 3 } | Format-Table

Mark Wragg的博客文章所解释的那样,一个脚本产生的所有输出,即使是在不同命令之间,也会被发送到同一管道中。
(您可以将交互式提交的命令行视为隐式脚本。)
要更详细地讨论如何处理单个管道中混合类型的显示格式,请参见此答案
为什么使用显式格式化命令有帮助: 通过显式地将数据流传输到Format-* cmdlet(例如:[pscustomobject] @{ one = 1; two = 2 } | Format-Table),您实际上正在向管道发送格式化对象(各种[Microsoft.PowerShell.Commands.Internal.Format.*]类型),然后PowerShell有效地将它们传递以供显示。
另一种方法是使用通用解决方法:如果您改用管道到Out-Host(例如:[pscustomobject] @{ one = 1; two = 2 } | Out-Host),则:
  • 您将绕过管道并直接打印到控制台(如果您在常规控制台窗口中运行PowerShell),
  • 并应用对象的默认格式化视图。
重要的是要注意,这些解决方法仅适用于显示目的,因为原始对象在此过程中被丢失
  • 当您显式地将数据流传输到Format-* cmdlet时,您将原始对象替换为包含格式化指令的对象,这对进一步处理没有用处。

  • 当您将管道传输到Out-Host时,您实际上没有向脚本的管道发送任何内容。


0

试试这个:

$beep = new-object -TypeName PSObject
$beep | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "beep1"
$beep | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "beep1"
$beep | format-table

$boop = new-object -TypeName PSObject
$boop | Add-Member -MemberType NoteProperty -Name "Entry1" -Value "boop1"
$boop | Add-Member -MemberType NoteProperty -Name "Entry2" -Value "boop1"
$boop | format-table

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接