New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add msbuild to NativeCommandProcessor (s_legacyCommands) in PWSH 7.3 #18660
Comments
To add additional context and elaborate on your initial post: Like
While an argument that contains no spaces normally needs no quoting at all - e.g., verbatim This anarchy - every executable on Windows being able to make up its own command-line parsing rules - is what makes a (capable) shell's life difficult; while mostly executable-agnostic general accommodations could be made that would make things work automatically in most cases, the case at hand is an example of a remaining edge case where explicit control over the process command line is required.
# WISHFUL THINKING as of v7.3.0
# Note that --"", unlike --%, would only ever act on the *next* argument, though you're free
# to encode *multiple* arguments in one string.
# Argument-specific use, single-quoted:
# Copies the verbatim value of the string - /p:Category="CI,Nightly" - as-is to the process command line.
msbuild.exe D:\test.xml --"" '/p:Category="CI,Nightly"'
# Argument-specific use, double-quoted:
$cat = 'CI,Nightly'
msbuild.exe D:\test.xml --"" "/p:Category=`"$cat`""
# All-arguments use:
# The direct-invocation equivalent of: Start-Process msbuild.exe "D:\test.xml /p:Category=`"$cat`""
$cat = 'CI,Nightly'
msbuild.exe --"" "D:\test.xml /p:Category=`"$cat`""
# Splatting use:
$cat = 'CI,Nightly'
$argsArray = 'D:\test.xml', '--""', "/p:Category=`"$cat`""
msbuild.exe @argsArray The existing,
# Via an array (implied splatting)
cmd /c msbuild.exe @( 'D:\test.xml', "/p:Category=`"CI,Nightly`"" )
# Literal equivalent
cmd /c msbuild.exe D:\Test.xml /p:Category=`"CI,Nightly`"
# Via an array - *explicit* splatting is needed for --% to be recognized.
# Note that --% applies to *all* subsequent elements in the array, not just the next one.
# (with --", it would only apply to the next one).
# !! BROKEN AS OF 7.3.0 - see https://github.com/PowerShell/PowerShell/issues/18664
# !! Use $PSNativeCommandArgumentPassing = 'Legacy' for now to see that it works.
$argsArray = @( 'D:\test.xml', '--%', "/p:Category=`"CI,Nightly`"")
msbuild.exe @argsArray
# Literal equivalent
# Note that the " now do not need escaping, but you get all the other --% downsides
# (all subsequent arguments affected, no support for PowerShell variables / expressions, no > redirections, ...)
cmd /c msbuild.exe D:\Test.xml --% /p:Category="CI,Nightly" |
If this is really fixed in 7.3.1 - Ths would be a very good solution to support backward compatibility scenarios: $categories = "CI,Nightly"
$parameters = @(
'--%'
"D:\test.xml",
"/p:Category=`"$categories`""
)
$msbuild = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe'
& $msbuild @parameters Hopefully this gets fixed in #18664 |
@mklement0 would it be your opinion then that we should really just have |
@SteveL-MSFT, indeed - to me, Here's what I think is needed to get out of this mess (and it will remain a mess, just one that is predictable and manageable):
While eliminating
|
@SteveL-MSFT, with the above in place, the following clear guidance could be provided to end users:
Diagnosing edge cases / the resulting raw process command line needs proper documentation - and should be part of the upcoming docs you mention. Additionally, consider shipping with |
|
I see, @yecril71pl, though note that By contrast, in POSIX-compatible shells In light of the above, |
|
@PowerShell/powershell-committee discussed this and don't have a proposed solution yet, however, we considered the following:
|
@SteveL-MSFT, these options only perpetuate the current confusion and lack of predictable behavior, indefinitely. |
@PowerShell/powershell-committee revisited this, we're proceeding with the plan above |
I am saddened to hear that, @SteveL-MSFT. Given that your previous comment already indicated this - regrettable - course of action, there was no need to repeat it, except if you wanted to shed light on why revisiting the decision caused you to stick with it. |
@mklement0 we want to get more feedback and not make a rash decision here. Since we are making a change to 7.3.x to default to |
Good politicians make decisions based on reason and logic; successful politicians take decisions based on the opinion of the majority. |
Are there any outlooks on the whole problem? We are stuck on version 7.2.11 because of the quoting problems. Whats the plan for this. Which next powershell release will be compatible to old scripts? |
Take a look at #18706. It's supposed to resolve the issue on Windows. We will consider whether it should be backported to PS v7.3. |
@mklement0 Can you please provide a solution to this, wehn the path to msbuild contains a space? For example like this: "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe" I fail at it :-( |
@Scordo, in this case you (unfortunately) have to pass a single cmd /c "`"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe`" $('D:\test.xml', '/p:Category="CI,Nightly"')" That is, bizarrely, If you don't use overall Therefore, to be safe:
Also note:
|
Hi @mklement0 , and thanks for the info. I've created 2 functions to ease the dealing with msbuid. This now compatible with new and old powershell versions: function Invoke-ThroughCmd {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $Executable,
[AllowNull()]
[AllowEmptyCollection()]
[Parameter(Mandatory=$false)]
[string[]] $Args,
[Parameter(Mandatory=$false)]
[int[]] $SuccessExitCode = @(0),
[switch]
$IgnoreExitCode
)
$cmdArgs = @('/c')
if ($Args) {
$cmdArgs += "`"$Executable`" $($Args -join ' ')"
} else {
$cmdArgs += "`"$Executable`""
}
& cmd.exe $cmdArgs
if ($IgnoreExitCode) {
return
}
if (-not $SuccessExitCode -contains $LASTEXITCODE) {
throw "Running 'cmd.exe $($cmdArgs -join ' ')' failed with exit code $LASTEXITCODE."
}
}
function Invoke-MSBuild {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string[]] $MSBuildArgs,
[Parameter(Mandatory=$false)]
[string] $MSBuildExe = 'msbuild.exe',
[switch]
$IgnoreExitCode
)
Invoke-ThroughCmd -Executable $MSBuildExe -Args $MSBuildArgs -IgnoreExitCode:$IgnoreExitCode
}
Invoke-MSBuild -MSBuildArgs @('D:\test.xml', '/p:Category="CI,Nightly"') -MSBuildExe 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe' It is sad to have to deal with this problem at all, but at least we now have a clean solution. Best regards, |
Glad to hear it, @Scordo, but note that your functions will only work as intended if none of the |
We know, that we have to escape args containing spaces with escaped quotes. But thanks for the info. |
Prerequisites
Steps to reproduce
After the breaking change in native command execution in pwsh 7.3 our scripts stopped working with msbuild. This happens when setting a property-value of an msbuild script containing a semicolon or comma. For this the raw part of the property assignment must contain quotes: /pCategory="CI,Nightly"
Without the quotes /pCategory=CI,Nightly the result is: MSBUILD : error MSB1006: Property is not valid. Switch: Nightly
Thats because you can set multiple properties like so: /p:Category=CI,OtherProperty=OtherValue
This command now produces different results (old pwsh without quotes in value of msbuild script, pwsh 7.3 with quotes):
& 'MSBuild.exe' @( 'D:\test.xml', "/p:Category=
"CI,Nightly
"")MSBuild-Script:
With the new quoting rules it is impossible to satisfy the msbuild commandline without using Start-Process. Which has other problems which needs workarounds: dotnet/msbuild#2269
Please add msbuild to the list of legacy commands.
Expected behavior
Actual behavior
Error details
No response
Environment data
Visuals
The text was updated successfully, but these errors were encountered: