i am trying to pass cmd.exe multi variable command line the code is running in PowerShell script as part of larger script .
the code below fails to pass the correct parameter's.
$msbuild = "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe"
$buildCommand = 'C:\Git\Asd\build\XDA_2019.sln /m /t:Build /p:Configuration=Debug /p:Platform="ASX Platform"'
Write-Host "buildCommand: $buildCommand"
Write-Host "msbuild: $msbuild"
$startProcessArgs = @('/c', $msbuild, $buildCommand)
Start-Process -FilePath cmd.exe -ArgumentList $startProcessArgs -PassThru -Wait -NoNewWindow
Error
buildCommand: C:\CamtekGit\BIS\build\Falcon_2019.sln /m /t:Build /p:Configuration=Debug /p:Platform="Eagle Platform"
msbuild: C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
tried running the command direct in cmd and it works cmd.exe also read through and could not fix it Powershell: Start-Process doesn't pass arguments to cmd.exe Running cmd.exe through start-process but unable to pass the command to cmd.exe
Thanks for any help
To synchronously execute console applications or batch files in the current window, call them directly, do not use Start-Process
(or the System.Diagnostics.Process
API it is based on) - see this answer.
GitHub docs issue #6239 provides guidance on when use of Start-Process
is and isn't appropriate.
Direct execution not also allows you to directly capture an external program's output, it also reflects its process exit code in the automatic $LASTEXITCODE
variable afterwards.
Therefore:
cmd /c "`"$msbuild`" $buildCommand"
Note the need to use embedded double quotes around the executable path in the command line passed to cmd.exe
, given that it contains spaces.
Their effective absence is also was caused the problem in your Start-Process
call:
A long-standing bug in Start-Process
unfortunately requires use of embedded double-quoting around arguments that contain spaces, e.g. -ArgumentList '-foo', '"bar baz"'
.
It is therefore generally better to encode all arguments in a single string, e.g. -ArgumentList '-foo "bar baz"'
, because the situational need to use embedded double-quoting is then obvious.
See this answer for details.
In your specific case, you could make your Start-Process
call work as follows:
$startProcessArgs = "/c `"`"$msbuild`" $buildCommand`""
Note: That this works - despite the lack of escaping of the doubly nested "
chars. - is a testament to cmd.exe
's "quirks" when it comes to quoting.
Taking a step back:
msbuild.exe
, as any external program, can also be invoked directly from PowerShell. However, behind the scenes PowerShell transforms arguments such as /p:Platform="ASX Platform"
to "/p:Platform=ASX Platform"
, which msbuild.exe
may not understand.
There are several workarounds, with the call via cmd /c
being the conceptually cleanest.
Another one is use of --%
, the stop-parsing token, but it comes with severe limitations:
& "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe" C:\Git\Asd\build\XDA_2019.sln /m /t:Build /p:Configuration=Debug --% /p:Platform="ASX Platform"
Another one - limited to Windows PowerShell - is use to use embedded double quotes, which, however, relies on PowerShell's fundamentally broken handling of embedded double quotes in external-program arguments:
& "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe" C:\Git\Asd\build\XDA_2019.sln /m /t:Build /p:Configuration=Debug '/p:Platform="ASX Platform"'
Another one - with all the disadvantages of Start-Process
use - is to use Start-Process
to call msbuild.exe
directly (not via cmd.exe
), which in your case would simplify your call to:
Start-Process -FilePath $msbuild -ArgumentList $buildCommand -PassThru -Wait -NoNewWindow