Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to Pause or Sleep after Select-Object

Tags:

powershell

In some cases, if I try to pause or sleep after a Select-Object command, the pause/sleep occurs before the command.

For example, with

Get-NetAdapter | Select-Object Name,Status
Pause

or

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

the output is:

Press Enter to continue...:

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

Whereas with

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

the output is:

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

Press Enter to continue...:

What's going on here? Is this a bug or a feature?

like image 285
Mica Avatar asked Jan 17 '16 05:01

Mica


Video Answer


2 Answers

What you see is a consequences of new PowerShell v5 feature. Format-Table now collect input for 300 milliseconds to find better column width. It work this way even if you explicitly specify -AutoSize:$false.

When you type command in command prompt, that command implicitly piped to single instance of Out-Default command. The Out-Default command then decide how to format objects and print them on PowerShell host (console). So that, even if you does not use Format-Table directly in your code, that does not mean that you does not have Format-Table in your pipeline. Out-Default can decide to format objects as table and use Format-Table internally.

Custom objects with four or less properties and without custom formatting defined for them in format files are formatted as table. By using Select-Object with two properties you produce exactly that objects.

PowerShell pipeline is single-threaded. That means that Format-Table can not just output all collected objects when 300 milliseconds interval elapsed. Format-Table have to wait till you pipe next item to it (process block invoked) or end of pipeline reported (end block invoked).

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 does not print anything (strictly saying it print empty line) before first Pause because it still waiting for more input objects (300 milliseconds not yet elapsed) to decide on column width. When first object (#1) come after 300 milliseconds interval (assuming that you are not to fast on pressing Enter), then Format-Table decide on column width and print all collected objects. Any further objects will be printed without delay, but them can not affect column width anymore. If value is to big for column it will be truncated.

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

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


Press Enter to continue...:
PS>

With this code, end block of explicit Format-Table will be executed before Pause. In end block Format-Table know that it already got all the input, so it can decide on column width and output all collected objects right away. Implicit Out-Default see that formatting objects from Format-Table output, and Out-Default know that them does not need any addition formatting and print them on host (console) right away as well. So whole table got printed before Pause invoked.

Notice the difference in placement of end of table mark (two empty lines). In first example it placed after last Pause. It is because implicit Format-Table still active and still wait, that you pass additional object to it. Only when your command fully completed Format-Table acknowledge end of input and output end of table mark. In second example, explicit Format-Table completes before Pause, so whole table (including end of table mark) got printed before Pause command.

The difference in placement of end of table mark can be noticed it previous versions of PowerShell as well.

like image 139
user4003407 Avatar answered Oct 13 '22 19:10

user4003407


Format-Table has nothing to do with that I just try the following in PowerSell V 4.0 and PowerShel V5.0 and the problem can be reproduced :

Get-Process |Select-Object -Property name ; pause

a turn arround is :

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

Here again pause is run first :

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

But not here

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

For me, in PowerShell V5.0 everything works like if the host is not needed in instructions that are pipelined then these instructions are run asynchronosly.

I would have like that people as @Keith Hill have a look to this behavior.

like image 30
JPBlanc Avatar answered Oct 13 '22 17:10

JPBlanc