How use curl with spaces in json - json

When making a POST call with curl I'm having trouble getting the JSON data to be passed correctly. The string is cut off at the first whitespace/blank space.
My call looks like this, I'm executing through a powershell script that has two parameters. Using these parameters I concatenate the JSON that is used for the call.
I input for instance 854e-ae7686fbc75a 365 as parameters
# usage: powershell -file send.ps1 [apitoken] [interval]
param (
[string]$apitoken = "",
[int]$startInterval = "365"
)
$AUTHORIZATION = $apitoken
$STARTDATE = (Get-Date).AddDays(-$startInterval)
$ENDDATE = (Get-Date)
$JSON = '{\"ApiToken\":\"' + $AUTHORIZATION + '\",' +
'\"StartDate\":\"' + $STARTDATE + '\",' +
'\"EndDate\":\"' + $ENDDATE + '\",' +
'\"Type\":\"SalesExport\"' +
'}'
$CURLEXE = '..\bin\curl.exe'
$CurlArgument = '-X', 'POST',
'-m', 7200,
'-H', '"Content-Type:application/json"',
'-d', $JSON,
'https://my.server/export/sales'
& $CURLEXE #CurlArgument
The STARTDATE would then be the current date minus 365 days. ENDDATE would be the current date.
The problem is as soon as there is a blank space (or possibly any whitespace) in the JSON variable curl thinks that the JSON has ended and says that the JSON is unterminated. There is no difference if I surround the variable with single or double quotes.
Even if the whitespace is inside one of the two DateTime variables the problem occurs!
How can I format the JSON properly so that it can include whitespace?

Not a direct answer to your question, but since you're using PowerShell anyway: why not use the native Invoke-WebRequest instead of an external command?
$today = (Get-Date).Date
$uri = 'https://example.org/export/sales'
$headers = #{
'Content-Type' = 'application/json'
}
$data = #{
'ApiToken' = $apitoken
'StartDate' = $today.AddDays(-$startInterval).ToString('d')
'EndDate' = $today.ToString('d')
'Type' = 'SalesExport'
} | ConvertTo-Json
Invoke-WebRequest -Method Post -Headers $headers -Body $data -Uri $uri
Alternatively you can define the JSON data as a multiline string:
$startDate = $today.AddDays(-$startInterval).ToString('d')
$endDate = $today.ToString('d')
$data = #"
{
"ApiToken": "$apitoken",
"StartDate": "$startDate",
"EndDate": "$endDate",
"Type": "SalesExport"
}
"#

Related

"Unexpected token" or "JSON parse error - trailing comma" when doing API call with PowerShell

I have the following PowerShell API script:
$VMname = "abcd"
$IP_address = '2.2.2.2'
$url = "https://ansibletower.xyz.com/api/v2/job_templates/12321/launch/"
$token = "9998980fsfdfsdfdf"
$headers = #{Authorization = "Bearer $token"}
$contentType = "application/json"
$method = "POST"
#### $body = '{"extra_vars": {"vm_name": "abc", "vm_ip_address": "2.2.2.2"}}'
$body = '{"extra_vars":{"vm_name":'$VMname', "vm_ip_address":'$IP_address'}}'
Invoke-RestMethod -ContentType "$contentType" -Uri $url -Method $method -Headers $headers -Body $body
When I try it with manually predefined values in the body (see the commented body line above) - it works. But when I try it with variables $VMname and $IP_address, I get the error:
Unexpected token '$VMname', "vm_ip_address":'$IP_address'}}''
expression or statement.
And if I remove single quotes before and after variables VMname and IP_address I get:
{"detail":"JSON parse error - Expecting value: line 1
column...Possible cause: trailing comma."}
It is obviously a problem with syntax and / or formatting but I cannot find the solution. Does anyone know?
Use ConvertTo-Json for this:
$VMname = "abcd"
$IP_address = '2.2.2.2'
$body = ConvertTo-Json -Compress -Depth 9 #{
extra_vars = #{
vm_name = $VMname
vm_ip_address = $IP_address
}
}
$Body
{"extra_vars":{"vm_name":"abcd","vm_ip_address":"2.2.2.2"}}
Btw, it is probably not even required to serialize your body to Json as Invoke-Restmethod is supposed to take care of that:
-body
When the input is a POST request and the body is a String, the value to the left of the first equals sign (=) is set as a key in the form data and the remaining text is set as the value. To specify multiple keys, use an IDictionary object, such as a hash table, for the Body.

