If you're given a string representing a whole command line - i.e. a string containing both an executable name/path and its arguments, you indeed can not use .
, the dot-sourcing operator, nor can you use &
, the call operator, because these operators only accept an executable name or path as their first argument, with the executable's arguments needing to be specified separately.
If, by contrast, you want to construct a command line yourself, programmatically, use the array-based technique shown in Luuk's answer.
Note that with external programs such as ping
, .
behaves the same as &
- only with PowerShell scripts or script blocks do these operators behave differently: .
runs the script (block) directly in the caller's scope, &
- the more common case as - runs it in a child scope.
Also note that use of &
for invoking scripts and external programs whose names/paths are neither quoted nor are expressed via variables is optional.
Invoke-Expression
(iex
) - which should generally be avoided - is the simplest solution, but the usual caveat applies:
- Given that
Invoke-Expression
allows execution of arbitrary code stored in a string, be sure that you either fully control or implicitly trust the string's content.
$commandText = "ping -t 127.0.0.1"
# !! Be sure that you trust $command to do what you expect.
Invoke-Expression $commandText
Alternatively, you can create a script block { ... }
and invoke it on demand with &
- but note that this involves the same risks as using Invoke-Expression
:
$commandText = "ping -t 127.0.0.1"
# Parse the command line into a script block.
$scriptBlock = [scriptblock]::Create($commandText)
# Invoke the script block, which you can do repeatedly.
& $scriptBlock
For repeated invocations this is slightly more efficient than using Invoke-Expression
every time, though that probably won't matter in practice.
At least hypothetically, you can use the technique to support passing additional arguments ad hoc on each invocation (@args
is the splatted form of the automatic $args
variable); e.g.:
$commandText = 'cmd /c echo one'
# Append @args to the original command line, which expands to
# to the arguments passed on invocation of the script block.
# Note:
# Placing @args *last* may not always work.
$scriptBlock = [scriptblock]::Create($commandText + ' @args')
# Pass additional arguments on invocation.
# -> 'one two three'
& $scriptBlock two three
If the command line was written for a different shell / for a no-shell invocation:
Command lines written for cmd.exe
and for no-shell invocation contexts such as scheduled tasks may or may not work when executed directly by PowerShell, depending on the specific command, due to PowerShell's different parameter syntax.
Notably, PowerShell has more metacharacters than cmd.exe
that need quoting or escaping, such as @
, (
, )
, and {
, }
, and its escape character (`
, the so-called backtick) is different (cmd.exe
uses ^
).
In that case, it is simplest to pass the command line to the cmd.exe
CLI, using its /c
parameter:
$commandText = "ping -t 127.0.0.1"
# Let cmd.exe execute the command line, via cmd /c
cmd /c $commandText
Note:
- On Unix-like platforms, use
/bin/sh -c $commandText
instead.