You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
$ErrorActionPreference = 'Stop' ignored, when command read from stdin. #21808
Another issue when reading the commands from stdin, possibly related to #21784.
Consider something like:
$ pwsh -NonInteractive -NoProfile -Command '$ErrorActionPreference = "Stop"; Get-Process -foo; Write-Host BLA'
Get-Process: A parameter cannot be found that matches parameter name 'foo'.
This exits on the error and BLA is not written.
The same when the command is given as argument but with newlines in it:
$ pwsh' -NonInteractive -NoProfile -Command $'$ErrorActionPreference = "Stop"\nGet-Process -foo\nWrite-Host BLA'
Get-Process:
Line |
2 | Get-Process -foo
| ~~~~
| A parameter cannot be found that matches parameter name 'foo'.
Now when read from stdin:
$ pwsh -NonInteractive -NoProfile -Command '-' <<'END'
$ErrorActionPreference = 'Stop'
Get-Process -foo
Write-Host BLA
END
gives:
Get-Process: A parameter cannot be found that matches parameter name 'foo'.
BLA
However:
$ pwsh -NonInteractive -NoProfile -Command '-' <<'END'
$ErrorActionPreference = 'Stop'
Get-Process -foo; Write-Host BLA
END
works as expected and does not print BLA:
Get-Process: A parameter cannot be found that matches parameter name 'foo'.
WTF?! ... Reading commands from stdin seems basically completely broken.
Expected behavior
reading commands from stdin should work as if given as `-Command` argument.
The stdin reader acts like the command line repl so things like $ErrorActionPreference = 'Stop' does apply but the next line is read in stdin so will still run. It's just like copy/pasting the stdin data to the actual console.
I find when you want to use -Command - with stdin input you are best to wrap the code to run in a scriptblock so that the standard rules apply to a file to run.
You still need the trailing newlines to ensure PowerShell sees the end of the } and runs it but everything inside the {} runs as one statement so things like $ErrorActionPreference = 'Stop' applies.
Indeed, as discussed in the previously mentioned #3223 and in #15331, both -Command - and -File - were seemingly designed to exhibit REPL-like behavior, were the code being provided via stdin isn't run as a whole - as it would be with a direct -Command argument or with a file argument passed to -File - but statement by statement.
-File - is especially baffling, since it prints the prompt string and the statement about to be executed before each statement, but there's seemingly code out there that relies on this - see #15331 (comment)
Given the desire to maintain backward compatibility, these behaviors won't change, though even in the context of this behaviors there are two bugs:
Note that when -Command - is truly used to create a REPL, the exit code isn't all that interesting, as it will only tell you the last statement's success status, whereas the point of a REPL is to keep the process open and feed multiple, separate statements to PowerShell, whose success status would have to be determined differently.
However, for non-REPL, all-statements-at-once use - which requires the workaround demonstrated by Jordan Borean (@jborean93) - a parser error should still result in an exit code of 1.
In other words: the following should print 1 after the parser error message, whereas it currently reports 0
Getting proper script-via-stdin CLI behavior would require introducing either a dedicated new CLI parameter, say a -CommandFromStdin, or some magic name other than - to request this behavior by -Command / -File argument.
Alternatively, there's the option to piggyback on the still-experimental PSCommandWithArgs feature, which introduces a -CommandWithArgs CLI parameter that supports passing arguments to the piece of code passed as a single string to this parameter. Since there's no backward-compatibility burden there, ... | pwsh -CommandWithArgs - could be made to exhibit the expected script-via-stdin CLI behavior
While this makes for a somewhat awkward asymmetry, this could be helped with documentation; the upside is that no new parameter is required.
There is a consistency rather than being completely broken.
My explanations often start with PowerShell is not a UNIX shell. UNIX programs are pipe/stream based, PowerShell is record based.
Now consider each line in stdin as its own record and executed one after the other, however in the same session so the state accumulates, so setting $ErrorActionPreference is persistent in the session.
Which would be fine, if PowerShell really always did it like that, but it doesn't. If I execute the whole thing as one string (with newlines) passed as single argument to -Command it works as expected. As it probably also does when executing it as .ps1 file.
IMO it simply never makes sense to have the exactly same script behave completely different depending on how it's read.
But again, this seems completely strange to me, especially when invoked with -NonInteractive.
Plus it kinda defeat's the whole purpose of reading from stdin.
As you might have guessed, I come from the Linux world, where a program in such a case would check whether stdin is connected to a terminal or not.
No idea whether windows has such a concept, but if one says -File - or -Command - one most like does not want something like an interactive prompt, cause then one would have simply omitted the options altogether?
Even if it's decided that this is in fact the desired behaviour, there should IMO be quite some warnings about it in the help texts to -Command - and -File - cause right now those read as if they'd behave just as if instead of - a real script respectively script file would be given (which again would behave as expected).
Taking a step back:
Well, in the end it's your decision, and if there'd be some warning in the description of these options which tells about the behaviour I'd also consider the issue as "solved", but...
From a perspective of what's common sense and assuming that PowerShell will be a long time around, I would suggest to rather do the compatibility break[0] now than live one with something that is in itself inconsistent[1].
[0] And do you really think that a lot people actually depend on that behaviour? I mean it's even not documented as it actually behaves, so anyone depending on this would already use it by accident. Plus what sense would it make to use -Commnd - and want the script to be semi-interactively read, when one can just omit the option for the same?
[1] Cause you'd then have -Command someReadCommandsHere which behaves non-interactively, -File someRealFile which behaves non-interactively, -CommandFromStdin which behaves non-interactively, but -Command - and -File - which suddenly behave semi-interactively. And at the same time, as you've said, for -CommandWithArgs (which I guess is modelled after POSIX behaviour - i.e. a script file + args) it would probably make quite some sense to really change the behaviour - so yet another unexpected deviation from homogenous behaviour.
I hear you - #3223 pretty much argued the same points.
I have no say in what technically breaking changes are considered acceptable; my previous comment links to at least one instance of existing code that would break.
I think it's more than a bucket 3 breaking change to change the - behavior. However, if the desire is to be able to pipe a script to pwsh via STDIN, then wouldn't it be better to introduce a new parameter strictly for that purpose?
I mostly meant what comes out of -help and friends.
As for -, one further way of handling that would be, to completely remove it for -Command and -File… and instead provide completely new options for both use cases (non-interactive vs semi-interactive).
Perhaps should there ever be a new major version.
That way, any current user would fail fast and could quickly adapt their code, without any silent issues.
The benefit would be, that you'd get rid of the ambiguously different behaviour within a single option.
One could further argue, that at least for -File - it should have been even more clear to anyone that the behaviour should have been from the beginning like as if it would be a (script) file, i.e. non-interactive... and that the current behaviour i simply a bug and not something where one could rely upon for backwards compatibility.
Anyway... I'm now simply using multi-line strings (instead of here-documents) to pass a script to PowerShell via -Command and no longer via stdin... so for me it doesn’t really matter much.
I mostly meant what comes out of -help and friends.
Command-specific help topics as well as conceptual help topics including the one for the CLI, about_Pwsh, are maintained both online and - assuming you've run Update-Help - locally.
However, a duplicate of the content of about_Pwsh is also baked into the pwsh binary (for invocation via pwsh -help, pwsh --help, pwsh -?, pwsh /?), which therefore requires a source-code change - but I'd still start with creating an issue in the docs repo - they'll know what to do.
Steve Lee (@SteveL-MSFT), personally I think that fixing the problem in the context of -CommandWithArgs is sufficient and preferable, but I wouldn't complain about a separate, new parameter either.
As for what could be done if backward compatibility were NOT a concern (a collection of proposed breaking changes can be found in #6745, but there are no plans for a version allowed to make such fundamentally breaking changes):
Introduce a new parameter, say, -REPLMode to request the REPL behavior (modeled on the -SSHServerMode parameter, possibly with an additional switch distinguishing between the two REPL modes provided by -Command - vs. -File -, if needed).
Make -File - behave as known from POSIX-compatible shells: read the entire stdin input, and treat it as a whole as the content of an (anonymous) script - along with support for pass-through arguments (which aren't currently supported with -File -); with stdin input only, -File - should be implied (as is currently already the case);
There is then no need to also support -Command -; it would amount to unnecessary duplication of functionality.
I think it's more than a bucket 3 breaking change to change the - behavior. However, if the desire is to be able to pipe a script to pwsh via STDIN, then wouldn't it be better to introduce a new parameter strictly for that purpose?
I agree that adding a new parameter makes more sense than changing behaviour as can then be better documented than this current mix of semi-broken expectations vs how PowerShell currently works which gives this mixed outputs.
Interactive-UX WG (which I can't make) will be discussing this later tonight so expect a response from one of the rest of the WG on this
Philippe Cerfon (@philcerf) - Thank you for this issue. The existing -command and -file were not intended for this scenario. The WG is not certain that the new scenario is needed since other ways are available to achieve this behavior. We would need to see more compelling use cases to consider adding a feature for this use case. We will update the documentation (Thank you Michael Klement (@mklement0) ) to explain the current behavior.
Activity
mklement0 commentedon May 9, 2024
See also:
pwsh -Command -andpwsh -File -unexpectedly exhibit pseudo-interactive behavior, lack support for argument passing #3223jborean93 commentedon May 9, 2024
The stdin reader acts like the command line repl so things like
$ErrorActionPreference = 'Stop'does apply but the next line is read in stdin so will still run. It's just like copy/pasting the stdin data to the actual console.I find when you want to use
-Command -with stdin input you are best to wrap the code to run in a scriptblock so that the standard rules apply to a file to run.You still need the trailing newlines to ensure PowerShell sees the end of the
}and runs it but everything inside the{}runs as one statement so things like$ErrorActionPreference = 'Stop'applies.mklement0 commentedon May 9, 2024
Indeed, as discussed in the previously mentioned #3223 and in #15331, both
-Command -and-File -were seemingly designed to exhibit REPL-like behavior, were the code being provided via stdin isn't run as a whole - as it would be with a direct-Commandargument or with a file argument passed to-File- but statement by statement.-File -is especially baffling, since it prints the prompt string and the statement about to be executed before each statement, but there's seemingly code out there that relies on this - see #15331 (comment)Given the desire to maintain backward compatibility, these behaviors won't change, though even in the context of this behaviors there are two bugs:
An incomplete statement is ignored, as mentioned in Script via STDIN does not exit with error code and does not stop correctly #15331 (comment); at the time, no separate issue was filed, but I now see that you have since done so in (some) command read from stdin seem to require extra trailing newline #21644.
A parser error occurring in the last statement doesn't result in a nonzero exit code: you've reported this in exit status
0on syntax errors, when reading scrip from stdin #21784.Note that when
-Command -is truly used to create a REPL, the exit code isn't all that interesting, as it will only tell you the last statement's success status, whereas the point of a REPL is to keep the process open and feed multiple, separate statements to PowerShell, whose success status would have to be determined differently.However, for non-REPL, all-statements-at-once use - which requires the workaround demonstrated by Jordan Borean (@jborean93) - a parser error should still result in an exit code of
1.In other words: the following should print
1after the parser error message, whereas it currently reports0Taking a step back:
Getting proper script-via-stdin CLI behavior would require introducing either a dedicated new CLI parameter, say a
-CommandFromStdin, or some magic name other than-to request this behavior by-Command/-Fileargument.Alternatively, there's the option to piggyback on the still-experimental
PSCommandWithArgsfeature, which introduces a-CommandWithArgsCLI parameter that supports passing arguments to the piece of code passed as a single string to this parameter. Since there's no backward-compatibility burden there,... | pwsh -CommandWithArgs -could be made to exhibit the expected script-via-stdin CLI behavior-CommandWithArgsCLI parameter doesn't work with-(code provided via stdin) #22891philcerf commentedon May 10, 2024
rhubarb-geek-nz
Which would be fine, if PowerShell really always did it like that, but it doesn't. If I execute the whole thing as one string (with newlines) passed as single argument to
-Commandit works as expected. As it probably also does when executing it as.ps1file.IMO it simply never makes sense to have the exactly same script behave completely different depending on how it's read.
Now as Jordan Borean (@jborean93) and Michael Klement (@mklement0) mentioned, the stdin reader apparently behaves like some semi-interactive prompt.
But again, this seems completely strange to me, especially when invoked with
-NonInteractive.Plus it kinda defeat's the whole purpose of reading from stdin.
As you might have guessed, I come from the Linux world, where a program in such a case would check whether stdin is connected to a terminal or not.
No idea whether windows has such a concept, but if one says
-File -or-Command -one most like does not want something like an interactive prompt, cause then one would have simply omitted the options altogether?Even if it's decided that this is in fact the desired behaviour, there should IMO be quite some warnings about it in the help texts to
-Command -and-File -cause right now those read as if they'd behave just as if instead of-a real script respectively script file would be given (which again would behave as expected).Well, in the end it's your decision, and if there'd be some warning in the description of these options which tells about the behaviour I'd also consider the issue as "solved", but...
From a perspective of what's common sense and assuming that PowerShell will be a long time around, I would suggest to rather do the compatibility break[0] now than live one with something that is in itself inconsistent[1].
[0] And do you really think that a lot people actually depend on that behaviour? I mean it's even not documented as it actually behaves, so anyone depending on this would already use it by accident. Plus what sense would it make to use
-Commnd -and want the script to be semi-interactively read, when one can just omit the option for the same?[1] Cause you'd then have
-Command someReadCommandsHerewhich behaves non-interactively,-File someRealFilewhich behaves non-interactively,-CommandFromStdinwhich behaves non-interactively, but-Command -and-File -which suddenly behave semi-interactively. And at the same time, as you've said, for-CommandWithArgs(which I guess is modelled after POSIX behaviour - i.e. a script file + args) it would probably make quite some sense to really change the behaviour - so yet another unexpected deviation from homogenous behaviour.mklement0 commentedon May 10, 2024
I hear you - #3223 pretty much argued the same points.
I have no say in what technically breaking changes are considered acceptable; my previous comment links to at least one instance of existing code that would break.
As for amending the docs: I encourage you to file an issue at https://github.com/MicrosoftDocs/PowerShell-Docs/issues/new?template=04-customer-feedback.yml&pageUrl=https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fpowershell%2Fmodule%2Fmicrosoft.powershell.core%2Fabout%2Fabout_Pwsh%3Fview%3Dpowershell-7.4&pageQueryParams=%3Fview%3Dpowershell-7.4&contentSourceUrl=https%3A%2F%2Fgithub.com%2FMicrosoftDocs%2FPowerShell-Docs%2Fblob%2Fmain%2Freference%2F7.4%2FMicrosoft.PowerShell.Core%2FAbout%2Fabout_Pwsh.md&documentVersionIndependentId=4ccd2aa8-1a49-5b9d-04ee-5d2c61fb3c38&feedback=%0A%0A%5BEnter+feedback+here%5D%0A&author=%40sdwheeler&metadata=*+ID%3A+583c1d4c-486c-9338-2cd2-9ea3bc30cefb+%0A*+Service%3A+**powershell**&labels=needs-triage
🤞that at least
-CommandWithArgswill be modified to work sensibly.SteveL-MSFT commentedon May 10, 2024
I think it's more than a bucket 3 breaking change to change the
-behavior. However, if the desire is to be able to pipe a script topwshvia STDIN, then wouldn't it be better to introduce a new parameter strictly for that purpose?philcerf commentedon May 10, 2024
I mostly meant what comes out of
-helpand friends.As for
-, one further way of handling that would be, to completely remove it for-Commandand-File… and instead provide completely new options for both use cases (non-interactive vs semi-interactive).Perhaps should there ever be a new major version.
That way, any current user would fail fast and could quickly adapt their code, without any silent issues.
The benefit would be, that you'd get rid of the ambiguously different behaviour within a single option.
One could further argue, that at least for
-File -it should have been even more clear to anyone that the behaviour should have been from the beginning like as if it would be a (script) file, i.e. non-interactive... and that the current behaviour i simply a bug and not something where one could rely upon for backwards compatibility.Anyway... I'm now simply using multi-line strings (instead of here-documents) to pass a script to PowerShell via
-Commandand no longer via stdin... so for me it doesn’t really matter much.mklement0 commentedon May 10, 2024
Command-specific help topics as well as conceptual help topics including the one for the CLI, about_Pwsh, are maintained both online and - assuming you've run
Update-Help- locally.However, a duplicate of the content of about_Pwsh is also baked into the
pwshbinary (for invocation viapwsh -help,pwsh --help,pwsh -?,pwsh /?), which therefore requires a source-code change - but I'd still start with creating an issue in the docs repo - they'll know what to do.Steve Lee (@SteveL-MSFT), personally I think that fixing the problem in the context of
-CommandWithArgsis sufficient and preferable, but I wouldn't complain about a separate, new parameter either.As for what could be done if backward compatibility were NOT a concern (a collection of proposed breaking changes can be found in #6745, but there are no plans for a version allowed to make such fundamentally breaking changes):
Introduce a new parameter, say,
-REPLModeto request the REPL behavior (modeled on the-SSHServerModeparameter, possibly with an additional switch distinguishing between the two REPL modes provided by-Command -vs.-File -, if needed).Make
-File -behave as known from POSIX-compatible shells: read the entire stdin input, and treat it as a whole as the content of an (anonymous) script - along with support for pass-through arguments (which aren't currently supported with-File -); with stdin input only,-File -should be implied (as is currently already the case);There is then no need to also support
-Command -; it would amount to unnecessary duplication of functionality.mklement0 commentedon May 10, 2024
I've created a docs issue:
-File -and-Command -and a workaround MicrosoftDocs/PowerShell-Docs#11098kilasuit commentedon May 15, 2024
I agree that adding a new parameter makes more sense than changing behaviour as can then be better documented than this current mix of semi-broken expectations vs how PowerShell currently works which gives this mixed outputs.
Interactive-UX WG (which I can't make) will be discussing this later tonight so expect a response from one of the rest of the WG on this
theJasonHelmick commentedon May 15, 2024
Philippe Cerfon (@philcerf) - Thank you for this issue. The existing -command and -file were not intended for this scenario. The WG is not certain that the new scenario is needed since other ways are available to achieve this behavior. We would need to see more compelling use cases to consider adding a feature for this use case. We will update the documentation (Thank you Michael Klement (@mklement0) ) to explain the current behavior.
microsoft-github-policy-service commentedon May 17, 2024
This issue has been marked as declined and has not had any activity for 1 day. It has been closed for housekeeping purposes.
microsoft-github-policy-service commentedon May 17, 2024
This issue has been marked as by-design and has not had any activity for 1 day. It has been closed for housekeeping purposes.
microsoft-github-policy-service commentedon May 17, 2024
📣 Hey Philippe Cerfon (@philcerf), how did we do? We would love to hear your feedback with the link below! 🗣️
🔗 https://aka.ms/PSRepoFeedback