Powershell 自定义对象混淆 [英] Powershell Custom Object Confusion
问题描述
我正在编写一个脚本,试图输出两个不同的自定义对象;一个接一个地出现问题,所以为了简化,我把所有的代码都精简到最少:
I was working on a script trying to output two different custom objects; one after another and was having problems, so to simplify, I stripped all the code down to just the minimum:
$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 时,它似乎只显示一个对象.为什么?
When I run this, it appears the objects are combined together. When I do a get-member, it seems to just show one object. Why?
在我实际尝试完成的代码中,一个对象是上面的自定义对象,但另一个是 selected.system.int32.当我尝试一个接一个地输出时,只有第一个输出.如果我翻转订单;同样的事情,第一个对象得到输出.我做错了什么/不明白?
In the code I am actually trying to finish, one object is a custom object like above, but the other it a selected.system.int32. When I try to output one after the other only the first one outputs. If I flip the order; same thing, the first object gets output. What am I doing wrong / don't understand?
@JamesQ - 我想让我困惑的是当我这样做时:
@JamesQ - I guess what is confusing me is when I do:
$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
我试图让问题保持简单,但我认为我把它说得太含糊了,所以......
I was trying to keep the question simple, but I think I've made it too ambiguous so...
我正在尝试重用一些代码:
I am trying to reuse some code:
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
}
}
然后在同一个脚本中类似:
then in the same script something like:
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 将有输出.
Only the output from get-computerinfo is displayed, then a bunch of blank lines where get-networkconfig would have output.
如果我颠倒顺序;只有第一个函数给出输出,第二个函数只输出空行.
If I reverse the order; only the first function gives output, the second only spits blank lines.
为什么我不能像这样按顺序调用两个函数?
Why can't I just call two functions in sequence like this?
推荐答案
当我执行
Get-Member
时,它似乎只显示一个对象.
When I do a
Get-Member
, it seems to just show one object.
Get-Member
显示有关输入集合中不同 类型的信息,这意味着报告每种类型的第一次出现,而跳过后续出现的情况.
Get-Member
shows information about the distinct types in the collection of inputs, which means that the first occurrence of each type is reported on, with subsequent occurrences skipped.
在您的情况下,两个输入对象都是 [System.Management.Automation.PSCustomObject]
类型,因此 Get-Member
将报告只是那个一个共享类型.
In your case, both input objects are of type [System.Management.Automation.PSCustomObject]
, so Get-Member
will report just that one shared type.
例如,1, 2 |Get-Member
报告有关 System.Int32
一次的信息.
For instance, 1, 2 | Get-Member
reports information about System.Int32
once.
一个对象是上面的自定义对象,但另一个是 selected.system.int32.当我尝试一个接一个地输出时,只有第一个输出.
one object is a custom object like above, but the other it a selected.system.int32. When I try to output one after the other only the first one outputs.
PowerShell 的默认输出格式默认为隐式使用 Format-Table
用于最多具有 4 个属性的自定义对象.
PowerShell's default output formatting defaults to implicit use of Format-Table
for custom objects with up to 4 properties.
如果您输出具有不同类型的多个对象,并且第一个对象默认为隐式Format-Table
输出,则第一个对象的类型单独 决定了要在结果表中显示哪些属性(列).
If you output multiple objects that have different types, and the first object defaults to implicit Format-Table
output, that first object's type alone determines what properties (columns) to show in the resulting table.
- 注意:如果第一个对象的类型碰巧具有与其关联的格式化数据(如
Get-FormatData
),后续对象do 打印,尽管总是通过隐式Format-List
格式化.
- Note: If the first object's type happens to have formatting data associated with it (as reported by
Get-FormatData
), subsequent objects do print, albeit invariably via implicitFormat-List
formatting.
如果后续对象没有任何与第一个对象相同的属性,它们只需打印一个空行;如果它们具有一些相同的属性,则只打印它们;任何附加属性都将被忽略.
If subsequent objects do not have any of the same properties that the first object has, they simply print a blank line; if they have some of the same properties, only those are printed; any additional properties are ignored.
需要注意的是,这只是一个显示问题,但是:输出的所有对象仍然存在;如果您将输出发送到另一个命令进行进一步处理而不是直接发送到控制台,它们都会在那里.
It is important to note that this is just a display problem, however: all objects that were output are still present; if you send the output to another command for further processing instead of directly to the console, they'll all be there.
一个简单的例子:
PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 }
one two
--- ---
1 2
注意第二个自定义对象是如何产生一个空行的,因为它既没有 .one
属性,也没有 .two
属性.
Note how the 2nd custom object resulted in just a blank line, because it has neither properties .one
nor .two
.
您可以通过使用应用于每个对象的显式格式化命令来解决这个问题:
You can work around the problem by using explicit formatting commands applied to each object to output:
PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 } |
ForEach-Object { Format-Table -InputObject $_ }
one two
--- ---
1 2
three
-----
3
与单个输出命令相同的方法:
The same approach as individual output commands:
[pscustomobject] @{ one = 1; two = 2 } | Format-Table
[pscustomobject] @{ three = 3 } | Format-Table
正如 Mark Wragg 的博文 所解释的那样,所有输出都由给定的脚本 - 即使跨越不同的命令 - 也会发送到相同的管道.
(您可以将交互式提交的命令行视为隐式脚本.)
As Mark Wragg's blog post explains, all output produced by a given script - even across separate commands - is sent to the same pipeline.
(You can think of a command line submitted interactively as an implicit script.)
有关如何在显示格式方面处理单个管道中的混合类型的更多详细讨论,请参阅这个答案.
For a more detailed discussion of how a mix of types in a single pipeline is handled in terms of display formatting, see this answer.
为什么使用显式格式化命令有帮助:
通过显式管道到Format-*
cmdlet(例如,[pscustomobject] @{ one = 1; two = 2 } | Format-Table
),实际上是将格式化对象(各种[Microsoft.PowerShell.Commands.Internal.Format.*]
类型)发送到管道,然后 PowerShell有效地传递它们以进行显示.
By explicitly piping to a Format-*
cmdlet (e.g, [pscustomobject] @{ one = 1; two = 2 } | Format-Table
), you're actually sending formatting objects (various [Microsoft.PowerShell.Commands.Internal.Format.*]
types) to the pipeline, and PowerShell then effectively passes them through for display.
另一种方法是使用通用解决方法:如果您管道到Out-Host
(例如, [pscustomobject] @{ one = 1; two = 2 } | Out-Host
),在这种情况下:
An alternative is to use a generic workaround: if you pipe to Out-Host
instead (e.g., [pscustomobject] @{ one = 1; two = 2 } | Out-Host
), in which case:
- 您绕过管道并直接打印到控制台(如果您在常规控制台窗口中运行 PowerShell),
- 并且应用对象的默认格式视图.
需要注意的是,这些变通办法仅适用于显示目的,因为原始对象在此过程中丢失:
当您显式地通过管道传输到
Format-*
cmdlet 时,您将原始对象替换为包含格式说明的对象,这些对象对进一步处理无用.
When you pipe to a
Format-*
cmdlet explicitly, you replace the original object with objects containing formatting instructions, which are useless for further processing.
当您通过管道传输到 Out-Host
时,您什么都不发送到脚本的管道.
When you pipe to Out-Host
, you send nothing to the script's pipeline.
这篇关于Powershell 自定义对象混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!