Convert Curl to Invoke-RestMethod - json

Problem
I am having a hard time converting a curl call into a Powershell Invoke-RestMethod call as Powershell doesn't really thow the most informative error messages (if any).
Curl call (Ubuntu)
token = "djsakldsakldjaslda"
host = "https://lalala.azuredatabricks.net/"
curl -X POST -H "Authorization: Bearer $(token)" $(host)/api/2.0/clusters/create -d $(cat my_file.json)
Invoke-RestMethod call (Powershell)
$token= "djsakldsakldjaslda"
$host = "https://lalala.azuredatabricks.net/"
Invoke-RestMethod -Method Post -Uri $host/api/2.0/clusters/create -Headers #{"Authorization" = "Bearer " + $token} -Body $(get-content my_file.json -raw | ConvertFrom-Json)
I have various formats for the body, but no matter what I send, I just get some HTML back for a login page. On Ubuntu with Curl everything works perfectly.
NOTE:
The problem seemed to be that PowerShell cannot handle double-"/" as in "https://lalala.azuredatabricks.net//api/2.0/clusters/create".
The strange part is that Invoke-RestMethod gets to the login page, but fails from there.

Use -InFile to upload a file. Don't forget to set the content type.
Wrapped for legibility (escaping the EOL works as line continuation in PowerShell, it looks funny because StackOverflow syntax highlighting cannot handle it):
Invoke-RestMethod `
-Method Post `
-Uri "$host/api/2.0/clusters/create"
-Headers #{
Authorization = "Bearer $token"
} `
-Infile my_file.json
-ContentType "application/json"

The body is expected to be JSON format, when you take the file and add the | ConvertFrom-Json the content becomes a PowerShell object.
So, you can remove the | ConvertFrom-Json and it should work :)

Related

Powershell/PowerCLI, Horizon REST-API, invoke-restmethod returns "BAD_REQUEST The input request cannot be parsed"

I'm trying to copy Horizon application pools that exist on a source Horizon connection server (HCS) to another one. In my homelab that works perfectly, in another environment on "invoke-restmethod" I run into the error above.
First I get an auth token and the applications on the source HCS:
$horizonApps_source = Invoke-RestMethod -Method Get -uri "$RESTurl_source/rest/inventory/v2/application-pools" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken_source)`
Then I loop through them and create the copies on the target HCS (also exporting a .json-File for every app and removing unique values that the POST "inventory/v2/application-pools" will not accept):
If ($horizonApps_source -ne $null) {
ForEach ($item in $horizonApps_source) {
$jsonFile = $fileLoc + $item.Display_Name + ".json"
$item = $item | Select-Object * -ExcludeProperty Id, access_group_id, icon_ids, customized_icon_ids
$item.farm_id = $farmID_target
$item | ConvertTo-Json -Depth 100 | Out-File $jsonFile
$appJson = $item | ConvertTo-Json -Depth 100
$app_target = Invoke-RestMethod -Method Post -uri "$RESTurl_target/rest/inventory/v2/application-pools" -ContentType "application/json" -Headers (Get-HRHeader -accessToken $accessToken_target) -body $appJson -SkipCertificateCheck
}
}
In one environment everything works, in another no chance...this is the error I get, .json-files are written and look okay, but no apps are created on the target HCS:
Line |
8 | … pp_target = Invoke-RestMethod -Method Post -uri "$RESTurl_target/rest …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| {"status":"BAD_REQUEST","timestamp":1670869477302,"error_message":"The input request cannot be parsed."}
Powershell 7.3.0, PowerCLI 13, Horizon 2111 everywhere. Any ideas? Any suggestion how I could catch the error in more detail to find the issue's source?
Tried to google problems with invoke-restmethod using a json-body. Sadly I'm not a Powershell pro...
Solved with help of a great colleague!
In my test enwironment I used two Horizon installations on Windows Server 2022 in an ENGLISH install. The other environment uses a source Horizon installation on a GERMAN server OS, but the target Horizon connection server runs on an ENGLISH OS. on the German based source install the admins made use of German special characters "äÄöÖüÜ".
In result the character set hast to be fixed to UTF-8 for the REST invocation:
$app_target = Invoke-RestMethod -Method Post -uri "$RESTurl_target/rest/inventory/v2/application-pools" -ContentType "application/json; charset=utf-8" -Headers (Get-HRHeader -accessToken $accessToken_target) -body $appJson
The part "application/json" has to become "application/json; charset=utf-8".
And that's it.

