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?
tl;dr
Your primary problem is the use of a verbatim string (single-quoted, i.e. '...'
), inside of which variable references such as $Firstname
are not interpolated.
You need an expandable (interpolating), string (double-quoted, i.e. "..."
) instead, in which any embedded "
characters must then also be escaped for PowerShell's sake (either as `"
or ""
); however, this additional escaping need can be avoided with the use of the here-string expandable string variant (@"<newline>...<newline>"@
), as shown below.
See the bottom section for a better, hashtable-based alternative solution.
Therefore, 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 (expandable) 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.
You're clearly aware of the - unfortunate - additional need to \
-escape the "
instances - update: no longer needed in PowerShell (Core) 7 v7.3+; see this answer - but just to explain why that is needed:
When passing arguments to an external program, PowerShell, after its own parsing and interpolation, wraps those resulting arguments that contain spaces in double quotes ("..."
) when concatenating them to form the process command line to launch the external utility with. Unfortunately, it does so without escaping any embedded "
characters, which in effect results in their getting discarded; the only way to preserve them 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\`"}}"
Alternative:
Ryan himself points out in a comment that using a hashtable is the better alternative for constructing 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