question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature Request: Support passing command line args with -Command option.

See original GitHub issue

Summary of the new feature/enhancement

Requesting support for passing arguments via command line to be passed to the command the user is requesting to be executed. Compare with python:

python.exe -c "import sys; print(sys.argv[1])" "It's `your`, not `you're`"

NOTE: this request is not about invoking PowerShell from within PowerShell as a cmdlet. I’m aware that there’s special processing there that translates -Command / -Args to the command line parameters -encodedCommand and -encodedArguments. This is specifically regarding creating a process where the native command line arguments passed to the process include -Command and -Args – e.g. invoking PowerShell form some other shell, such as bash or cmd.

Proposed technical implementation details (optional)

Propose extending -Command to support -Args when passed as command line arguments to the PowerShell host. This would apply any time that:

  1. The argument immediately following -Command starts with ‘{’ and ends with ‘}’, once whitespace has been trimmed.
  2. The 2nd argument after -Command is the argument -Args (ordinal case insensitive)
  3. -Args is followed by zero or more additional command line arguments.

When this occurs, the $Args value will be bound with an array of the remaining command line arguments following the -Args argument.

Backwards compat risk: estimated to be small, but non-zero. When attempting to use -Command with the first argument being a script block scring, I found no way to pass -Args afterward and result in a correcltly parsing powershell command, let alone a useful one. I suspect it can be done, but is unlikely to be practical. If nothing else, the change is definitely smaller in impact than the breaking changes to Set-Content between pwhs 5.1 and 6.0.

Note: proposing no change to -Command or -Args parsing when invoking the Powershell function/commandlet from within powershell. That behavior will remain unchanged – namely, when invoking PowerShell from within Powershell, the -Command and -Args arguments are replaced with -encodedCommand and -encodedArguments before the process is launched. This already has full fidelity today.

Rationale

Note that this greatly simplifies string escaping. Being able to pass arguments after the command allows the user to only have to deal with one level of string escaping – the current shell they’re interacting with.

In contrast, schemes like powershell.exe -Command "{ param($a) echo $a }" -A 'my example', the argument my example gets parsed twice – first in your current shell (e.g. PowerShell, Bash, or Windows Command Shell), and then again by the powershell parser when parsing it as part of the -Command argument. This makes it prohibitively difficult to forward arguments between scripts, or invoke PowerShell via exec/CreateProcess from another program.

For example, passing the string “It’s `your`, not `you’re`” PowerShell through another script is exceedingly difficult, e.g. if embedded in the -Command argument. For instance, if you don’t quote the string, PowerShell will treat the whitespace as argument separators. Also, PowerShell will parse the “`” characters as escapes, and the “'” characters as unescaped string literals. This is on top of the unescaping the outer shell has already performed on the user input – e.g. in bash, the user probably wrapped the above in single or double quotes in order to be able to include spaces in the argument.

As discussed in issue https://github.com/PowerShell/PowerShell/issues/15410, Powershell only support passing arguments to a -command when invoked as a function from within powershell, not when invoked externally.

Examples in other script environments:

  • Python (invoked from cmd)

    $ c:\bin\Python26\python.exe -c “import sys; print(sys.argv[1])” “It’s your, not you're” It’s your, not you're

  • JavaScript/node (invoked from cmd)

    $ c:\bin\node.exe -e “console.log(process.argv[1])” “It’s your, not you're” It’s your, not you're

  • sh (invoked from cmd)

    $ C:\bin\busybox.exe sh -c “echo $0” “It’s your, not you're” It’s your, not you're

  • bash (invoked from PowerShell)

    bash -c ‘echo $0’ “It’s your, not you're” It’s your, not you're

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:14 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
mklement0commented, Dec 2, 2022

FWIW, this was first proposed as a breaking change in 2017, pre-v6, in the context of better aligning the PowerShell CLI with that of POSIX-compatible shells:

I think -CommandWithArgs (perhaps aliased to -ca) would help, but to avoid confusion around the syntax for -Args I would simply omit -Args and use purely positional processing: the first argument following -CommandWithArgs would be the PowerShell code, and all remaining arguments would implicitly be the arguments to pass to it.

That is, the equivalent of the following sh command line (note the unfortunate need for -, which binds to $0, which is something we can avoid in PowerShell):

# Run from Bash, for instance.
$ sh -c 'for a; do echo "[$a]"; done' - '$fun' '@times'
[$fun]
[@times]

would then be:

pwsh -CommandWithArgs '$args | % { "[$_]" }'  '$fun' '@times'

Note that, as in sh and Python, for instance, the $args | % { "[$_]" } argument would implicitly act like a script block, so no need for { ... } enclosure; to put it differently: the argument would act like an anonymous, in-memory script file.

1reaction
ghostcommented, May 28, 2021

FYI, for folks looking for a short term workaround, I’m using [Environment]::GetCommandLineArgs and a carefully placed line comment to work around this limitation for now. Posting here as it might help others with the same issue.

Workaround: https://github.com/aaronla-ms/powershell-tips-and-tricks/blob/main/examples/embed.cmd

<div> GitHub</div><div>aaronla-ms/powershell-tips-and-tricks</div><div>Contribute to aaronla-ms/powershell-tips-and-tricks development by creating an account on GitHub.</div>
Read more comments on GitHub >

github_iconTop Results From Across the Web

[Feature] Allow custom command-line arguments in ...
Maybe I'm missing something, but it appears that right now, the only way to pass custom arguments is through environment variables, which seems ......
Read more >
Jest: Passing custom arguments
In the post i'll show how to pass custom command line arguments to test suits run by Jest framework.
Read more >
argparse — Parser for command-line options, arguments ...
The argparse module's support for command-line interfaces is built around an instance of argparse.ArgumentParser . It is a container for argument ...
Read more >
Adding arguments and options to your Bash scripts
The ability for a Bash script to handle command line options such as -h to display help gives you some powerful capabilities to...
Read more >
How do I pass command line arguments to a Node.js ...
Standard Method (no library). The arguments are stored in process.argv. Here are the node docs on handling command line args:.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found