Skip to content

CLI: pwsh -Command - and pwsh -File - unexpectedly exhibit pseudo-interactive behavior, lack support for argument passing #3223

Closed

Description

Related: #9497

While pwsh -Command - and pwsh -File - both accept command input from the pipeline / from stdin:

  • they exhibit undesirable pseudo-interactive behavior:

    • they execute each line one by one, in separate pipelines.

      • additionally, -File - prints the prompt string and each input line before the output
    • they require pipelines that are spread across multiple lines for readability to be terminated with two newlines (see below) - as would be necessary interactively, if PSReadLine weren't loaded.

  • they do not support combining - input with passing arguments:

    • While that limitation is documented for -Command - (-File - is undocumented altogether), there's no good reason for this limitation, and it limits the usefulness of the construct.

    • While you could (but in my mind shouldn't) argue that -Command - should be limited to providing a self-contained source-code snippet that doesn't expect arguments, at the least
      -File - should support passing arguments by placing them after the - - after all, you want to be able to pass arguments to a script - whether that script is specified as a a file or as a script's content via stdin.

Thus, the following command, which spreads pipeline "hi" | % { "$_ there" } across two lines - does not work:

@'
"in"
"hi" |
  % { "$_ there" }
"out"
'@ | powershell -noprofile -command -

The above yields only in, because the end of the multi-line command is never detected, causing it to be quietly ignored.

As evidence that this happens in the real world, see this Stack Overflow question, whose accepted answer provides more detail.

Inserting an empty line after the multi-line command fixes the problem:

@'
"in"
"hi" |
  % { "$_ there" }

"out"
'@ | powershell -noprofile -command -

The above now yields in, hi there and out - that is, the multi-line pipeline was correctly submitted due to the extra newline, as was the single-line statement afterwards.


Summary:

Activity

  1. changed the title [-]Reconsider the behavior of powershell.exe -Command -: it shouldn't require terminating multi-line commands with an empty line and/or consider proper support for `-File -`[/-] [+]Reconsider the behavior of powershell.exe -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for `-File -`[/+] on Feb 27, 2017
  2. changed the title [-]Reconsider the behavior of powershell.exe -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for `-File -`[/-] [+]Reconsider the behavior of powershell.exe -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for -File -[/+] on Feb 27, 2017
  3. added
    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif
    on Aug 29, 2018
  4. changed the title [-]Reconsider the behavior of powershell.exe -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for -File -[/-] [+]CLI: Reconsider the behavior of pwsh -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for -File -[/+] on Feb 2, 2019
  5. changed the title [-]CLI: Reconsider the behavior of pwsh -Command -: it shouldn't require terminating multi-line commands with an empty line, and/or consider proper support for -File -[/-] [+]CLI: `pwsh -Command -` and `pwsh -File -` unexpectedly exhibit pseudo-interactive behavior, lack support for argument passing[/+] on Apr 25, 2019
  6. iSazonov commented on Apr 29, 2019

    @iSazonov
    Collaborator

    At first look I'd expect that "-Command -" accept only one line command but how input multi-line one? And it is not clear that is semantic of "-File script.ps1 -"

    Also I'd expect that we read console input if there is not explicit redirection but currenly the dash accepted as argument that can confuse.

  7. mklement0 commented on Apr 29, 2019

    @mklement0
    ContributorAuthor

    At first look I'd expect that -Command - accept only one line command but how input multi-line one?

    As argued in #9494 (comment), there's really no point in supporting -Command - altogether, if -File - worked properly.

    Given that we cannot remove it: Just like you can already pass a multi-line argument to -Command, the entirety of stdin input should be executed as a snippet of source code.
    (Line-by-line interactive execution doesn't really make sense - just start a PowerShell session normally to do that.)

    it is not clear that is semantic of -File script.ps1 -

    As stated in the linked comment, the - is not special at all in this case: since it follows a -File argument - script.ps1 - it is just a (positional) argument to pass to script.ps1; - is only special in lieu of a script-file argument.

  8. iSazonov commented on Apr 29, 2019

    @iSazonov
    Collaborator

    Given that we cannot remove it: Just like you can already pass a multi-line argument to -Command, the entirety of stdin input should be executed as a snippet of source code.

    We have API Powershell.AddCommand() and Powershell.AddScript() - I believe "-Command" behavior must fit first and "-File" - second.

  9. mklement0 commented on Apr 29, 2019

    @mklement0
    ContributorAuthor

    It is the other way around:

    .AddScript() is the one that behaves like -Command - you can pass it an arbitrary snippet of PowerShell code - the method is poorly named, .AddScriptBlock() would have made more sense.

    .AddCommand() is for adding a command name or path, with the need to specify arguments separately; as such it is akin to -File.

    Aside from that, there's no requirement of one-to-one mapping to SDK methods here.

  10. iSazonov commented on Apr 29, 2019

    @iSazonov
    Collaborator

    Aside from that, there's no requirement of one-to-one mapping to SDK methods here.

    My comment was about expected behavior. Both methods is often used in our tests and I'd expect such behavior in CLI too.

  11. mklement0 commented on Apr 29, 2019

    @mklement0
    ContributorAuthor

    As shown, the names of the SDK methods not only do not align with the CLI parameters, but suggest the opposite mapping.

    It is the CLI parameters that are sensibly named, and their fundamental semantics must not and should not change (-File is self-describing (the fact that the argument must be a script file is implied), and -Command / -c aligns with the long-established -c command in POSIX-like shells (and is akin to /c in cmd.exe)).

    What should change, however, is how they deal with stdin input, as (now) suggested in the OP and argued in #9494 (comment)

  12. mklement0 commented on Apr 29, 2019

    @mklement0
    ContributorAuthor

    P.S., Ilya (@iSazonov): You could open a separate issue suggesting more sensible alias names for the SDK methods (obviously, the old names cannot be removed); especially .AddScript() keeps causing confusion.

  13. iSazonov commented on Apr 30, 2019

    @iSazonov
    Collaborator

    Michael Klement (@mklement0) I think this is a dead proposal (add aliases) because it is a public API.

    -File - is not documented so we could change its behavior as we need.

  14. mklement0 commented on Apr 30, 2019

    @mklement0
    ContributorAuthor

    -File - is not documented so we could change its behavior as we need.

    That's a good point.

    We can then deprecate -Command - (and leave it as is) to support the following idioms, mostly based on -File, in conjunction with fixing #9497:

    # Execute *code* piped from stdin.
    ... | pwsh   # same as: ... | pwsh -File -
    
    # Execute *code* piped from stdin *with arguments* 
    # (`File -` is then required for disambiguation)
    ... | pwsh -File - args...
    
    # Provide *input data* via stdin - to a script file
    ... | pwsh -File someScript.ps1 [args...] 
    
    # Provide *input data* via stdin - to a string containing commands
    ... | pwsh -Command $snippetOfPsCode

    The unfortunate thing - which we cannot change - is that -Command doesn't accept arguments to pass to $snippetOfPsCode (which the latter would see as $Args or bind to its parameters) - it simply considers the remaining arguments to be part of the command string.

    I think this is a dead proposal (add aliases) because it is a public API.

    I don't think it's a pressing issue, and the downside is that it bloats the SDK, but why couldn't we add new, more descriptive method names that effectively call their less descriptively named predecessors? Of course, you'd then need to know what version of the SDK you're targeting.

  15. 5 remaining items

  16. Veetaha commented on Mar 22, 2024

    @Veetaha

    This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.

    Nice joke. It is still relevant

  17. Veetaha commented on Nov 6, 2024

    @Veetaha

    This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.

    Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.

    Bruh. Fix this issue already please

  18. pjeby commented on Jan 5, 2025

    @pjeby

    While the need for the extra line feed is suboptimal, I do want to point out that the interactive, block-at-a-time nature of -Command - is actually useful if you want to avoid PowerShell startup times to run multiple PS commands from a long-running process written in another language. Just open a pipe, feed it commands and read all the output, repeat as needed. Works like a charm for things you don't want to have to write in PowerShell, and don't want to have to wait an entire second for the executable to load up to run each command. It's like having a PowerShell DLL you can load from any language using only that language's subprocess piping capabilities.

    So there are downsides to removing block-at-a-time execution - mainly that it's nearly impossible to do this in a practical manner when using actually-interactive PS, which echoes your input and spits out intermediate results you don't care about along with the final result you're looking for. -Command - neatly solves this.

  19. Veetaha commented on Jul 5, 2025

    @Veetaha
    Image

    Nah-ah

  20. microsoft-github-policy-service commented on Jan 2, 2026

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if there is no further activity in 7 days, the issue will be closed automatically.

    Activity in this case refers only to comments on the issue. If the issue is closed and you are the author, you can re-open the issue using the button below. Please add more information to be considered during retriage. If you are not the author but the issue is impacting you after it has been closed, please submit a new issue with updated details and a link to this issue and the original.

  21. xtqqczze commented on Jan 13, 2026

    @xtqqczze
    Contributor

    Ilya (@iSazonov) Please reopen.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifResolution-No ActivityIssue has had no activity for 6 months or moreWG-Interactive-Consolethe console experience

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions