How do I escape a directory correctly when using psake, exec, and msbuild?

3.4k views Asked by At

I can execute the following command in PowerShell:

msbuild "c:\some\spaced path\project.sln" /p:MvcBuildViews=False /p:OutDir="c:\\some\\spaced path\\deploy\\Package\\"

The paths are changed, but the real ones also contain a spaced component. The double-slash is a trick from e.g. this answer.

If I run that directly, msbuild understands the path. However, it needs to run in psake like this:

exec { msbuild $SolutionFile "/p:MvcBuildViews=False;OutDir=$OutputDir" }

That works if the path has no spaces, but I want to adapt it to work with spaces (for both the sln path and OutDir). I've tried, but I couldn't figure out the escaping.

EDIT:

To clarify, it also works if I hard-code the full path in psake:

exec { msbuild "c:\some\spaced path\project.sln" /p:MvcBuildViews=False /p:OutDir="c:\\some\\spaced path\\deploy\\Package\\" }

However, it needs to use the OutputDir variable (which is not double-slash escaped). So, I add a temporary variable for that, then try to construct the command line.:

$double_slashed_dir = $OutputDir.Replace('\', '\\');
write $double_slashed_dir;
exec { msbuild $SolutionFile /p:MvcBuildViews=False "/p:OutDir=`"$double_slashed_dir`"" }

This doesn't work (I've tried a couple variations). With the above I get "MSB1008: Only one project can be specified."

5

There are 5 answers

2
Roman Kuzmin On BEST ANSWER

This variation worked for me (double slashes and trailing slashes in $OutputDir seem to be important):

task build {
    $SolutionFile = "C:\TEMP\spaced path\ConsoleApplication1.sln"
    $OutputDir = "C:\\TEMP\\spaced path2\\"
    exec { msbuild $SolutionFile "/p:MvcBuildViews=False;OutDir=$OutputDir" }
}
0
Rob On

I've been struggling this this too, and the answer I finally came up with is: quote the entire switch, not just the path.

So, for example:

$buildBranch = "a path/with multiple/spaces in/"

# Use an array of arguments for common build settings, note: no trailing slash after Apps
$buildSettings = (
    ('"/Property:SolutionDir=' + $buildBranch + '\My Apps"'),
    '/t:Build', 
    '/p:PlatformTarget=x86', 
    '/p:Configuration=Release')

# Combine the common build settings with the specific project
$arg = $buildSettings + @('"' + $buildBranch + '\My Apps\MyProjectPath\MyProject.vcxproj"')

exec {
    &$msbuild $arg
}

The key difference between this and all my other attempts is in the quoting of the /Property switch.

I initially did:

'/Property:SolutionDir="' + $buildBranch + '\My Apps"'

Note that the double quote I want to pass to msbuild comes after the switch name and before the value.

MsBuild would see:

/Property:SolutionDir="some path\with spaces\My Apps"

This didn't work.

I changed it to:

'"/Property:SolutionDir=' + $buildBranch + '\My Apps"'

MsBuild would see:

"/Property:SolutionDir=some path\with spaces\My Apps"

This did work!

1
zdan On

You want to put quotes around your OutDir, but putting single quotes will confuse the command shell parser due to the other quotes in your argument, so you need to escape those quotes by double quoting them:

exec { msbuild $SolutionFile "/p:MvcBuildViews=False;OutDir=`"`"$OutputDir`"`"" }
2
Matthew Flaschen On

I got it working with Invoke-Expression:

$double_slashed_dir = $OutputDir.Replace('\', '\\');
$msbuild_command = 'msbuild "' + $SolutionFile + '" /p:MvcBuildViews=False /p:OutDir="' + $double_slashed_dir + '"';
exec { Invoke-Expression $msbuild_command }

I consider this a little hackish. It requires string concatenation, and as far as I can tell, Invoke-Expression is basically eval (though it should be safe as there is no user input involved here).

So I'm leaving the question open for now in the hopes of a better answer. It should show the variables clearly.

1
gprasant On

I tried this with the following and it worked. The only thing i added is a double quote(") after the msbuild command. This is what I have tried :

properties{
    $build_Dir="F:\projects\tweet sharp\src";
}

Task Default -depends Build


Task Build {
        Exec { msbuild "$build_Dir\TweetSharp.sln" }
}

As you can see, the build dir includes a space('tweet sharp'). Just try enclosing all the parameters of your msbuild task within double quotes and check if it works.