select对象后无法暂停或hibernate

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

例如,用

 Get-NetAdapter | Select-Object Name,Status Pause 

要么

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

输出是:

 按Enter继续...:

名称状态
 ---- ------
 Wi-Fi了
以太网断开 

而与

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

输出是:

 名称状态
 ---- ------
 Wi-Fi了
以太网断开

按Enter继续...: 

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

您看到的是新的PowerShell v5function的后果。 Format-Table收集input300毫秒,以find更好的列宽。 即使你明确地指定了-AutoSize:$false它也是这样工作的。

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

自定义对象具有四个或更less的属性,并且没有在格式文件中为它们定义自定义格式,它们被格式化为表格。 通过使用具有两个属性的Select-Object ,您可以精确地生成该对象。

PowerShellpipe道是单线程的。 这意味着Format-Table在300毫秒的时间间隔内不能输出所有收集的对象。 Format-Table必须等到你input下一个项目(被调用的进程块)或者结尾的pipeline(被调用的结束块)。

 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> 

Implicit Format-Table在第一次Pause之前不打印任何东西(严格地说是打印空行),因为它仍在等待更多的input对象(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知道它已经得到了所有的input,所以它可以决定列的宽度,并立即输出所有的收集的对象。 Implicit Out-Default看到Format-Table输出中的格式化对象,而Out-Default知道它们不需要任何添加格式,并立即将其打印在主机(控制台)上。 所以整个表在打印Pause之前打印。

注意表格标记结尾位置的不同(两个空行)。 在第一个例子中,它放在上次Pause 。 这是因为隐式的Format-Table仍然处于活动状态,仍在等待,您将其他对象传递给它。 只有当你的命令全部完成后, Format-Table才会确认表标记的input输出结束。 在第二个例子中,显式的Format-TablePause之前完成,所以整个表(包括表标记的结尾)在Pause命令之前被打印。

表标记结束位置的差异可以注意到以前版本的PowerShell。

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中,一切正常,如果在stream水线指令中不需要主机,那么这些指令是asynchronous运行的。

我会像@凯斯希尔那样看待这种行为。