Powershell自定义对象混淆

时间:2017-08-16 02:10:42

标签: powershell

我正在尝试输出两个不同的自定义对象的脚本;一个接一个地出现了问题,为了简化,我将所有代码都删除到了最低限度:

$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输出的一堆空行。

如果我撤销订单;只有第一个函数给出输出,第二个函数只发出空行。

为什么我不能像这样按顺序调用两个函数?

2 个答案:

答案 0 :(得分:1)

  

当我执行Get-Member时,它似乎只显示一个对象。

Get-Member显示有关输入集合中 distinct 类型的信息,这意味着会报告每种类型的第一次出现,并跳过后续出现。

在您的情况下,两个输入对象都是[System.Management.Automation.PSCustomObject]类型,因此Get-Member将只报告一个共享类型。

例如,1, 2 | Get-Member一次报告有关System.Int32 的信息。

  

一个对象是上面的自定义对象,另一个是selected.system.int32。当我尝试一个接一个地输出时,只有第一个输出。

PowerShell的默认输出格式默认为Format-Table隐式使用最多4个属性的自定义对象。

如果输出多个不同类型的对象,并且第一个对象默认为隐式Format-Table输出,则第一个对象的类型单独< / em>确定在结果表中显示的属性(列)。

如果后续对象没有与第一个对象具有相同属性的任何,则只需打印一个空行;如果他们有某些相同的属性,则只打印那些

请务必注意,这只是一个显示问题,但是:输出的所有对象仍然存在;如果你将输出发送到另一个命令进行进一步处理而不是直接发送到控制台,他们都会在那里。

一个简单的例子:

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's blog post所解释的那样,由给定脚本生成的所有输出 - 即使是在单独的命令中 - 也会发送到相同的管道
(您可以将交互式提交的命令行视为隐式脚本。)

有关如何根据显示格式处理单个管道中的各种类型的详细讨论,请参阅this answer

为什么使用显式格式化命令有助于:

通过明确管道到Format-* cmdlet (例如[pscustomobject] @{ one = 1; two = 2 } | Format-Table),您实际上正在发送格式化对象(各种{ {1}}类型)到管道,然后PowerShell有效地通过进行显示。

另一种方法是使用 通用解决方法:如果您管道转到[Microsoft.PowerShell.Commands.Internal.Format.*] (例如Out-Host }),在这种情况下:

  • 绕过管道并直接打印到控制台(如果您在常规控制台窗口中运行PowerShell),
  • 并应用了对象的默认格式视图。

请注意,这些变通办法仅适用于显示目的,因为原始对象在此过程中丢失:< / p>

  • 当您显式地管道到[pscustomobject] @{ one = 1; two = 2 } | Out-Host cmdlet时,将原始对象替换为包含格式说明的对象,这些对象无法进行进一步处理。

  • 当你管道到Format-*时,你将 nothing 发送到脚本的管道。

答案 1 :(得分: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