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.
& "C:/Program Files (x86)/ClamWin/bin/clamd.exe" --install
or use apostrophes instead of double quotes. – Jacelynjacenta&
(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