Select-Object后无法暂停或休眠

时间:2016-01-17 05:10:49

标签: powershell

在某些情况下,如果我在Select-Object命令后尝试暂停或休眠,则在命令之前发生暂停/休眠。

例如,使用

Get-NetAdapter | Select-Object Name,Status
Pause

Get-NetAdapter | Select-Object Name,Status | Where-Object {$_ -ne $null}
Pause

输出是:

Press Enter to continue...:

Name     Status
----     ------
Wi-Fi    Up
Ethernet Disconnected

Get-NetAdapter | Select-Object Name,Status | Format-Table
Pause

输出是:

Name     Status
----     ------
Wi-Fi    Up
Ethernet Disconnected

Press Enter to continue...:

这里发生了什么?这是一个错误还是一个功能?

2 个答案:

答案 0 :(得分:6)

您看到的是新PowerShell v5功能的后果。 Format-Table现在收集输入300毫秒以找到更好的列宽。即使您明确指定-AutoSize:$false,它也会以这种方式工作。

在命令提示符下键入command时,该命令隐式通过管道传递给Out-Default命令的单个实例。然后Out-Default命令决定如何格式化对象并在PowerShell主机(控制台)上打印它们。因此,即使您未在代码中直接使用Format-Table,也不意味着您的管道中没有Format-TableOut-Default可以决定将对象格式化为表格,并在内部使用Format-Table

具有四个或更少属性且没有在格式文件中为它们定义自定义格式的自定义对象被格式化为表格。通过将Select-Object与两个属性一起使用,可以准确生成这些对象。

PowerShell管道是单线程的。这意味着Format-Table在300毫秒间隔过去时不能只输出所有收集的对象。 Format-Table必须等到你管道下一个项目(调用的进程块)或报告的管道结束(调用结束块)。

PS> Get-NetAdapter | Select-Object Name,Status
>>> Pause
>>> [PSCustomObject]@{Name='Some long name';Status='Some long status'} #1
>>> Pause
>>> [PSCustomObject]@{Name='Even longer name';Status='Even longer status'}
>>> Pause

Press Enter to continue...:
Name           Status
----           ------
Ethernet       Up
Some long name Some long status
Press Enter to continue...:
Even longer... Even longer s...
Press Enter to continue...:


PS>

隐式Format-Table在第一个Pause之前不打印任何内容(严格地说它打印空行),因为它仍在等待更多输入对象(尚未经过300毫秒)来决定列宽。当第一个对象(#1)在300毫秒间隔后出现(假设您不要在按 Enter 时禁用),则Format-Table决定列宽并打印所有收集的对象。将立即打印任何其他对象,但它们不再影响列宽。如果列的值很大,则会被截断。

PS> Get-NetAdapter | Select-Object Name,Status | Format-Table
>>> Pause

Name     Status
----     ------
Ethernet Up


Press Enter to continue...:
PS>

使用此代码,显式Format-Table的结束块将在Pause之前执行。在结束块Format-Table知道它已经获得所有输入,因此它可以决定列宽并立即输出所有收集的对象。隐式Out-Default看到来自Format-Table输出的格式化对象,Out-Default知道它们不需要任何添加格式,也可以立即在主机(控制台)上打印它们。因此,在调用Pause之前打印整个表格。

注意表格标记结尾的位置差异(两个空行)。在第一个示例中,它放在最后Pause之后。这是因为隐式Format-Table仍处于活动状态且仍在等待,您将其他对象传递给它。仅当您的命令完全完成Format-Table时才会确认表标记的输入和输出结束。在第二个示例中,显式Format-TablePause之前完成,因此整个表(包括表标记的结尾)在Pause命令之前打印。

表标记结尾的位置差异也可以在以前的PowerShell版本中注意到。

答案 1 :(得分:1)

Format-Table与我无关,我只是在PowerSell V 4.0和PowerShel V5.0中尝试以下内容,可以重现问题:

Get-Process |Select-Object -Property name ; pause
转过来是:

Get-Process |Select-Object -Property Name  |%{Write-host $_.name};pause

这里再次暂停:

Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';$_} |Select-Object -Property Name  ;pause

但不是在这里

Get-Process |%{$_.name | Set-Content 'c:\temp\test.txt';Start-Sleep -Milliseconds 1;$_} |Select-Object
-Property Name  ;pause

对于我来说,在PowerShell V5.0中,一切都像在流水线操作的指令中不需要主机一样,然后这些指令是异步运行的。

我希望@Keith Hill的人能够看到这种行为。