1

I'm trying to send a post request using az rest. When I try send request like this - it works:

az rest --method POST --uri "https://someaddress" --body '{"some": "Text" }'

but If I put ')' - closing parenthesis in body like this:

az rest --method POST --uri "https://someaddress" --body '{"some": "Text)" }'

then my rest body is cut off and I receive an error:

az : " }" was unexpected at this time.
At line:2 char:1
+ az rest --method POST --uri "https://someaddress" --body '{"some": "T ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (" }" was unexpected at this time.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

How can I escape the ')' character?

santal
  • 55
  • 5
  • 1
    They code you've posted is clearly not the code you're running. Where did `$body` come from? – Mathias R. Jessen Mar 23 '23 at 12:28
  • You can use ```--body @x.json``` and x.json contains json string – RithwikBojja Mar 23 '23 at 12:31
  • 1
    Are the curly bracket inside the single quotes or outside the single quotes in the PS script? I think the curly brackets need to be place outside the single quotes. – jdweng Mar 23 '23 at 13:41
  • @MathiasR.Jessen I've just fixed error message in my post – santal Mar 23 '23 at 13:59
  • @jdweng, it is a _JSON string_ that is to be passed, so `{` and `}` should definitely _not_ go outside the single quotes. If you did that - `{'"some": "Text" '}` - you'd create a _script block_, which - due to invoking an _external program_ - gets _stringified_, in the process of which `{` and `}` are _lost_. (However, up to at least PowerShell 7.3.3 there's actually a _bug_ with respect to passing script blocks to external programs, which produces a different symptom - see [GitHub issue #10842](https://github.com/PowerShell/PowerShell/issues/10842)). – mklement0 Mar 23 '23 at 15:16
  • @mklement0 : This time I'm right. See answer. – jdweng Mar 23 '23 at 15:33
  • @jdweng, the solution in santal's answer - despite mistakenly crediting you - is very different from what your original comment states. – mklement0 Mar 23 '23 at 15:47
  • 1
    @mklement0 That's true. I misunderstood jdweng, but his answer gave me a hint how to solve it. Anyway - replacing double quotes with single quotes works. – santal Mar 23 '23 at 16:22

2 Answers2

2

Let me complement your own answer with some background information:

  • '{ "some": "Text)" }' is a valid JSON string (verify with {"some": "Text)" } | ConvertFrom-Json) and therefore should work.

  • However, due to a long-standing bug in how PowerShell passes arguments with embedded " chars. to external programs (such as the az CLI), " must manually be escaped - typically as \", but in this case as "".

    • As a result of the bug, embedded " chars. are in effect removed:

      • '{ "some": "Text)" }' becomes "{ "some": "Text)" }" behind the scenes, which most CLIs, including az, parse as verbatim { some: Text) }, because - due to lack of escaping of the embedded " - all " instances are considered to have syntactic function and are therefore removed.

      • See this answer for details.

    • You can use az --debug to echo how az parses its arguments, which demonstrates the problem:

       # Note the effective loss of the " chars. in the output.
       PS> az --debug '{ "foo": "bar" }' 2>&1  | Select-String 'command arguments'
      
       DEBUG: cli.knack.cli: Command arguments: ['--debug', '{ foo: bar }']
      
  • In fact, there's a dedicated Quoting issues with PowerShell article that az rest Azure docs link to that discusses the problems, which not only affect embedded " chars. but also (space-less) URLs that contain & (e.g. https://example.org?foo&bar).

  • The problem with & is owed to the fact that az is implemented as a batch file - az.cmd. It also the reason "" rather than \" must be used for manual escaping (\" being the most widely used syntax for escaping, with only Windows-heritage CLIs also / exclusively supporting ""), because cmd.exe (the batch-file interpreter) recognizes only "" as an escaped ", so that an argument on its process command line such as "{ \"some\": \"Text)\" }" breaks an az.cmd call, because the ) is seen as unquoted, i.e. as having syntactic function, which cause a syntax error. By contrast, "{ ""some"": ""Text)"" }" works.


Therefore you have two options:

  • Perform the required manual escaping - note the "":

    # Direct:
    az rest --method POST --uri "https://someaddress" --body '{ ""some"": ""Text)"" }'
    
    # Indirect, using string replacement:
    az rest --method POST --uri "https://someaddress" --body '{ "some": "Text)" }'.Replace('"', '""')
    
  • If your target web service supports it, bypass the problem by switching to '-quoting (single quotes), as also shown in your answer, which isn't affected by the PowerShell bug:

    az rest --method POST --uri "https://someaddress" --body "{ some: 'Text)' }"
    
    • Note that the above is - strictly speaking - not valid JSON, but some JSON parsers also accept JSON-like strings, allowing the property names to be unquoted (some) and allowing use of single-quoting in string property values (and also names, if needed) in lieu of the JSON-standard double-quoting.

      • This seems to be the case for you, and it also true for the Json.NET parser that underlies PowerShell's ConvertFrom-Json as of PowerShell 7.3.3.
        ("{ some: 'Text)' }" | ConvertFrom-Json works, for instance).
        By contrast, it does not work with the .NET-native System.Text.Json APIs ([System.Text.Json.JsonDocument]::Parse("{ some: 'Text)' }") breaks, for instance)
    • The fact that you say '{"some": "Text" }' - with no ) - worked even suggests that your service's JSON parser also accepts string property values with no quoting, given that az saw this arguments as verbatim {some: Text }

      • '{"some": "Text)" }' - with ) - which PowerShell (brokenly) placed as
        "{"some": "Text)" }" on the az process command line - caused the batch file that the az is implemented as - az.cmd - to break, because to cmd.exe (the interpreter of batch files), the ) is then unquoted (outside a "..." string), which means it has syntactic function, ultimately causing the syntax error you saw (… was unexpected at this time).
mklement0
  • 382,024
  • 64
  • 607
  • 775
1

Placing body in single quotes works:

az rest --method POST --uri "https://someaddress" --body "{'some': 'Text)' }"
santal
  • 55
  • 5