tags:

views:

776

answers:

2

I've just tested this on PowerShell v1.0. Setup is as follows:

 Id CommandLine
 -- -----------
  1 $msbuild = "C:\Windows\Microsoft.NET\Framework\v3.5\msbuild.exe"
  4 $a = "C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build"

.

This line fails with an unintuitive error message:

 Id CommandLine
 -- -----------
  5 & $msbuild $a

.

This line fails because & expects the first argument to be the command itself.

 Id CommandLine
 -- -----------
 10 & "$msbuild $a"

.

This line works:

 Id CommandLine
 -- -----------
 16 cmd /c "$msbuild $a"

.

Please explain. I'm more interested in why the & syntax isn't working, than an MSBuild-specific workaround.

+3  A: 

Ugh.

$collectionOfArgs = @("C:\some\project\or\other\src\Solution.sln", 
    "/target:Clean", "/target:Build")
& $msbuild $collectionOfArgs

This works. & takes a collection of arguments, so you must split up strings containing multiple arguments into a collection of string arguments.

Peter Seale
+5  A: 

The issues you are seeing results from PowerShell parsing arguments. In the first example, when PowerShell sees $a it passes it as a single parameter msbuild. We can see this using the echoargs utility from PSCX:.

PS> $a = "C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build"
PS> & echoargs $a
Arg 0 is <C:\some\project\or\other\src\Solution.sln /target:Clean /target:Build>

The second example is even worse because you are telling powershell to invoke "$echoargs $a" as the command name and it isn't a valid command name.

The third line works because CMD.exe gets the expanded form of "$echoargs $a" as a single argument which is parses and executes:

You have a couple of options here. First I do it this way:

PS> & $msbuild C:\some\project\or\other\src\Solution.sln `
    /target:Clean /target:Build

The other option is to use Invoke-Expression like so:

PS> Invoke-Expression "$msbuild $a"

In general I try to be very careful with Invoke-Expression particularly if any part of the string that gets invoked is provided by the user.

Keith Hill