I'd like to change release notes during dotnet pack
command. Normally this is straightforward:
$releaseNotes = "Something"
dotnet pack --configuration Release -p:PackageReleaseNotes=$releaseNotes
But then $releaseNotes variable contains some special characters, multiple lines and otherwise "illegal" symbols i.e.:
# Release 2.8.1 - Integrate with Github Actions
- Add Github Actions for build. Remove integration with AppVeyor
- Add architecture tests to check if settings can be properly handled
- Add debuging option for code gen
# Improve TupleHelper
User is no longer required to call for TupleHelper.ParseNext method. It's code was incorporated into ParseElement method. It's now enough to call:
```csharp
var _helper = new TupleHelper(',', '∅', '\\', '(', ')');
var input = "(3.14, Ala ma kota)";
var enumerator = _helper.ParseStart(input, 2, "DoubleAndString");
var key = _helper.ParseElement(ref enumerator, TextTransformer.Default.GetTransformer<double>());
var value = _helper.ParseElement(ref enumerator, TextTransformer.Default.GetTransformer<string>(), 2, "DoubleAndString");
_helper.ParseEnd(ref enumerator, 2, "DoubleAndString");
```
All generated calls were updated accordingly
then things go south. How can I force PowerShell to pass proper variables to -p:PackageReleaseNotes
parameter ?
I tried
dotnet pack --configuration Release -p:PackageReleaseNotes=$releaseNotes
and various other forms of command calling including starting command with "&"
The problematic content can be downloaded from (element body
):
Github API call
tl;dr
Call via cmd /c
with an expandable (interpolating) string ("..."
), which gives you full control over the quoting in the arguments ultimately placed on the target process command line.
-p
is enclosed in "..."
.Additionally, embedded "
chars. in your variable value must be escaped as \"
-replace '(?<!\\)(\\*)"', '\$1$1"'
in the code below does that robustly; that is, it doubles any preexisting \
characters that immediately precede an embedded "
# NOTE:
# In v7.3+, make sure that $PSNativeCommandArgumentPassing is at
# its default, 'Windows' (or set to 'Legacy')
cmd /c @"
dotnet pack --configuration Release -p:PackageReleaseNotes="$($releaseNotes -replace '(?<!\\)(\\*)"', '\$1$1"')"
"@
Note: To simplify embedded quoting, an expandable here-string (@"<newline>...<newline>"@
) is used.
There are two potential problems:
One problem - ultimately a moot point in the case at hand - is that in Windows PowerShell and PowerShell (Core) 7+ up to v7.2.x you must manually \
-escape embedded "
characters in arguments passed to external programs.
This long-standing problem is fixed in v7.3+, but with selective exceptions on Windows - see this answer for details.
These exceptions and the fact that the old, broken way of argument-passing applies to them are highly problematic; another problematic aspect is that the list of exceptions may grow over time, sowing confusion over which programs are affected.
msbuild.exe
be placed on the exception list, due to its specific partial-quoting requirements for property-defining arguments; in fact, it is msbuild.exe
that dotnet pack
passes its -p:
(/p:
) arguments through to, so dotnet.exe
itself may be another candidate - illustrating the risk of an eternal game of catch-up.The other problem is likely that dotnet
and /or msbuild.exe
require very specific, partial quoting on the process command line (as also discussed in the linked GitHub issue).
PowerShell, when it - of necessity - re-quotes arguments when it builds the process command line behind the scenes, does not preserve partial quoting as originally specified; e.g. -p:Foo='bar baz'
turns into "-p:Foo=bar baz"
, i.e. it is double-quoted as a whole (and if the argument didn't contain spaces, it wouldn't use quoting at all).
The solution at the top avoids this problem by calling via cmd /c
, which offers direct control over quoting.