tags:

views:

150

answers:

3

In windows powershell, I am trying to store a move command in a string and then execute it. Can someone tell me why this doesn't work?

PS C:\Temp\> dir
    Directory: Microsoft.PowerShell.Core\FileSystem::C:\Temp

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         8/14/2009   8:05 PM       2596 sa.csproj
-a---         8/15/2009  10:42 AM          0 test.ps1


PS C:\Temp> $str = "mv sa.csproj sb.csproj"
PS C:\Temp> &$str
The term 'mv sa.csproj sb.csproj' is not recognized as a cmdlet, function, operable program, or script file. Verify the
 term and try again.
At line:1 char:2
+ &$ <<<< str
PS C:\Temp>

I get this error when storing any command with arguments. How do I overcome this limitation?

+6  A: 
Joey
George Mauer
Joey
+5  A: 

All of Johannes suggestions are spot on but I want to make folks aware that in V2 there is another option. You put the command in a string as before but you put the parameters in a hashtable and invoke using & e.g.:

$cmd = 'mv'
$params = @{Path = 'log.txt'; Destination = 'log.bak'}
&$cmd @params

This uses a new V2 feature called splatting. It is kind of like using a response file for a command but you put the parameters in a hashtable instead of a file.

Note: you can also put the parameters in an array which will plug in the parameters "by positional" rather than by name e.g.:

$cmd = "cpi"
$params = ('log.txt', 'log.bak')
&$cmd @params

It may not exactly fit the OP's problem but it is a trick worth knowing about.

Keith Hill
+1  A: 

I had to answer a similar question a while back about invoking an external program after building up a list of arguments:

Checked and it looks like using . $program $argString or & $program $argString does not work if $argString contains multiple arguments. The . and & operators just do a direct call, passing the entire $argString as a single argument.

Instead of using [string]$argString and doing $argString += "-aaa `"b b b`"", you could change it to [string[]]$argArray and use $argArray += @('-aaa', 'b b b'), which will work and will automatically escape strings as necessary.

You can also use $process = [Diagnostics.Process]::Start( $program, $argString ). This will make it easier to track execution progress, but harder to retrieve any text output.

Or you can put everything in a string and use Invoke-Expression "$program $argString", which will parse the entire string as a command and execute it correctly.

As Keith mentioned, splatting is another good option in PowerShell 2.

Emperor XLII