Powershell Command Processing (Passing in Variables)
The call operator '&' is unnecessary in this case. It is used to invoke a command in a new scope. This is typically used to invoke a command specified by a string or scriptblock. It also has the side benefit that any variables created in say a PowerShell script are discarded after the command finishes and the scope goes away.
However since the cmd is an EXE it executes in a completely different process. FWIW, you get similar output directly from cmd.exe:
> cmd "/c echo foo"foo"
So the extra quote on the end is a cmd.exe issue. Typically you need to keep the command separate from the parameters when PowerShell is doing the parsing to invoke the command e.g.
45> & { $foo = "foo" }46> $foo # Note that $foo wasn't found - it went away with the scope47> . { $foo = "foo" } # dotting executes in the current scope48> $foo foo
The notable exception here is that Invoke-Expression behaves like an "evaluate this string" function. Use with care, especially if the user provides the string. Your day could suck if they provided "ri C:\ -r".
In this case, as others have suggested I would pull the /c out of the string $param string and specify it e.g.:
cmd /c $param
Or use Invoke-Expression but use with care. BTW when you are trying to debug issues with sending arguments to EXE from PowerShell, check out the echoargs utility in PowerShell Community Extensions (http://pscx.codeplex.com). It is very handy:
49> $param = "/c echo foo"50> echoargs $paramArg 0 is </c echo foo>
This shows that cmd.exe receives "/c echo foo" as a single argument. "/c" should be a separate argument from "echo foo" (the command to execute).
I have had problems with the & call operator in the past when trying to invoke executable type commands like you are trying. Not sure I understand why. Invoke-Expression however, always seems to work in this context:
PS C:\> $cmd = "cmd /c echo foo"PS C:\> Invoke-expression $cmdfoo
One other way I found to do this was to create an array of arguments for the command line and use that with the apersand & call operator. Something like this:
$exe = "cmd";[Array]$params = "/c", "echo", "foo";& $exe $params;
It's worked well for me.
I originally found this technique here: http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html