Powershell script Missingtypename

I am trying to make some API calls through powershell using this documentation
https://octopus.com/blog/manually-push-build-information-to-octopus
$Headers = #{"X-Octopus-ApiKey"=$MYKEY"}
$jsonBody = #{
PackageId = "Test"
Version = "1.1.1"
OctopusBuildInformation =
#{
BuildEnvironment = "Jenkins"
BuildNumber = "1"
BuildURL = "myURL"
VcsCommitNumber = "250"
VcsType = "Git"
Commits = [{Id = "250" LinkUrl = "gitUrl" Comment = "someComment"}]
VcsRoot = "gitUrl"
}
} | ConvertTo-Json -Depth 5
Invoke-RestMethod -Method Post -Uri "http://alfadeployment/api/build-information" -Headers $Headers -Body $jsonBody
However, since I added the commits array, I am getting the following error:
Missing type name after '['.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : MissingTypename
PowerShell arrays aren't enclosed in [...] - the latter is used for type literals, i.e. to refer to .NET types - hence the error message.
You may - but don't have to - enclose PowerShell arrays in #(...), the array-subexpression operator; using ,, the array constructor operator is enough, though #(...) can be helpful for visual clarity, and to create an empty (#()) or single-element arrays (#('foo')), which is perhaps clearer than the unary use of , (, 'foo')).
Additionally, the array element in your case must be a hashtable too (#{ ... }, not { ... }, the latter is a script block), and, given that the property definitions are on the same line, they must be ;-separated.
To put it all together:
Commits = #(
#{ Id = "250"; LinkUrl = "gitUrl"; Comment = "someComment" }
)

Convert cURL to PowerShell Invoke-WebRequest - JSON data table issue

I have the following PowerShell script that uses cURL in Windows 10 and works perfectly:
$Body = #{
'data' = #{
'CID' = 15;
'HID' = 37;
'Type' = "TYPE1";
'downloadOn' = "NEXT_CONTACT";
'AutomationEnabled' = "True";
}
}
$CurlArgument = '-s', '-X', 'PATCH',
'-H', 'Content-Type: application/json',
$URL,
'-H',
$AuthBearer,
'-d',
(($Body | ConvertTo-Json) -replace '"', '\"')
Write-Host "$Section cURL command took" ("{0:n1}" -f (Measure-Command {$UpdateResponse = & $CURLEXE #CurlArgument}).TotalSeconds) "Seconds" -ErrorAction SilentlyContinue
I can't use cURL, I need to use native Invoke-WebRequest on my production servers. I need to convert the above into a Invoke-WebRequest command, which I have done, as follows:
$Body = #{
'data' = #{
'CID' = 15;
'HID' = 37;
'Type' = "TYPE1";
'downloadOn' = "NEXT_CONTACT";
'AutomationEnabled' = "True";
}
}
(($Body | ConvertTo-Json) -replace '"', '\"')
$Method = "PATCH"
$Header = #{"Accept" = "*/*" ; "Cache-Control" = "no-cache" ; "Host" = "myURL"; "accept-encoding" = "gzip,deflate"; "Authorization" = "Bearer $SessionToken" }
$ContentType = "application/json"
Write-Host "$Section Invoke-WebRequest command took" ("{0:n1}" -f (Measure-Command { $UpdateResponse = Invoke-WebRequest -Method $Method -Uri $URL -Header $Header -ContentType $ContentType -Body $Body }).TotalSeconds) "Seconds"
When I run the Invoke-WebRequest, I get the following error, i.e. A JSONObject text must begin with '{':
Invoke-WebRequest : {"status":"FAILURE","errors":...."message":{"5011":"A JSONObject text must begin with '{' at 1 [character 2 line 1]"}}]}
My $Body looks like this i.e. it begins with '{' :
{
\"data\": {
\"downloadOn\": \"NEXT_CONTACT\",
\"HID\": 37,
\"AutomationEnabled\": \"True\",
\"CID\": 15,
\"Type\": \"TYPE1\"
}
}
I tried with and without "-replace '"', '\"'", from this post"
cURL to PowerShell - Double hash table in --data?
Looking at my $Body JSON "object"(?), I can see this:
Name Value
---- -----
data {downloadOn, HID, AutomationEnabled, CID...}
Looking at my Value, I can see it is listed as follows:
Name Value
---- -----
downloadOn NEXT_CONTACT
HID 37
AutomationEnabled True
CID 15
Type TYPE1
Instead of sending -Body $Body,I thought maybe I should just sent the values, as follows (which also failed) with the same message.
-Body $Body.Values
I did a heap of searching last night, but I am at a loss on how to convert that into a successful Invoke-WebRequest, and any help would be appreciated.
You are sending $Body as a Hashtable, try converting it to JSON
$Body = $Body | ConvertTo-Json
If you send $Body before the above line and again after to an echo service you'll see the difference
Invoke-RestMethod -Method 'POST' -Uri 'https://postman-echo.com/post' -ContentType 'application/json' -Body $Body

