有人可以帮我理解下面两段代码之间的区别。为什么两者的结果都不同。我在每种情况下选择相同的属性(名称):
代码1:
$obj = Get-Service | Where-Object {$_.Status -eq "Running"} | foreach-object {$_.Name} | select -first 3
foreach ( $item in $obj ) { write-output "Name is : $item" }
Output :
Name is : AeLookupSvc
Name is : Appinfo
Name is : AudioEndpointBuilder
代码2:
$obj = Get-Service | Where-Object {$_.Status -eq "Running"} | select -first 3 name
foreach ( $item in $obj ) { write-output "Name is : $item" }
Output :
Name is : @{Name=AeLookupSvc}
Name is : @{Name=Appinfo}
Name is : @{Name=AudioEndpointBuilder}
答案 0 :(得分:11)
Select-Object将一个自定义对象数组返回给管道;在这种情况下,只有一个属性恰好是一个字符串
正如@walidtourni所提到的,使用expand
可以解决这个问题。这是因为expand
导致输出为属性的值,而不是具有该值的属性的自定义对象。这是可能的原因是expand
只需要一个参数;即,您不可能尝试为同一“行”返回多个值。
另一方面,foreach-object只是将东西吐出到管道中。如果您尝试包含第二个属性而不手动将两者都包装到自定义对象中,则输出将在同一行上创建另一行而不是两个属性。
要演示,请运行以下命令:
Clear
$x = Get-Service | Where-Object {$_.Status -eq "Running"} | select -first 3
$x | foreach-object {$_.Name} #returns 3 rows, single column; string
$x | foreach-object {$_.Name,$_.CanPauseAndContinue;} #returns 6 rows, single column; alternate string & boolean
$x | foreach-object {$_.Name;$_.CanPauseAndContinue;} #returns 6 rows, single column; alternate string & boolean
$x | select Name #returns 3 rows, single column (string); custom object
$x | select Name, CanPauseAndContinue #returns 3 rows, two columns (string & boolean); custom property
$x | select -expand Name #returns 3 rows, single column; string; notice the lack of column header showing this is a string, not a string property of a custom object
$x | select -expand Name,CanPauseAndContinue #error; -expand can only take single valued arguments
$x | select -expand Name -expand CanPauseAndContinue #error; you can't try to define the same paramenter twice
答案 1 :(得分:3)
对于类似的结果,您可以更改第二个示例:
select -first 3 -expand name
选择对象选择属性对象
答案 2 :(得分:0)
这是一篇旧帖子,但我想我会扩展@JohnLBevan 的答案。
Select-Object
的正常操作是创建一个 PSCustomObject
来复制原始对象的属性。
Get-Process
Get-Process | Select-Object Name,CPU
如果您只指定一个属性,那么它会创建一个只有一个属性 (Get-Process | Select-Object Name
) 的对象——这就是您在 @{Name=AeLookupSvc}
等中看到的。请注意,这与属性的值完全不同,它有一个支持获取的参数:
Get-Process | Select-Object -ExpandProperty Name
另一方面,ForEach-Object
的作用更像是针对每个管道对象执行的循环体。这很容易用于检索要传递的属性的值,甚至还提供了一种方便的简写方式。
Get-Process | ForEach-Object Name
所以为了真正补充其他答案,我对性能差异做了一些探索:
# Benchmark
1..100 | ForEach-Object {Measure-Command {Get-WinEvent -LogName System -ErrorAction SilentlyContinue} | Select-Object -ExpandProperty TotalMinutes} | Measure-Object -Average
# Average: 2.01325857505 Minutes
# Select-Object -ExpandProperty
1..100 | ForEach-Object {Measure-Command {Get-WinEvent -LogName System -ErrorAction SilentlyContinue | Select-Object -ExpandProperty LevelDisplayName -ErrorAction SilentlyContinue} | Select-Object -ExpandProperty TotalMinutes} | Measure-Object -Average
# Average: 2.87394915385 Minutes
# note the `Select-Object -ErrorAction SilentlyContinue` because not all pipeline records are accepted by Select-Object (strange, but I did not explore why)
# ForEach-Object
1..100 | ForEach-Object {Measure-Command {Get-WinEvent -LogName System -ErrorAction SilentlyContinue | ForEach-Object LevelDisplayName} | Select-Object -ExpandProperty TotalMinutes} | Measure-Object -Average
# Average: 3.10188571238333 Minutes
请注意,我在 PowerShell 5.1 上并行运行这些(不同的 PowerShell 窗口)。