6

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.
1
  • 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 Commented May 3, 2020 at 9:08

1 Answer 1

15

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.

Sign up to request clarification or add additional context in comments.

3 Comments

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
@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.
Try: ConvertTo-Json -Depth 1024

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.