I'm working against the OneLogin REST API and can't seem to get any calls with a PUT method working. When I test in Postman, I can pass a raw JSON body like this:
{
"role_id_array": [
115028
]
}
to the endpoint:
https://api.us.onelogin.com/api/1/users//add_roles
This works just fine. However, when I attempt to do the same with PowerShell's Invoke-RestMethod command, I'm getting 400 Bad Request errors. My code looks like this:
$Splat = @{
Method = $Method
Uri = https://api.us.onelogin.com/api/1/users/12345678/add_roles
ContentType = "application/json"
Headers = @{authorization = "bearer:$($Token.access_token)"}
Body = @{role_id_array = @(123456)}
}
Invoke-RestMethod @Splat
So far I've had no issues with any GET calls, only with PUT. Also, if I run the Body hashtable that I'm passing in through ConvertTo-Json, the output looks just like the above working example. Does anyone have any thoughts on why this doesn't work?
I was able to get a PUT to work!
First, I used this blog post here which has an excellent method to retrieve the full error message of an Invoke-RestMethod or WebRequest cmdlet.
In his method, first define a Function called Failure.
function Failure {
$global:helpme = $body
$global:helpmoref = $moref
$global:result = $_.Exception.Response.GetResponseStream()
$global:reader = New-Object System.IO.StreamReader($global:result)
$global:responseBody = $global:reader.ReadToEnd();
Write-Host -BackgroundColor:Black -ForegroundColor:Red "Status: A system exception was caught."
Write-Host -BackgroundColor:Black -ForegroundColor:Red $global:responsebody
Write-Host -BackgroundColor:Black -ForegroundColor:Red "The request body has been saved to `$global:helpme"
break
}
Then, wrap all of your Invoke-RestMethod calls in a try Catch block like this.
try {
$e = Invoke-WebRequest 'https://api.us.onelogin.com/api/1/users/$id' `
-Headers @{ Authorization = "bearer:$token" } `
-Body ( @{ phone = "7709746046" } | ConvertTo-Json ) `
-Method Put `
-ErrorAction:Stop `
-ContentType 'application/json'
}
catch {Failure}
Now when you run into an error, you can see the actual message, like this
> Status: A system exception was caught.
{"status":{"error":true,"code":400,"type":"bad request","message":{"description":"notes is not a valid attribute for user model","attribute":"notes"}}}
The request body has been saved to $global:helpme
This was super helpful in helping me get rid of the errors I was encountering, and I was able to update a user entry using a PUT verb and get it to work.
I only had to make two changes to your code to get this to work.
First, put quotes around the URI, as your example code didn't have them and you must have quotes around strings in a hashtable.
Finally, pipe your body content to ConvertTo-JSON, otherwise the data is sent over as a string, as you found in Fiddler.
With those two changes, here's my request and the response
$Splat = @{
Method = 'PUT'
Uri = 'https://api.us.onelogin.com/api/1/users/27697924/add_roles'
ContentType = "application/json"
Headers = @{authorization = "bearer:$token" }
Body = @{role_id_array = @(143175)} | ConvertTo-Json
}
try {Invoke-RestMethod @Splat -ErrorAction Stop }
catch {Failure}
Here's the response:
status
------
@{type=success; message=Success; error=False; code=200}
If you think PowerShell should present the actual server response for a non 200 status code, then help draw attention to this open issue on the PowerShell project page on Github.
Add your feedback or thumbs up it, and we might be able to get this changed in a future release of the language.
This issue is now fixed as of PowerShell v6.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With