7

I'm wanting to pass arbitrary scripts to Powershell via stdin. (In practice, I'd like to avoid having to put the script into a temporary file, but for the purposes of this question I will pipe the contents of a file to powershell.)

So I'm doing something like so (in this example, from a Windows cmd shell):

type myfile.txt | powershell -

It works if myfile.txt contains something like this:

1..3 | % { $_ *2 } 
echo done  

(It outputs 2\n4\n6\ndone.) However, if I split this first statement across multiple lines like so, then Powershell simply exists without generating any output at all:

1..3 | 
  % { $_ *2 } 
echo done  

This seems to fail for any multiline statement. For example, this also fails to produce output:

1..3 | % {
  $_ *2 } 
echo done  

I'm surprised by this since each are legal Powershell scripts that would work normally if placed into a .ps1 file and run as normal.

I've tried various things including escaping the EOL using line continuation chars, to no avail. The same effect occurs if the parent shell is Powershell, or even Python (using subprocess.Popen with stdin=PIPE). In each case, Powershell exits without any error, and the exit code is 0.

Interestingly, if I run the following, only "before.txt" gets created.

"before" | out-file before.txt
1..3 | 
   % { $_ *2 } 
"after" | out-file after.txt
echo done   

Any ideas why Powershell would have trouble reading a multi-line command, if read from stdin?

  • on a related note, if you are already within a powershell prompt, here is how you invoke the output of a non-powershell command as a script: `curl.exe https://me.com/script.ps1 | Out-String | Invoke-Expression` – masterxilo Mar 05 '23 at 11:59

2 Answers2

8

I'm going to consider this answered by this: How to end a multi-line command in PowerShell since it shows that an extra newline is required. However, I'm going to raise this to MS as a bug since this should not be required when reading from a non-tty, or when -NonInteractive switch is specified.

Please vote on my bug report to the Powershell team.

Community
  • 1
  • 1
  • Please vote on my [bug report](https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/14127231) to the Powershell team. – Michael Lewis May 24 '16 at 16:34
1

This is not a complete answer, but from what I can tell, the problem has to do with the input being sent in line by line.

To demonstrate the line-by-line issue, I invoke powershell this way:

powershell.exe -command "gc myfile.txt" | powershell.exe -

vs

powershell.exe -command "gc myfile.txt -raw" | powershell.exe -

The first example replicates what you see with type, the second reads the entire contents of the file, and it works as expected.

It also works from within PowerShell if you put the script contents in a string and pipe it into powershell.exe -.

I had a theory that it had to do with line-by-line input lacking line breaks, but it's not so clear cut. If that were the case, why would the first option work but not the second (removing the line break splitting the single pipeline should have no effect, while removing the line break between the pipeline and the echo should make it fail). Maybe there's something unclear about the way powershell is handling the input with or without line breaks.

briantist
  • 45,546
  • 6
  • 82
  • 127
  • Thanks. I've just tried this and I get same (failed) result. – Michael Lewis May 24 '16 at 15:50
  • I get same failed result if I pipe a string as you suggest. – Michael Lewis May 24 '16 at 15:51
  • @MichaelLewis: I wouldn't be surprised if PowerShell splits strings into lines when passing them to other programs. And `powershell` in this case is a program, not a cmdlet. – Joey May 24 '16 at 15:52
  • however... adding a blank line after the multi-line fixes it. As described [here](http://stackoverflow.com/questions/13229066/how-to-end-a-multi-line-command-in-powershell?rq=1) – Michael Lewis May 24 '16 at 15:54
  • @MichaelLewis interesting, does that fix all examples? – briantist May 24 '16 at 15:54
  • This doesn't solve my problem though as I need to handle arbitrary powershell scripts - I can't require multi-line commands to be followed by an extra line. – Michael Lewis May 24 '16 at 15:55
  • @briantist - Yes, all the above examples produce output if modified with an extra line. It's a clue, but not a solution... I'm still looking for a way around this. – Michael Lewis May 24 '16 at 15:57
  • 1
    @MichaelLewis so I see, so it has to be an extra line after any multiline command, not just at the end. Yeah that's rough. Replacing all linebreaks with 2 won't work correctly in all cases (because it's a valid character in a string). Why do you need invoke `powershell` this way (by piping)? – briantist May 24 '16 at 15:57
  • Well I've a yaml file which describes various commands (which can be complex scripts) to execute under various conditions. That yaml file is not under my control. TBH _could_ start messing about with temporary files created and destroyed before and after each invocation, and I may have to go that route, but it's messy and I'm intrigued as to why this doesn't work. It's clear that powershell is asking for an extra newline for reasons described in that other SO article, but I think it's a bug that that behaviour isn't turned off when non-interactive. – Michael Lewis May 24 '16 at 16:04