Run command line in PowerShell
Asked Answered
B

1

1

I know there are lots of posts regarding this, but nothing worked for me.

I am trying to run this command line in PowerShell:

C:/Program Files (x86)/ClamWin/bin/clamd.exe --install

I have this in PowerShell:

&"C:/Program Files (x86)/ClamWin/bin/clamd.exe --install"

But all this does is execute clamd.exe, ignoring the --install parameter

How can I get the full command line to run?

Buenabuenaventura answered 27/6, 2016 at 22:59 Comment(3)
Possible duplicate of PowerShell: Start a process with unquoted argumentsChronaxie
& "C:/Program Files (x86)/ClamWin/bin/clamd.exe" --install or use apostrophes instead of double quotes.Jacelynjacenta
@KoryGill: While the linked question is related, this question is distinct in that it is about the fundamentals of the syntax of & (whereas the linked question builds on a preexisting basic understanding of it and concerns an advanced aspect that doesn't come into play here).Nystrom
N
8

Josef Z's comment on the question provides the solution:

& "C:/Program Files (x86)/ClamWin/bin/clamd.exe" --install # double-quoted exe path

or, given that the executable path is a literal (contains no variable references or subexpressions), using a verbatim (single-quoted) string ('...'):

& 'C:/Program Files (x86)/ClamWin/bin/clamd.exe' --install # single-quoted exe path

As for why your own solution attempt failed:

  • The call operator, &, expects only a command name/path as an argument, not a full command line.
    Invoke-Expression accepts an entire command line, but that complicates things further and can be a security risk.
  • If you want to store a whole command line in a variable, for later on-demand execution, use a script block ({ ... }): see this answer
  • To construct arguments programmatically for a call to an external program, use splatting - see this answer.

As for why using & is the solution:

  • The need for quoting stands to reason: you need to tell PowerShell that C:/Program Files (x86)/ClamWin/bin/clamd.exe is a single token (path), despite containing embedded spaces.

  • The need for &, the so-called call operator is due to PowerShell's two fundamental parsing modes:

    • argument mode, which works like a traditional shell, where the first token is a command name, with subsequent tokens representing the arguments, which only require quoting if they contain shell metacharacters (chars. with special meaning to PowerShell, such as spaces to separate tokens);
      that is why --install need not, but can be quoted (PowerShell will simply remove the quotes for you before passing the argument to the target executable.)

    • expression mode, which works like expressions in programming languages.

PowerShell decides based on a statement's first token what parsing mode to apply:

If the first token is a quoted string - which we need here due to the embedded spaces in the executable path - or a variable reference (e.g., $var ...), PowerShell parses in expression mode by default.
A quoted string or a variable reference as an expression would simply output the string / variable value.

However, given that we want to execute the executable whose path is stored in a quoted string, we need to force argument mode, which is what the & operator ensures.


Generally, it's important to understand that PowerShell performs nontrivial pre-processing of the command line before the target executable is invoked, so what the command line looks like in PowerShell code is generally not directly what the target executable sees.

  • If you reference a PowerShell variable on the command line and that variable contains embedded spaces, PowerShell will implicitly enclose the variable's value in double quotes before passing it on - this is discussed in this answer to the linked question.

  • PowerShell's metacharacters differ from that of cmd.exe and are more numerous (notably, , has special meaning in PowerShell (array constructor), but not cmd.exe - see this answer).

  • To simplify reuse of existing, cmd.exe-based command lines, PowerShell v3 introduced the special stop-parsing token, --%, which turns off PowerShell's normal parsing of the remainder of the command line and only interpolates cmd.exe-style environment-variable references (e.g., %USERNAME%). However, this comes with fundamental limitations - see the bottom section of this answer.

Nystrom answered 28/6, 2016 at 3:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.