Read-Host Executes Before Previous Statements

Am relatively new to powershell and the following is driving me insane.

Get-ChildItem -path C:\temp

$filename = Read-host “Enter filename you want”

This produces the following as expected:

Directory: C:\temp

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/10/2019 5:30 PM 0 File A.txt 
-a---- 4/10/2019 5:30 PM 0 File B.txt
-a---- 4/10/2019 8:21 PM 0 File C.txt

Enter filename you want:

If I add a “| select name” to the first statement, the Read-Host gets executed first BEFORE it. Once I press ENTER, the output from the the first line is displayed

Get-ChildItem -path C:\temp | select name

$filename = Read-host "Enter filename you want"

<p style=“text-align: left;”>OUTPUT:</p>
<p style=“text-align: left;”>Enter filename you want: Notice the child item stuff hasn’t come up yet. So I am going to press ENTER after which the output from the previous line is displayed.

Name
----
File A.txt
File B.txt
File C.txt

What in the world is happening? Amazed I can’t find anything on google

Thanks,
Bob

You can add ‘out-host’, that will force it to display first.

Get-ChildItem -path C:\temp | select name | out-host

$filename = Read-host "Enter filename you want"

It has to do how powershell handles stuff, some stuff is an in output stream where as other stuff is written directly to host.
‘out-host’ will ‘force’ it to write it directly to the host.

https://devblogs.microsoft.com/scripting/understanding-streams-redirection-and-write-host-in-powershell/

In both the cases Get-ChildItem executes first, but in the second case the output is shown post Read-Host execution. IMO, its something related to output fomrating as below example returns same output as first method.

Get-ChildItem -path C:\temp | Select Name | Format-Table

$filename = Read-host "Enter filename you want"

#Or

Get-ChildItem -path C:\temp | Select Name | Out-String

$filename = Read-host "Enter filename you want"

PowerShell intentionally disables standard output by around 300ms in order to be able to group objects of the same type. This is a necessary concession to the pipeline nature of much of its internals.

As others have said, the best way to avoid this is with Write-Host or Out-Host to bypass the standard output. Which, if you intend to actually return output from your script or function to other code, you should be doing anyway. The more clutter in the standard output stream, the harder time you’ll have getting what you actually want out of it.

Thanks guys!!! My family thanks you as well since I was screaming at the computer for hours. :slight_smile: Still very strange though. I read the article Alex referenced and it was pretty interesting. Makes me think that adding the select statement, without out-host, is causing the output to be piped to the Read-Host command which doesn’t know what to do with it. Holds onto it until after it gets input from the user and then passes it to the host output.

In essence powershell seems to be parsing the two statements like this with a pipe:

Get-ChildItem -path C:\temp | select name | $filename = Read-host “Enter filename you want”

At a loss as to why that would happen without my having a pipe in there. Regardless, now I can go back to spending time on the parts of the application I am writing that actually should be complicated. :slight_smile:

Not really :slight_smile:

It’s just that the Read-Host triggers before the output pipeline finishes processing the previous output and it gets through the system to the screen. If you did have a pipe there, it’d be a parse error anyway; you can’t have an expression in the middle or end of a pipeline.

I just tried testing your timing theory by putting a sleep of 5 seconds between the two statements so that output can finish before the read-host. The result is the same except there is a 5 second delay before Read-host prompts me. After pushing ENTER, I see the output from the first statement. Strange.

Get-ChildItem -path C:\temp |select name

Start-Sleep -Seconds 5

$filename = Read-host “`nEnter filename you want”

Yeah, Start-Sleep won’t help you here I’m afraid. It sleeps the whole thread, which means PowerShell’s pipeline stuff also pauses. :frowning:

Save to a variable the select the property.

$Detail = Get-ChildItem -path C:\temp

$Detail.Name

$filename = Read-host "`nEnter filename you want"