Unable to retrieve proper error from sharepoint using invoke-webrequest/restmethod - rest

Upload a document into sharepoint using invoke-webrequest works but comes back with an unhelpful error when overwrite=false is used
I have used postman to send the same request and get back a sharepoint exception error
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code>-2130575257, Microsoft.SharePoint.SPException</m:code>
<m:message xml:lang="en-US">A file with the name docs/a.txt already exists. It was last modified by [redacted] on 08 Aug 2019 15:23:02 +0100.</m:message>
</m:error>
try
{
Invoke-webrequest -method post -uri $uri -infile $fullpath -headers $Headers -credential $credential
}
catch
{
$errors = $_.exception
}
instead of getting the error that is in postman I get "The remote server returned an error: (400) Bad Request."

I got around this by following the parserror function suggested here
How to get Powershell Invoke-Restmethod to return body of http 500 code response
function ParseErrorForResponseBody($Error) {
if ($PSVersionTable.PSVersion.Major -lt 6) {
if ($Error.Exception.Response) {
$Reader = New-Object System.IO.StreamReader($Error.Exception.Response.GetResponseStream())
$Reader.BaseStream.Position = 0
$Reader.DiscardBufferedData()
$ResponseBody = $Reader.ReadToEnd()
if ($ResponseBody.StartsWith('{')) {
$ResponseBody = $ResponseBody | ConvertFrom-Json
}
return $ResponseBody
}
}
else {
return $Error.ErrorDetails.Message
}
}
try
{
Invoke-restmethod -method post -uri $uri -infile $fullpath -headers $Headers -credential $credential
}
catch
{
ParseErrorForResponseBody($_)
}

Related

Soti MobiControl API call to update devicegroups in PowerShell

