Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell Command Processing (Passing in Variables)

I'm creating a Powershell script to deploy some code and part of the process is to call a command-line compression tool called RAR.EXE to back-up some folders.

I'm attempting to dynamically build out the parameters and then have powershell call the command with the variables but I'm running into trouble. It isn't working...

Run the following script and you should see what I'm talking about. The parameters being passed in as a variable are being mangled. If I pass the entire command + parameters in I get the infamous "is not recognized as a cmdlet..." message.

Thanks for any help!

echo "this should succeed"
& cmd /c echo foo

echo "why does this echo out an additional double quote?"
$param = "/c echo foo"
& cmd "$param"

echo "this does the same"
$param = "/c echo foo"
& cmd $param

echo "escaping the slash doesn't work either..."
$param = "`/c echo foo"
& cmd $param

echo "this fails, but why?"
$cmd = "cmd /c echo foo"
&$cmd
like image 747
GabeA Avatar asked Apr 30 '09 22:04

GabeA


People also ask

How do you pass variables in a PowerShell script?

Passing arguments in PowerShell is the same as in any other shell: you just type the command name, and then each argument, separated by spaces. If you need to specify the parameter name, you prefix it with a dash like -Name and then after a space (or a colon), the value.

How do I pass multiple parameters to a PowerShell script?

To pass multiple parameters you must use the command line syntax that includes the names of the parameters. For example, here is a sample PowerShell script that runs the Get-Service function with two parameters. The parameters are the name of the service(s) and the name of the Computer.

What does %% mean in PowerShell?

% is an alias for the ForEach-Object cmdlet. An alias is just another name by which you can reference a cmdlet or function.


2 Answers

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).

like image 193
Keith Hill Avatar answered Dec 13 '22 07:12

Keith Hill


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
like image 37
zdan Avatar answered Dec 13 '22 07:12

zdan