SurveyMonkey creating a collector in Powershell returning "The body provided was not a proper JSON string

I'm using Powershell to automate a survey creation, adding a collector, and sending the survey invitation - a pretty common use case. I was able to create a survey but I'm running into an issue in creating the collector. I created a collector via Postman but I get the error "1001 - The body provided was not a property JSON string" when using Powershell. I've tried everything I can think of but continue to get the error no matter how I create the JSON. Here is the code I'm using:
$SurveyCollector = [PSCustomObject]#{ type = 'email' }
$BodyText = $SurveyCollector | Select-Object -Property type |ConvertTo-Json -Depth 100 -Compress
$Results = Invoke-RestMethod -Uri $uri -StatusCodeVariable "ExtIDscv" -SkipHttpErrorChe -Method
Post -ContentType "application/json" -Authentication Bearer -Token $SecureToken -body -$BodyText
I'm sure I'm missing something simple. I'd appreciate any help.
The answer was more simple than what tripleee suggested. I had introduced a -$BodyText into the call and didn't catch it. I removed it and it works just fine.
$Results = Invoke-RestMethod -Uri $uri -StatusCodeVariable "ExtIDscv" -SkipHttpErrorChe -Method
Post -ContentType "application/json" -Authentication Bearer -Token $SecureToken -body -$BodyText

How to pass options to Rundeck job webhook URL

