Powershell Command Processing (Passing in Variables)

孤街浪徒 提交于 2019-12-03 14:53:54

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 scope
47> . { $foo = "foo" } # dotting executes in the current scope
48> $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 $param
Arg 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 $cmd
foo

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

Your last example if failing because "&" treats the string as one argument, so it is looking for a program named "cmd /c echo foo.exe". :)

This works:

& $cmd $params

As for the double quote issue, it does seem that cmd does not like the quotes around arguments that PowerShell puts. It gets this:

cmd "/c echo foo"

So I think it treats everything after /c as the exact command, so like so:

echo foo"

Some command line programs and funky parsing of the command line (that is why PowerShell takes over this job for functions and cmdlets). In the case of cmd, I would suggest this:

$param = "echo foo"
& cmd /c $param

it's an artifact of using cmd /c, I think. running

$param = "echo foo"
cmd /c $param

works fine. Unless you have a real code example, it's a bit hard to trouble shoot.

Args are treated differently when they are contained in a String:

PS D:\> echo "1 2 3"
1 2 3
PS D:\> echo 1 2 3
1
2
3

The same results occur when you use a variable for the args:

PS D:\> $param = "1 2 3"
PS D:\> echo $param
1 2 3

The SOLUTION is to use an Array:

PS D:\> $param = @(1,2,3)
PS D:\> echo $param
1
2
3
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!