Create Post Body with Parameter and List in Powershell - rest

I'm attempting to use a REST API where I can add a list of items via a POST. However, I cannot seem to get the format of the body correct. The documentation says it's looking for a parameter called "data" that's type is body and the data type is an array. The sample provided for data, shows ["String","String","String"] I've asked for help on the vendors forums, but few users seem to use PowerShell.
I receive the following error:
"Invoke-RestMethod : {"message":"Request body must be populated for body parameter \"data\"","details":{},"description":"","code":10,"http_response":{"message":"The request was well-formed but was unable to be followed due to semantic errors","code":422}}"
I've tried many different formats for the body, but none seem to take. Here's an example of what I've been attempting:
$apiKey = "XXXXXXXXXXXXXXXXXXXXXX"
$url = "https://X.X.com"
$URI = "https://X.X.com/api/reference_data/sets/bulk_load/APITest"
Invoke-RestMethod -Method Post -Uri $URI -Body (convertto-json $body) -Header #{"SEC"= $apiKey }
$body = #{"10.10.1.5","10.10.1.5","50.50.50.50","123.45.6.7"}
I've also tried something like:
$body = #{"data"="body";"value"="10.10.1.5","50.50.50.50","123.45.6.7"} | convertto-json
But then I get this error:
Invoke-RestMethod : {"message":"beginObject() Expecting JSON Array, not a JSON Start of an Object","details":{},"description":"An error occurred parsing the JSON formatted message
body","code":1001,"http_response":{"message":"Invalid syntax for this request was provided","code":400}}
At Z:\Tools\Scripts\PowerShell\RefSetPostExample.ps1:24 char:1
+ Invoke-RestMethod -Method Post -Uri $URI -Body $body -contenttype "ap ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Thanks in advance for any advice on this.

Thanks to #4c74356b41 's practical advice I found:
http://wahlnetwork.com/2016/02/18/using-powershell-arrays-and-hashtables-with-json-formatting/
The answer was to do this:
$body = #("10.10.50.50","10.50.1.5")| convertto-json
Thank you!

Related

powershell invoke rest api toward AWX

I'm struggling for last week or more with sending rest api command from powershell to add host in AWX(from curl is working). When I sent one parameter is worki but I need to send also variables
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $VfAwxTokenX")
$Headers.Add('Content-Type', 'application/json')
$body = #{
name = '$vmname'
variables = 'test'
}| ConvertTo-Json
write-output $body
$response = Invoke-RestMethod 'https://awx/api/v2/inventories/2/hosts/' -Method 'POST' -Headers $headers -UseBasicParsing -Body $body
and error what i get:
{
"name": "wewewe",
"variables": "test" } Invoke-RestMethod : {"variables":["Cannot parse as JSON (error: Expecting value: line 1 column 1 (char 0)) or
YAML (error: Input type str is not a dictionary)."]} At line:32
char:13
$response = Invoke-RestMethod 'https://awx/api ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebException
FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Maybe any one of users had that issue and now how to overcome it?
According to my research, the parameter variables should be defined as JSON or YAML format. For more details, please refer to here.
For more details about how to call the API, please refer to the blog.
the problem was prosaic
variables = 'test'
if i put anything else then test is working :/

Invoke-WebRequest / Invoke-RestMethod failed with error underlying connection closed

I have an existing REST API that accept x-www-form-urlencoded. The API need parameter apikey, and tested successfully in Postman as shown below.
However I need to invoke this API using Powershell.Below is my code :
$params = #{"apikey"="abcd1234"}
Invoke-WebRequest -Uri http://localhost:3030/api/v1/usergroupsync -Method POST -Body $params
#also tried below, no avail.
Invoke-RestMethod -Uri http://localhost:3030/api/v1/usergroupsync -Method POST -Body $params
However I encountered this error :
Invoke-WebRequest : The underlying connection was closed: An unexpected error occured on a receive At line:14 char:1
+ Invoke-WebRequest -Uri http://localhost:3030/api/v1/usergroupsync -Method POST -...
+==============================================================================
+ CategoryInfo : InvalidOperations: (System.Net.HttpWebRequest:HTTTpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebcmdletWebResponseException,Microsoft.Powershell.Commands.InvokeWebRequest
If I remove -Body, there is no error, and Response was as expected "API Key is not valid" which means my REST API validate correctly.
So I suspect the reason if my issue is on the body? Any idea on how to solve this issue?
PS Version is 4.0.0
PS C:\> $PSVersionTable.PSVersion
Major Minor Build Revision
----- ----- ----- --------
4 0 -1 -1
You should use the -Header switch to pass your parameters. Though Invoke-WebRequest support header, I recommend using Invoke-RestMethod as it also return the Headers.
Try something like,
Invoke-RestMethod -Method Post -Uri http://localhost:3030/api/v1/usergroupsync -Body (ConvertTo-Json $body) -Header #{"apikey"=$apiKey}
Check this and this for more information

Can't find expected json body in System.Net.WebException

I'm working with an API via PowerShell that returns human-readable errors as a json object in the response body when an error occurs. However, when I attempt to find that json body in an exception, I can see the error, the underlying System.Net.WebException and the further underlying System.Net.HttpWebResponse, but nowhere can I find the actual body they're referring to. Is this something that is accessible?
For example, here is a valid API call that would work:
Invoke-RestMethod -Method Get -Headers #{Authorization="Token token=$YourTokenHere";"Content-type"="application/json"} -Uri "https://mydomain.pagerduty.com/api/v1/users/ABCDEF" -Body #{offset=0;limit=100}
If you then change the user ID at the end of the URI, it fails and you get this error:
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:1 char:1
+ Invoke-RestMethod -Method Get -Headers #{Authorization="Token token=b ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I can dive down in to the error to see the underlying error and the response if I do the following and convert to json for easy viewing of subproperties:
$Error[0].Exception.Response | ConvertTo-Json
But no matter how I comb through these errors, I can't seem to find the json body. Where might it be, or how can I capture it? I seem to have the same result if I do a try/catch.
You could read the responsestream so you can get the body of the response. Ex:
try {
Invoke-RestMethod -Method Get -Headers #{Authorization="Token token=$YourTokenHere";"Content-type"="application/json"} -Uri "https://mydomain.pagerduty.com/api/v1/users/ABCDEF" -Body #{offset=0;limit=100}
} catch {
$stream = New-Object System.IO.StreamReader $_.Exception.Response.GetResponseStream()
$json = $stream.ReadToEnd()
$stream.Dispose()
$json
}
Output:
{"error":{"message":"Account Not Found","code":2007}}

How can I update an entity via OData service using PowerShell?

I'm trying to work out how to do OData updates using PowerShell as the client. I found the site services.odata.org to use for testing: http://services.odata.org/OData/OData.svc/$metadata.
I've tried this:
Invoke-RestMethod -Method Put -ContentType 'application/json' `
-Uri 'http://services.odata.org/V3/(S(k22mmq0ajlv45epd2psyysnd))/OData/OData.svc/Products(0)' `
-Body ( #{ Description = 'CheesyPeas' } | ConvertTo-Json )
but I get back
Invoke-RestMethod : <?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">
Error processing request stream. Type information must be specified for types that take part in inheritance.
</m:message>
</m:error>
At line:1 char:1
+ Invoke-RestMethod -Uri 'http://services.odata.org/V3/(S(k22mmq0ajlv45epd2psyysnd ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I think this has something to do with the Navigation Properties. Ideally, I'd be testing against a simple entity with no Navigation Properties until I've got a basic PUT working but I can't find one. Can anyone help me get this working?
As the error said, you need to specify the type you send in the body.
Write your code like below:
Invoke-RestMethod -Method Put -ContentType 'application/json' `
-Uri 'http://services.odata.org/V3/(S(k22mmq0ajlv45epd2psyysnd))/OData/OData.svc/Products(0)' `
-Body ( #{ "odata.type" = 'ODataDemo.Product'; Description = 'CheesyPeas' } | ConvertTo-Json )

Running PowerShell code in powershell works, executing as .ps1 doesn't

I wrote some code which tries to Get a value from one Rest API and post it to another.
I have the code saves in a .ps1 file. If I edit it and run it (or just copy and paste it into an empty PowerShell terminal) it does what I expect. However when I try to run the same .ps1 file directly I get an error on the 2nd Invoke-RestMethod.
Don't understand why I'm getting a different result and the error message not giving me many clues.
What am I doing wrong?
The code I am using is (with modified API key):
$encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($APIkey+":"))
$headers = #{"Content-Type" = "application/json"; "AUTHORIZATION" = "Basic $encoded"}
$APIkey = "123456789"
$metricId = "123"
$r = Invoke-RestMethod -Uri https://coinbase.com/api/v1/currencies/exchange_rates
$metric = [PSCustomObject]#{
value = [Math]::Round($r.btc_to_eur, 2)
}
$baseuri = "https://api.numerousapp.com/v1/metrics/$metricId/events"
$data = ConvertTo-Json $metric
Invoke-RestMethod -Uri $baseuri -Body $data -Headers $headers -Method Post
And the error message I get when running the .ps1 file is:
Invoke-RestMethod : :
At C:\NumerousBitcoinEur.ps1:13 char:1
+ Invoke-RestMethod -Uri $baseuri -Body $data -Headers $headers -Method Post
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I'm using PowerShell 4.0
$APIkey is being set after it is being used, which must be wrong. It probably works in the console because $APIkey happens to already be set.
If you like (I think it's a good idea), you can add the following to the top of your scripts to catch errors like this one.
Set-StrictMode -Version Latest