Skip to content

$ErrorActionPreference = 'Stop' ignored, when command read from stdin. #21808

Closed

Description

Prerequisites

Steps to reproduce

Hey.

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.

Actual behavior

it's completely broken

Error details

No response

Environment data

N/A

Visuals

No response

Activity

  1. jborean93 commented on May 9, 2024

    @jborean93
    Collaborator

    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.

    pwsh -NoProfile -NoLogo -Command - << EOF
    & {
        code here
    }
    
    
    EOF

    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.

  2. mklement0 commented on May 9, 2024

    @mklement0
    Contributor

    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:

    In other words: the following should print 1 after the parser error message, whereas it currently reports 0

    # From Bash
    pwsh -NoProfile -NoLogo -Command - <<'EOF'
    & {
        1 -eqFOO 1
    }
    
    EOF
    echo $?

    Taking 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 / -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

  3. philcerf commented on May 10, 2024

    @philcerf
    Author

    rhubarb-geek-nz

    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.

    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).

    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.

  4. SteveL-MSFT commented on May 10, 2024

    @SteveL-MSFT
    Member

    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?

  5. philcerf commented on May 10, 2024

    @philcerf
    Author

    As for amending the docs

    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.

  6. mklement0 commented on May 10, 2024

    @mklement0
    Contributor

    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.

  7. mklement0 commented on May 10, 2024

    @mklement0
    Contributor
  8. kilasuit commented on May 15, 2024

    @kilasuit
    Collaborator

    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

  9. theJasonHelmick commented on May 15, 2024

    @theJasonHelmick
    Collaborator

    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.

  10. added and removed
    Needs-TriageThe issue is new and needs to be triaged by a work group.
    WG-NeedsReviewNeeds a review by the labeled Working Group
    on May 15, 2024
  11. microsoft-github-policy-service commented on May 17, 2024

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as declined and has not had any activity for 1 day. It has been closed for housekeeping purposes.

  12. microsoft-github-policy-service commented on May 17, 2024

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as by-design and has not had any activity for 1 day. It has been closed for housekeeping purposes.

  13. microsoft-github-policy-service commented on May 17, 2024

    @microsoft-github-policy-service
    Contributor

    📣 Hey Philippe Cerfon (@philcerf), how did we do? We would love to hear your feedback with the link below! 🗣️

    🔗 https://aka.ms/PSRepoFeedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions