Skip to content
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

In pwsh 7.3.0 the call operator escapes embedded quotes. #18756

Closed
5 tasks done
skyguy94 opened this issue Dec 9, 2022 · 6 comments
Closed
5 tasks done

In pwsh 7.3.0 the call operator escapes embedded quotes. #18756

skyguy94 opened this issue Dec 9, 2022 · 6 comments

Comments

@skyguy94
Copy link

skyguy94 commented Dec 9, 2022

Prerequisites

Steps to reproduce

After upgrading to 7.3.0 from 7.2.7 I noticed that the string passed in via the call operator retrieved from Environment.CommandLine has escaped embedded quotes that were not part of the original string. This is only in 7.3.0 as pwsh 7.2.7 and earlier and powershell 5.1 do not do this. I came across the problem with a custom tool (that uses libstandard2.0 and .net 4.8 for the libraries and exe respectively) that takes in json like this:

$json = ConvertTo-Json @{
  'Argument1'                = $Argument2
  'Argument2'                = $Argument1
  ...
}

& $tool -AsJson $json

where $json normally contains:

{
  "Argument1": "SomeValue",
  "Argument2": "SomeOtherValue"
  ...
}

but when I output the contents of Environment.CommandLine from the tool with 7.3.0 it looks like this:

{
  \\"Argument1\\": \\"SomeValue\\",
  \\"Argument2\\": \\"SomeOtherValue\\"
  ...
}

If I use Start-Process instead of the call operator then the string is left alone:

Start-Process $tool.Path -ArgumentList "-AsJson $json" -NoNewWindow

I came across this issue #18660 which mentions After the breaking change in native command execution but I could not find details on that breaking change or its impact in the release notes: https://learn.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-73?view=powershell-7.3

Expected behavior

The string should be unmodified:

{
  "Argument1": "SomeValue",
  "Argument2": "SomeOtherValue"
  ...
}

Actual behavior

The string is escaped:

{
  \\"Argument1\\": \\"SomeValue\\",
  \\"Argument2\\": \\"SomeOtherValue\\"
  ...
}

Error details

No response

Environment data

Name                           Value
----                           -----
PSVersion                      7.3.0
PSEdition                      Core
GitCommitId                    7.3.0
OS                             Microsoft Windows 10.0.22621
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

@skyguy94 skyguy94 added the Needs-Triage The issue is new and needs to be triaged by a work group. label Dec 9, 2022
@237dmitry
Copy link

237dmitry commented Dec 9, 2022

$json = ConvertTo-Json @{ item1 = 'abc'; item2 = 'def' }
& bash -c "echo '$json'"

# $PSNativeCommandArgumentPassing = 'Standard' or 'Windows'
{
  "item1": "abc",
  "item2": "def"
}

# $PSNativeCommandArgumentPassing = 'Legacy'
{
  item1: abc,
  item2: def
}

@skyguy94
Copy link
Author

skyguy94 commented Dec 9, 2022

There isn't a description or explanation in your post and I don't see embedded quotes or similar escaping problems in the sample so its rather different than what I posted about. However, the inclusion of the $PSNativeCommandArgumentPassing preference variable is helpful. I found docs for it here: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.3#psnativecommandargumentpassing

Legacy mode seems to be what works in my case but there's nothing in that above link that describes what happens or what the modes do. I don't have an opinion on this feature but it doesn't feel like a minor (7.2.7->7.3.0) change to me. I do think that this change should be called out better in the release notes as a breaking change given how often and important it is to pass arguments to various tools and utilities that will likely be affected by this behavior.

Variables that customize the behavior of PowerShell.

@237dmitry
Copy link

There isn't a description or explanation

I do not know what I could explain. About experimental variable? Its behavior in different cases is not fully understood. I only showed examples. Similar one:

> $PSNativeCommandArgumentPassing = 'Legacy'

> & /usr/bin/echo $json | jq '.' 
parse error: Invalid numeric literal at line 2, column 8     # error. Parser does not know where property name and where value

> $PSNativeCommandArgumentPassing = 'Standard'

> & /usr/bin/echo $json | jq '.' 
{
  "item2": "def",
  "item1": "abc"
}

Legacy mode loses quotes, it is possible that they were not escaped or vice versa, and /usr/bin/jq (json parser) return error.

@mklement0
Copy link
Contributor

@skyguy94, start reading here for an explanation and see #18694, which suggests that the breaking change will be reverted in the sense that it will be opt-in in the future.

@skyguy94
Copy link
Author

skyguy94 commented Dec 9, 2022

Closing as this seems well issued and discussed. Thanks for the help everyone.

@skyguy94 skyguy94 closed this as completed Dec 9, 2022
@ghost ghost removed the Needs-Triage The issue is new and needs to be triaged by a work group. label Dec 9, 2022
@237dmitry
Copy link

237dmitry commented Dec 9, 2022

The question. Why quotes are escaped in a argument of json format? Maybe in other formats where quotes are the element of syntax?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants