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?

3
  • 1
    Possible duplicate of PowerShell: Start a process with unquoted arguments Commented Jun 27, 2016 at 23:07
  • 2
    & "C:/Program Files (x86)/ClamWin/bin/clamd.exe" --install or use apostrophes instead of double quotes. Commented Jun 27, 2016 at 23:40
  • 1
    @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). Commented Jun 28, 2016 at 3:50

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.