I have defined a webhook in Rundeck to run a particular job. This job has 3 options defined: ${option.VMName}, ${option.CPU} and ${option.Memory}. The job itself is defined as a local powershell script and executes as: powershell ${scriptfile} ${option.VMName} ${option.CPU} ${option.Memory}. This is tested and works fine.
I would now like to invoke the webhook POST URL so that the job is remotely triggered (from a web dashboard, using PowerShell) with these options defined. I tried, unsuccessfully, adding the options to the end of my URL:
http://mywebhookuri#myjobname?opt.VMName=$VMName&opt.CPU=$CPU&opt.Memory=$Memory
http://mywebhookuri#myjobname?VMName=$VMName&CPU=$CPU&Memory=$Memory
The following PowerShell code is being used to invoke the webhook:
$WebHookURI = "http://mywebhookuri#myjobname"
$header = #{}
$header.add("Content-Type","text/plain")
$body = #{} | ConvertTo-Json
$result = Invoke-RestMethod -Method Post -Uri $WebHookURI -Body $body -Headers $header
The documentation for the webhook plug-in and run-job usage state that "The JSON that is received by the plugin can be used to supply options, node filter, and the Run As user", but doesn't show a clear example of either.
How do I successfully pass these options to the webhook URL?
Following the documentation, you need to define the option in this way, and later call passing a JSON data, I did an example but using cURL:
curl -H "Content-Type: application/json" -X POST -d '{"field1":"hello world"}' http://yourhost:4440/api/34/webhook/3moY0Ru1zxl5gM0tpVlecJ5BN1LPyhsx#New_Hook
That is for this Job Definition example:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='opt1' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>e97efb53-99a6-4e5a-80b7-a1b055866f43</id>
<loglevel>INFO</loglevel>
<name>HelloWorld</name>
<nodeFilterEditable>false</nodeFilterEditable>
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<exec>echo ${option.opt1}</exec>
</command>
</sequence>
<uuid>e97efb53-99a6-4e5a-80b7-a1b055866f43</uuid>
</job>
</joblist>
To add some detail to MegaDrive68k's accepted answer (as this is essentially two questions):
I added the following to the "Options" field in the Rundeck webhook definition:
-VMName ${data.field1} -CPU ${data.field2} -Memory ${data.field3}
And the PowerShell code was modified as follows:
$WebHookURI = 'http://mywebhookuri#myjobname'
$header = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$header.add("Content-Type", "application/json")
$body = "{`n `"field1`" : `"$VMName`",`n `"field2`" : `"$CPU`",`n `"field3`" : `"$Memory`"`n}"
$result = Invoke-RestMethod -Method 'POST' -Uri $WebHookURI -Body $body -Headers $header
With these changes I was able to successfully invoke the Rundeck webhook with options.
a bit more concise version for PowerShell:
$WebHookURI = 'http://mywebhookuri#myjobname'
$header = #{}
$header.add("Content-Type", "application/json")
$body = #{
field1 = "$VMName";
field2 = "$CPU";
field3 = "$Memory"
} | ConvertTo-Json
$result = Invoke-RestMethod -Method 'POST' -Uri $WebHookURI -Body $body -Headers $header

convert simple curl data request to powershell invoke-webrequest

Converting a very simple Plaid API curl data request to a powershell invoke-webrequest
what works:
curl -X POST https://tartan.plaid.com/balance \
-d client_id=client-id-value \
-d secret=secret-value \
-d access_token=access-token-value
What I'm trying unsuccessfully in Powershell
#test powershell api call
$hash = #{ client_id = "client-id-value";
secret = "secret-value"
access_token = "access-token-value"
}
$JSON = $hash | convertto-json
#Invoke-WebRequest -uri "https://tartan.plaid.com/balance" -Method POST -Body $JSON
This returns a plaid error 1100 (client id missing), so I know some API functionality is working, but it's not parsing input data correctly.
My biggest misunderstanding is how to translate a "curl -data" value into the proper Powershell parameter.
Is this a header value, body value? etc.
Unless the target url expects the POST body to be in JSON format, skip the ConvertTo-JSON step completely.
When the chosen HTTP method is POST, Invoke-WebRequest will automatically take all the keys in the hashtable supplied to the -Body parameter and construct a body payload similar to that of curl -d:
$POSTParams = #{
client_id = "client-id-value"
secret = "secret-value"
access_token = "access-token-value"
}
Invoke-WebRequest -Uri "https://tartan.plaid.com/balance" -Method POST -Body $POSTParams

How to POST in powershell to canvas LMS

I am currently making an API for an university. The purpose of this project to to look at every course and check if it contains a certain module and if not, add one in. Seems fairly simple enough, but the thing that is making the project complicated is on learning the syntax on to actually do it! I am writing this code in powershell and I have tried to use curl and invoke web request. I tried following canvas' documentation, but I cannot get it. Here are two instances I have, can you please show me how to properly format this.
######this is the first way I tried it and the error I get Invoke-WebRequest : {"message":"missing module parameter"}
$temp2=($mainURL+$course.ID+"/modules"+$securityToken)
$reply = curl -Uri $temp2 -Method Post -Body '{"module[name]"="Getting started","module[position]"="1"}'
#######
#########This is the second way I've tried and the error I get Invoke-WebRequest : The remote server returned an error: (422) Unprocessable Entity.
$url="https://University.instructure.com/api/v1/courses/1371/modules?access_token=abc123"
$body= "{'module[name]'='Getting started,'module[position]'=1}"
Invoke-WebRequest -Uri $url -ContentType "application/json" -Method Post -Body $body
#########
Documentation from the website https://canvas.instructure.com/doc/api/index.html
UPDATE 5-26-2016
I have figured out how to properly format the body for the message. Now I am getting the error message
$header = #{"Authorization"="Bearer "+ $security_token}
$body= '{"module[name]":"Getting started","module[position]":"1"}'
$curlly=Invoke-WebRequest -Headers $header -Body $body -Method Post -ContentType "application/json" -Uri ($url_main+"courses/1371/modules")
$module = ConvertFrom-Json $curlly.Content
curl : Invalid URI: The hostname could not be parsed.
At line:1 char:1
+ curl
+ ~~~~
+ CategoryInfo : NotSpecified: (:) [Invoke-WebRequest], UriFormatException
+ FullyQualifiedErrorId : System.UriFormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
I really do not know what to do at this point any guidance will be appreciated at this point.
After a week of fiddling around with the actual JSON format, I took out the content type on the Invoke-WebRequest to see if the server would be able to just guess the format. It worked!