4

I need to HttpPost a Json-body to a ASP.NET Core Web Api endpoint (controller) using a PowerShell script.

$CurrentWindowsIdentity = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$CurrentPrincipalName = $CurrentWindowsIdentity.Identity.Name

# Build JSON payload
$JsonString = @"
{
    "CurrentPrincipalName":"$CurrentPrincipalName"
}
"@

$response = Invoke-RestMethod -Uri "https://webapiendpoint.tld/api/somecontroller" -Method Post -Body $JsonString -ContentType "application/json"

Since the value of the variable $CurrentPrincipalName can be domain\username, the json get's invalid because of the backslash, which is not properly escaped.

Error in the log of the web api:

  JSON input formatter threw an exception: 'C' is an invalid escapable character within a JSON string. The string should be correctly escaped. Path: $.CurrentPrincipalName | LineNumber: 15 | BytePositionInLine: 36.
  System.Text.Json.JsonException: 'C' is an invalid escapable character within a JSON string. The string should be correctly escaped. Path: $.CurrentPrincipalName

How can i make sure that when creating a json string and adding variables - whose values of course can not be controlled - the json string gets properly escaped?

i also tried ConvertTo-Json like:

$JsonConverted = $JsonString | ConvertTo-Json

and then HttpPost that object, but that was even worse:

JSON input formatter threw an exception: The JSON value could not be converted to solutionname.model. Path: $ | LineNumber: 0 | BytePositionInLine: 758.
Christian Casutt
  • 2,334
  • 4
  • 29
  • 38
  • As an aside re `$JsonString | ConvertTo-Json`: `ConvertTo-Json` is designed to convert _from_ hash tables or (custom) objects _to_ JSON; if you pass it something that already is a JSON string, you'll get a single JSON _string value_ (enclosed in literal double quotes), and the input object structure is lost. Try `'{ "foo": 1 }' | ConvertTo-Json` – mklement0 May 03 '20 at 09:08

1 Answers1

10

The robust way to create JSON text is to construct your data as a hash table (@{ ... }) or custom object ( [pscustomobject] @{ ... }) first and pipe to ConvertTo-Json:

$JsonString = @{
  CurrentPrincipalName = $CurrentPrincipalName
} | ConvertTo-Json

That way, PowerShell performs any necessary escaping of values for you, notably including doubling the literal \ character in your $CurrentPrincipalName value to ensure that it is treated as a literal.

Note:

  • Depending on how deeply nested the hashtable is, you may have to add a -Depth argument to the ConvertTo-Json call to prevent more data from getting truncated - see this post for more information.

  • If you have multiple properties and want to preserve their definition order in the JSON representation, use an ordered hash table ([ordered] @{ ... }) or a custom object.

  • In cases where the resulting JSON string is to be passed to an external program, in Windows PowerShell and in PowerShell (Core) up to v7.2.x you unfortunately have to \-escape all " characters - see this answer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Agree. Well, partially, just hit another issue: $CurrentPrincipalIsAdmin = $CurrentWindowsIdentity.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) needs to be $CurrentPrincipalIsAdmin = $CurrentWindowsIdentity.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator).ToString() otherwise : this: $JsonString = @{ CurrentPrincipalIsAdmin = $CurrentPrincipalIsAdmin } | ConvertTo-Json leads to System.InvalidOperationException: Cannot get the value of a token type 'True' as a string. But this is out of scope here, would have to create a new question i think – Christian Casutt May 03 '20 at 09:19
  • @ChristianCasutt That's a curious error, which I would not expect - Booleans are definitely supported. If you have a reproducible case, please do post a new question, with details about your particular PowerShell version. – mklement0 May 03 '20 at 09:28
  • Try: ConvertTo-Json -Depth 1024 – Kenneth Benjamin Mar 17 '21 at 14:07