smartsheet api update rows error 1004. you are not authorized

I am trying to use powershell and the API to update a cell, but I get an error: 1004 You are not authorized to perform this action. I've elided the IDs . . .
I have a 30 day trial. Do I need to buy in to some level of support before I can use the API to do updates or what? The sheet is on my account and I am the owner. Is Write Sheets role not included in Owner?
I am using powershell 5.1 to make the http request – here is my script. It first gets the correct sheet ID, then puts the rows and columns I am interested in into hashes, and then tries to update the sheet, but although I am the owner, I am unauthorized.
# access account of jjj.mmm#ddd.com
$apiKey = "3ccfgk..."
$url = "https://api.smartsheet.com/2.0/sheets/"
$get_headers = #{"Authorization" = "Bearer " + $apiKey}
$put_headers = #{"Authorization" = "Bearer " + $apiKey, "Content-Type: application/json" }
# get all the sheets
$response = Invoke-RestMethod -Uri $url -Headers $get_headers
$rd = $response.data
$json = ConvertTo-Json $rd
# find the Forecast sheet
$sheet_id = $rd | Where {$_.name -eq "Forecast Intermediary Sheet"} | Select -ExpandProperty id
"Sheet ID: $sheet_id"
#get the Forecast sheet
$surl = "$url$sheet_id"
$surl
$response = Invoke-RestMethod -Uri $surl -Headers $get_headers
$response | Format-List
# iterate over the rows and get the active ones
$active_rows = #{}
foreach ($row in $response.rows) {
if ($row.rowNumber -ge 14) {
if ($row.cells[2].value -Match "Active") {
$active_rows.Add($row.cells[2].value, $row.id)
}
}
}
# get the col_ids by date
$date_cols = #{}
foreach ($c in $response.columns) {
if ($c.title -as [datetime]) {
$d = $c.title -replace "/20", "/"
$ds = [datetime]::parseexact($d, 'mm/dd/yy', $null)
$date_cols.Add($ds.Tostring("yyyy-mm-dd"), $c.id)
}
}
"UPDATE:"
$rowid = $active_rows["SSL PS Active"]
$colid = $date_cols["2017-11-01"]
"row: $rowid, col: $colid"
$json = '[{ "id": "'+$rowid+'", "cells": [{"columnId": "'+$colid+'","value": "23"} }]'
"JSON: $json"
$purl = "$surl/rows"
"PUT URL: $purl"
$r = Invoke-RestMethod -Method "PUT" -uri $purl -Headers $put_headers -Body $json
$r
Below is the output of the script. The error seems to indicate it is syntactically correct, but OWNER is insufficient permissions.
Sheet ID: 5724...
https://api.smartsheet.com/2.0/sheets/5724....
UPDATE:
row: 5668..., col: 5118...
JSON: [{ "id": "5668...", "cells": [{"columnId": "5118...","value": "23"} }]
PUT URL: https://api.smartsheet.com/2.0/sheets/5724.../rows
Invoke-RestMethod : {
"errorCode" : 1004,
"message" : "You are not authorized to perform this action.",
"refId" : "14a7o8lu9sfyj"
}
At \\winfiles\jmoore\powershell\ss_api.ps1:58 char:6
+ $r = Invoke-RestMethod -Method "PUT" -uri $purl -Headers $put_headers ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodComand
Here is the meta data of my sheet
Sheet ID: 5724...
https://api.smartsheet.com/2.0/sheets/5724....
id : 5724...
name : Forecast Intermediary Sheet
version : 2
totalRowCount : 37
accessLevel : OWNER
effectiveAttachmentOptions : {GOOGLE_DRIVE, DROPBOX, ONEDRIVE, EGNYTE...}
ganttEnabled : False
dependenciesEnabled : False
resourceManagementEnabled : False
cellImageUploadEnabled : True
userSettings : #{criticalPathEnabled=False; displaySummaryTasks=True}
permalink : https://app.smartsheet.com/b/home?lx=LCTEj6F0xWNKWWxFUuLH0w
createdAt : 2017-11-22T22:34:51Z
modifiedAt : 2017-11-22T22:34:51Z
columns : {#{id=6985...; index=0; title=Column1; type=TEXT_NUMBER; primary=True;
validation=False; width=64}, #{id=1356...; index=1; title=Column2;
type=PICKLIST; options=System.Object[]; validation=False; width=64},
#{id=5859...; index=2; title=Column3; type=TEXT_NUMBER; validation=False;
....
You should be able to make API calls using an API Access Token that's owned by a trial Smartsheet account, and you can most certainly update a sheet that you own using an API Access Token you own.
I'd suspect that the 1004 error response is being caused by the fact that the contents of $put_headers isn't formatted properly. i.e., Smartsheet isn't able to accurately parse the headers you're attempting to specify in $put_headers in order to identify the Authorization header and read its value. When Smartsheet doesn't see the Authorization header in an inbound API request, it'll respond with the 1004 You are not authorized to perform this action. error response.
To troubleshoot this issue, I'd suggest that you use a tool like Fiddler to examine the outbound "Update Rows" request, paying special attention to what headers are present in the request. Then, if you discover that the Authorization header is absent from the request, you'll need to figure out how to specify multiple request headers in PowerShell, and update your code accordingly re how you're setting the value of $put_headers.
Update (adding PowerShell code):
I'm no PowerShell expert, but you might try replacing this line:
$put_headers = #{"Authorization" = "Bearer " + $apiKey, "Content-Type: application/json"}
With these lines instead:
$put_headers = #{}
$put_headers.Add("Authorization", "Bearer " + $apiKey)
$put_headers.Add("Content-Type", "application/json")
Thanks #kim-brandl
Or if you want to build the headers in a single command, you need to use syntax like this:
$put_headers = #{"Authorization" = "Bearer " + $apiKey; "Content-Type" = "application/json" }
Note also that your json payload has a few problems including:
Unmatched brackets
Extra square brackets on the outside (the body is an object, not an array)
Column and row ids must be numbers, not strings
I suggest you test the payload in a tool like postman first.

Get location (lat/long) from googlemap with address - Using powershell

I would like to create a script that allow myself to get the coordinates of some locations on Google map using their addresses.
To do this I use powershell code:
clear-host
$address = "Place+de+la+concorde"
$city = "Paris"
$cp = "75000"
$country = "France"
$url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + $address + "+" + $city + "+" + $cp + "+" + $country
$result = Invoke-WebRequest -Uri $url
Write-Host = $result
Unfortunately I can not retrieve rows interesting to me, ie:
results> geometry> location> lat
and
results> geometry> location> lng
Any idea for getting a specific line information, considering that the number of lines could change ?
Thank you !
ConvertFrom-JSON is the cmdlet you need.
$json = Invoke-WebRequest $url | ConvertFrom-JSON
$json.results.geometry.location.lat
$json.results.geometry.location.lng
Now you are looking at a JSON object (as intended) rather than lines so you won't have to worry about line position, etc.