I am trying to make an API call to update one devicegroup in each loop using the reference ID. I am able to fetch token but having issue when using PUT to update the devicegroup. Here is what i tried so far:
$Header1 = #{}
$Header1["Authorization"] = "Bearer " + $Token
try
{
#Using /devices to get the group level path as I am trying to update a customattribute on group level instead of each device
$response1 = Invoke-RestMethod -Uri "https://$MCFQDN/MobiControl/api/devices" -Headers $Header1
#Using /devicegroups for reference ID
$response2 = Invoke-RestMethod -Uri "https://$MCFQDN/MobiControl/api/devicegroups" -Headers $Header1
}
catch
{
$($_.Exception.Message)
}
foreach ($path1 in $response1)
{
foreach ($path2 in $response2)
{
if ($path1.Path -eq $path2.Path)
{
$refid = "referenceId:" + $path2.ReferenceId
#$refid = [System.Web.HttpUtility]::UrlEncode($refid) #tried encoding refid but no use
$uri = "https://$MCFQDN/MobiControl/api/devicegroups/$refid/customAttributes/{Custom_Attribute_Name}"
#This is the value for my Custom_Attribute_Name
$groupname = ($path2.Path).split('\')[-1]
$Body1 = #{}
$Body1["customAttributeValue"] = $groupname
# tried $Body1 = #{$groupname} but in vain
Invoke-RestMethod -Uri $uri -Method PUT -Body ($Body1 | ConvertTo-Json) -Headers $Header1 -ContentType "application/json"
}
}
}```
When trying to execute the above, getting below error:
*Invoke-RestMethod : {
"$type": "ErrorDetails",
"ErrorCode": 0,
"Message": "Contract validation failed",
"Data": [
"customAttributeValue: Error parsing value"
],
"HelpLink": null
}*
Any help is greatly appreciated.
Based off a brief test on the api page (https://FQDN/MobiControl/api). I receive the same “customAttributeValue: Error parsing value” error if I don’t quote the customAttributeValue value itself with single or double quotes. Try amending your $groupname variable with that in mind.

PowerShell: How can I determine if Invoke-WebRequest has timed out?

I need to produce some output when Invoke-WebRequest exceeds the time limit set by the -TimeoutSec parameter. How can I build an If condition that runs when this is the case?
In other words; what goes in place of ????? in the example below?:
Try {
Invoke-RestMethod -Uri $Uri -contentType "application/json"
-Method Post -Headers $Headers -Body $Body -TimeoutSec 8
}
Catch {
If (?????) {
Write-Host "the request timed out..."
}
}
In Windows PowerShell, the exception thrown will be a [System.Net.WebException] with the Status field set to Timeout:
try{
Invoke-WebRequest 'http://hostname.fqdn/really/slow/endpoint/' -TimeoutSec 3 -UseBasicParsing
}
catch [System.Net.WebException] {
if($_.Exception.Status -eq 'Timeout'){
# the request timed out
}
# something else went wrong during the web request
}

Exception when creating a Databricks cluster via REST API

I can successfully create a Databricks cluster via REST API using the following in Postman:
POST /api/2.0/clusters/create HTTP/1.1
Host: adb-xxxxxxxxxxxxxxxx.xx.azuredatabricks.net
Authorization: Bearer eyJ <REMOVED> EJA
Content-Type: application/json
{
"cluster_name": "xxxxxxx-xxxxx-xx-x-xxx-##-xxxxxxx-####",
"spark_version": "5.5.x-scala2.11",
"node_type_id": "Standard_DS3_v2",
"autoscale" : {
"min_workers": 2,
"max_workers": 10
},
"autotermination_minutes": 30
}
When I convert the above for use with PowerShell's Invoke-RestMethod, I get a WebException. When running the script in the Windows PowerShell ISE (running as Administrator) the following results:
The remote server returned an error: (400) Bad Request.
at <ScriptBlock>, <No file>: line 91
System.Net.WebException: The remote server returned an error: (400) Bad Request.
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
The Azure AD token generated in PowerShell is the same token used successfully in Postman. This issue doesn't appear to be related to a bad token.
Here is the PowerShell that results in the exception:
<SCRIPT>
... API calls re: AAD Token omitted ...
Write-Host "Create Databricks Cluster"
$body = #{
cluster_name = "xxxxxxx-xxxxx-xx-x-xxx-##-xxxxxxx-####"
spark_version = "5.5.x-scala2.11"
node_type_id = "Standard_DS3_v2"
autoscale = #{
min_workers = 2
max_workers = 10
}
autotermination_minutes = 30
}
$headers = #{
"Authorization"="Bearer " + "$apiKey";
"Content-Type"="application/json";
}
$uri = "$uriroot/2.0/clusters/create"
Write-Host $uri
Write-Host $headers
try { $response = Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body }
catch {
Write-Host $_
Write-Host $_.ScriptStackTrace
Write-Host $_.Exception
Write-Host $_.ErrorDetails
}
Write-Host $response
</SCRIPT>
What is the PowerShell version missing but present in Postman?
Here's a solution I found. Use ConvertTo-Json on the $body variable passed to the -Body command-line argument.
try { $response = Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body (ConvertTo-Json $body) }

Powershell Invoke-RestMethod Internal Server Error

When I run this (parameters and body that worked from Postman):
$Url = "http://${IPADDR}:8080/api/v1/topology/query"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Access-Token', 'token')
$headers.Add('Content-Type', 'application/json')
$headers.Add('Accept', 'application/json')
$json =
'{
"includes":[{"ids":["264690t5te74hy4y"],"observationName":"page_life_expectancy"}],
"startTime":1528718400000,
"endTime":1528768800000,
"granularity":3600000,
"numberOfValue":1,
"retrievalType":"RAW"
}'
$response = Invoke-RestMethod -Method 'Post' -Uri $url -Headers $headers -Body $json
$ple = $response | select -ExpandProperty data | select max
in Powershell ISE, I get this:
An error occurred while calling REST method at: http://${IPADDR}:8080/api/v1/topology/query. Error: The remote server returned an
error: (500) Internal Server Error.. Response body: Apache Tomcat/7.0.82 - Error report
Any expert in Powershell, JSON, and REST API that can help me with this issue?
The content of the Body parameter of Invoke-RestMethod should be an object serialized in JSon. In your example, you have 3 levels of serialization.
You should remove 2 levels of serialization:
$jsonBody = '{
"includes":[{"ids":
["264690t5te74hy4y"],"observationName":"page_life_expectancy"}],
"startTime":1528718400000,
"endTime":1528768800000,
"granularity":3600000,
"numberOfValue":1,
"retrievalType":"RAW"
}'
$response = Invoke-RestMethod -Method 'Post' -Uri $url -Headers $headers -Body $jsonBody
But it's not guaranteed that the error 500 disappear.
You may have more details about the error with the Exception content. You can try that:
try {
$response = Invoke-RestMethod -Method 'Post' -Uri $url -Headers $headers -Body $jsonBody
}
catch {
$errorMessage = $_.Exception.Message
if (Get-Member -InputObject $_.Exception -Name 'Response') {
try {
$result = $_.Exception.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($result)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
} catch {
Throw "An error occurred while calling REST method at: $url. Error: $errorMessage. Cannot get more information."
}
}
Throw "An error occurred while calling REST method at: $url. Error: $errorMessage. Response body: $responseBody"
}
Error handling from post: How to get Powershell Invoke-Restmethod to return body of http 500 code response
From PowerShell since you serialize the content to JSON, specify -ContentType "application/json". Also, if you think the content might contain unicode strings, include the -ContentType "application/json; charset=utf-8".

PowerShell 403 HTTP Request With Parameters Containing Square Brackets

I'm trying to make a PATCH request using the following lines in PowerShell but it is returning a 403:
Try{
$Body = #{
'api_key' = 'myapikey'
'item[status]' = 'unavailable'
} | ConvertTo-Json
$response = Invoke-WebRequest -Method PATCH -Uri "https://api.example.com/store/apikey.json" -Body $Body -ContentType "application/json"
$response.StatusCode
}
Catch [System.Net.WebException]{
$code = [int]$_.Exception.Response.StatusCode
}
Fiddler is returning a 403 with the following message: "{"error":"Parameter item is required"}". Also, the query string in Fiddler is empty. However, a successful request is made when everything is hard-coded into the Uri:
$statusUpdate = Invoke-WebRequest -Method PATCH -Uri "https://api.example.com/store/apikey.json?api_key=myapikey&item[status]=unavailable" -ContentType "application/json"
If that's the code you're actually using to hit the API, your problem appears to simply be due to piping your json body to out-host, thus sending an empty $Body to the API, so you should edit it to do this:
try
{
$Body = #{
'api_key' = 'myapikey'
'item[status]' = 'unavailable'
} | ConvertTo-Json
$response = Invoke-WebRequest -Method PATCH -Uri "https://api.example.com/store/apikey.json" -Body $Body -ContentType "application/json"
$response.StatusCode
}
catch [System.Net.WebException]
{
$code = [int]$_.Exception.Response.StatusCode
}