4

I am currently trying to automate new user creation in our Zendesk ticketing system using Powershell and Curl. The problem I am running into is that the curl json body is enclosed by single quotes and I need to reference a variable inside that body. Here is what I have:

$Firstname = "Test"
$Lastname = "User"
$email= 'user@test.org'   
curl.exe https://mydomain.zendesk.com/api/v2/users.json -H "Content-Type: application/json" -X POST -d '{\"user\": {\"name\": \"$Firstname $Lastname\", \"email\": \"$email\"}}' -v -u myuser:mypass

This works fine if I type in regular text values inside the json, but how can I get it to recognize the variables $Firstname, $Lastname and $email?

Ryan Arnold
  • 67
  • 1
  • 2
  • 6

2 Answers2

11

Try the following:

$Firstname = "Test"
$Lastname = "User"
$email= 'user@test.org'   
$json=@"
{\"user\": {\"name\": \"$Firstname $Lastname\", \"email\": \"$email\"}}
"@
curl.exe https://mydomain.zendesk.com/api/v2/users.json -d $json -H 'Content-Type: application/json' -X POST -v -u myuser:mypass

Using a double-quoted here-string @"<newline>...<newline>"@ makes specifying embedded " instances easy (no escaping for the sake of PowerShell's own syntax required), while still expanding variable references - see the docs online or Get-Help about_Quoting_Rules.

You're clearly aware of the - unfortunate - additional need to \-escape the " instances, but just to explain why that is needed:

When passing arguments to an external program, PowerShell, after its own parsing and interpolation, conditionally wraps the resulting arguments in double quotes when concatenating them to form the argument list (a single string) to pass to the external utility. Unfortunately, this can result in embedded " instances getting discarded, and the only way to preserve them reliably is to \-escape them - see this answer for more information.

If you wanted to do it inline with a regular double-quoted string, you'd have to escape the " instances for PowerShell too (as `"), resulting in the awkward combination \`":

"{\`"user\`": {\`"name\`": \`"$Firstname $Lastname\`", \`"email\`": \`"$email\`"}}"

Afterthought:

Ryan himself points out in a comment that using a hashtable to construct the data and then converting it to JSON with ConvertTo-Json and feeding it to curl via stdin is an alternative that avoids the quoting headaches:

# Create data as PS hashtable literal.
$data = @{ user = @{ name = "$Firstname $Lastname"; email = "$adUsername@mydomain.org" } }

# Convert to JSON with ConvertTo-Json and pipe to `curl` via *stdin* (-d '@-')
$data | ConvertTo-Json -Compress | curl.exe mydomain.zendesk.com/api/v2/users.json -d '@-' -H "Content-Type: application/json" -X POST -v -u myuser:mypass
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I have the inline version `$body_j="{\`"user\`":\`"ti\`",\`"pass\`":\`"passw\`"}"`, then `Invoke-WebRequest -Uri http://localhost:5000/login -Method Post -Body $body_j -ContentType 'application/json'` and get `Invoke-WebRequest : SyntaxError: Unexpected token \ in JSON at position 1` – Timo Mar 27 '21 at 10:30
  • @Timo, I don't see any `\ ` in your command, so I don't have an explanation, but note that this question is about `curl.exe`, not `Invoke-WebRequest` and that comments aren't the right place for troubleshooting, so I encourage you to ask a _new question_. – mklement0 Mar 27 '21 at 13:09
1

I think we can use here-string as json body for Invoke-RestMethod as below

$bufferTime = 5
$requestBody = @"
{
"size": 0,
    "aggs": {
    "last_x_min": {
        "filter": {
        "range": {
            "@timestamp": {
            "gte": "now-$($bufferTime)m",
            "lte": "now"
            }
        }
        },
        "aggs": {
        "value_agg": {
            "avg": {
            "field": "time-taken"
            }
        }
        }
    }
    }
}
"@

$esResponse = Invoke-RestMethod -URI http://locahost:9200 -TimeoutSec 15 -Method Post -ContentType 'application/json' -Body $requestBody

This is the script I use to query Elasticsearch. No need to escape double quotes.

Anh Le
  • 19
  • 3
  • This works without `\ `-escaping the embedded `"` instances, because you're calling a _cmdlet_ (a PowerShell-native command, `Invoke-RestMethod`) rather than an _external utility_ (such as `curl` in the OP's case). While I wish that these two invocation scenarios didn't require different quoting, they unfortunately do. – mklement0 Oct 11 '17 at 13:25