PowerShell. Catch error. How add body to Invoke-RestMethod? - rest

I need to add this model:
{ "sourceVersion": "5ddcada97436a83dfedf5b41261ef9bfb8b718d7", "debug": true }
but PowerShell Console shows me Error "Bad Request."
This is my Code:
try {
$serverHost = "api.appcenter.ms"
$service = "https://$serverHost/v0.1/apps/App/App/branches/dev/builds"
$ContentType = "application/json" # Add the content type
$Method = 'POST' # Add the method type
$Body = '{ "sourceVersion" = "5ddcada97436a83dfedf5b41261ef9bfb8b718d7", "debug" = True }'
$Headers = #{'accept'='application/json';'X-API- Token'='efa699e279155919d4ed7ca880e335ebd7ad8191'}
$result = Invoke-RestMethod -Method POST -Uri $service -Headers $Headers - Body $Body
Read-Host -Prompt $result
}
catch {
Write-Error $_.Exception.ToString()
Read-Host -Prompt "The above error occurred. Press Enter to exit."
}

Related

Invoke-RESTMethod error "request_data must be of type: dict"

I am just starting out with REST API and the only language I have available to me is PowerShell
I am calling a list of "things" - this works and I get the ID property
I then try to iterate through that list and get a more detailed record for the "thing" (The second Invoke-RestMethod) - when I attempt this I get an error:
Invoke-RestMethod : {"reply": {"err_code": 500, "err_msg": "Got an invalid input while processing XDR public API", "err_extra": "request_data must be of type: dict"}}
I thought that convertto-json would convert the hashtable "request" to a dictionary.
I am new to this so please don't assume I know anything.
$ContentType = "application/json"
$URL_All = 'https://api-<company>.xdr.eu.paloaltonetworks.com/public_api/v1/endpoints/get_endpoints/'
$URLEndpoint = 'https://api-<company>.xdr.eu.paloaltonetworks.com/public_api/v1/endpoints/get_endpoint/'
$endpoints = Invoke-RestMethod -uri $URL_All -method POST -Headers #{"x-xdr-auth-id" = "1"; "Authorization" = "<API-KEY_Goes_Here>" } -ContentType "application/json" -Verbose
if ($endpoints.reply.count -gt 0){
write-host "Found $($endpoints.reply.count) details"
}
else {
write-host " API didn't return any endpoint - ending script "
break
}
foreach ($endpoint in $endpoints.reply) {
if($endpoint.agent_id -ne $null){
$request = #{
request_data = '{}'
filters = #{
field = "endpoint_id_list"
operator = "in"
Value = "$($endpoint.agent_ID)"
Search_from = 0
Search_to = 1
sort = #{
field = "last_seen"
keyword = "desc"
}
}
} | ConvertTo-Json
$Endpoint_full += Invoke-RestMethod -uri $URLEndpoint -method POST -Body $request -Headers #{"x-xdr-auth-id" = "1"; "Authorization" = "<API-KEY_Goes_Here>" } -ContentType "application/json" -Verbose
}
}
Your JSON conversion isn't the issue, the hint is in the error message.
"request_data must be of type: dict"
Key being request_data which just consists of this in your request:
request_data = '{}'
Ie. it's basically blank while the API expects a hash table or similar structure.

Invoke-WebRequest in an own function with arguments

I am trying to run an Invoke-WebRequest command on PowerShell Core 6.3 on a Ubuntu system with the following settings to create a forwarder:
$userLocalMailPart = "user"
$userGlobalMailPart = "Hotmail.com"
$address = "Some Address"
$pair = $login + ":" + $password
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$url = "https://" + $server + ":" + $port + "/Domain/ObjectList.html"
$headers = #{"Authorization" = $basicAuthValue;
"Referer" = $url
}
$body = #{
"NewForwarderName" = $userLocalMailPart ;
"NewForwarderAddress" = $address;
"CreateForwarder" = "Create Forwarder"
}
$result = Invoke-WebRequest `
-Uri $url `
-SkipCertificateCheck `
-Method 'POST' `
-Headers $headers `
-Body $body
This runs perfectly. No error and the forwarder is successfully created.
Now I want to use a function like this:
[Web]::requestHeaderContent($url, $headers, (ConvertTo-Json($body)), 'POST')
[object] static requestHeaderContent([String] $url, [hashtable] $headers, [Object] $body, [String] $meth) {
Invoke-WebRequest `
-Uri $url `
-SkipCertificateCheck `
-Method $meth `
-Headers $headers `
-Body $body
}
The variables like headers and body are the same. I also tried it with ConvertTo-Json but it just don’t work. I also receive a Success 200 Code but the forwarder is not created. I guess my problem are the parameters. Any idea what I am doing wrong?
Thanks
Stephan

Azure DevOps how to edit Wiki page via REST API

I want to edit a Azure DevOps wiki page over the REST API (Azure DevOps Server 2019.0.1).
When I run this PowerShell script:
#VARIABLES
$api = "api-version=5.0"
$root = "http://136.202.18.216:8070/Samples"
$personalToken = "uwawlzqp6j7i1nd5dasspwkwp63tr2w2sxb5563zrla2bivynbza"
#AUTHORIZATION
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$headers = #{
"Authorization" = ('Basic {0}' -f $token)
"If-Match" = '*'
}
#PROJECT VARIABLES
$project = "Framework%20A"
$pageToUpdate = "/Seite2"
#BODY
$body = #"
{
"content": "Hello"
}
"#
#GET
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&includeContent=True&$api"
$content = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers $headers
Write-Host "$($content.path) = $($content.content)" -ForegroundColor Yellow
#PUT
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&$api"
$update = Invoke-RestMethod -Uri $url -Method Put -ContentType "application/json" -Headers $header -Body $body -Verbose
Write-Host $update.content -ForegroundColor Yellow
exit(0)
The consolen output is:
/Seite2 = Seite 2 Content
AUSFÜHRLICH: PUT http://136.202.18.216:8070/Samples/Framework A/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=/Seite2&api-version=5.0 with -1-byte payload
Invoke-RestMethod: {"$ id": "1", "innerException": null, "message": "The required \" IfMatch \ "header specified in the request is an invalid page version Version of the
Wiki page as \ "IfMatch \" header for the request. \ R \ nParameterName: IfMatch "," typeName ":" Microsoft.TeamFoundation.SourceControl.WebServer.InvalidArgumentValueException,
Microsoft.TeamFoundation.SourceControl.WebServer "," TypeKey ":" InvalidArgumentValueException "," error code ": 0," eventId ": 0}
In C:\Users\mkober\Desktop\Azure DevOps Skripte (Bearbeitung)\WikiAPI.ps1:34 Zeichen:11
+ $update = Invoke-RestMethod -Uri $url -Method Put -ContentType "appli ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
The first line /Seite2 = Seite 2 Content is the result of a successful get request from the page I want to edit. The put request occures the error. What am I doing wrong here?
UPDATE: (Working Example)
#VARIABLES
$api = "api-version=5.0"
$root = "http://136.202.18.216:8070/Samples"
$personalToken = "uwawlzqp6j7i1nd5dasspwkwp63tr2w2sxb5563zrla2bivynbza"
#AUTHORIZATION
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$headers = #{
"Authorization" = ('Basic {0}' -f $token)
"If-Match" = '{0}'
}
#PROJECT VARIABLES
$project = "Framework%20A"
$pageToUpdate = "/Seite2"
#BODY
$body = #"
{
"content": "Hello"
}
"#
#---------------------------------------------------------------------------------------------------------------------------
#GET
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&includeContent=True&$api"
$content = Invoke-WebRequest -Uri $url -Method Get -ContentType "application/json" -Headers $headers
$etag = $content.Headers.ETag
$headers.'If-Match' = $headers.'If-Match' -f $etag
Write-Host "$($content.path) = $($content.content)" -ForegroundColor Yellow
#PUT
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&$api"
$update = Invoke-RestMethod -Uri $url -Method Put -ContentType "application/json" -Headers $headers -Body $body -Verbose
Write-Host $update.content -ForegroundColor Yellow
exit(0)
#---------------------------------------------------------------------------------------------------------------------------
In the If-Match header you can't just put '*', you need to put there the ETag of the page.
How do you get it? in your first GET call use Invoke-WebRequest (instaed of Invoke-RestMethod), now in the response you will get also headers response and there the ETag exist:
$page = Invoke-WebRequest -Uri $url ...........
$etag = $page.Headers.ETag
$headers = #{
"Authorizaion = ....."
"If-Match" = $etag
}
Now the second Invoke-RestMethod will work to update the page.

Getting Unauthorised error while triggering TFS build from release definition

I need to trigger a build after successful deployment of a release. I have tried using below code in Powershell in the release definition.
After executing, I get this error - Access is denied due to invalid credentials
$url = "http://abc:8080/tfs/GlobalCollection/Project/_apis/build/builds?
api-version=2.0"
$body = "{ 'definition' : { 'id' : 1} }"
$type = "application/json"
$headers = #{
Authorization = "Basic d3JlblxzcsampleTIzNA=="
}
Write-Host "URL: $url"
$definition = Invoke-RestMethod -Uri $url -Body $body -ContentType $type -
Method Post -Headers $headers
Write-Host "Definition = $($definition | ConvertTo-Json -Depth 1000)"`
Based on my test, you can use -UseDefaultCredentials :
$type = "application/json"
$url = "http://abc:8080/tfs/GlobalCollection/Project/_apis/build/builds?api-version=2.0"
$body = "{ 'definition' : { 'id' : 56} }"
Write-Host "URL: $url"
$definition = Invoke-RestMethod -Uri $url -Body $body -ContentType $type -Method Post -UseDefaultCredentials
Write-Host "Definition = $($definition | ConvertTo-Json -Depth 1000)"
Alternatively provide the specific Credential:
$user = "username"
$password = "password"
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$password)))
$headers = #{Authorization=("Basic {0}" -f $base64AuthInfo)}
$type = "application/json"
$url = "http://abc:8080/tfs/GlobalCollection/Project/_apis/build/builds?api-version=2.0"
$body = "{ 'definition' : { 'id' : 56} }"
Write-Host "URL: $url"
$definition = Invoke-RestMethod -Uri $url -Body $body -ContentType $type -Method Post -Headers $headers
Write-Host "Definition = $($definition | ConvertTo-Json -Depth 1000)"

Foreach and If linked issue

Here after my code for which I have an issue:
#Delivery Groups Information
$dgroup = Invoke-RestMethod -Uri "https://${XMS}:4443/xenmobile/api/v1/deliverygroups/filter" -Body '{}' -Headers $headers -Method Post
$new = 0
$count = $dgroup.dglistdata.dglist.length
for ($v=0; $v -lt $count; $v++) {
foreach ($dglistdata in $dgroup) {
Write-Host $dglistdata.dglistdata.dglist[$new].name
$new++
}
}
$Host.UI.RawUI.ForegroundColor = "white"
$dgroup = Read-Host -Prompt "Please provide Delivery Group Name for which notification will be sent"
$message = Read-Host -Prompt "Please provide the message to be sent"
#Devices
$devices = Invoke-RestMethod -Uri "https://${XMS}:4443/xenmobile/api/v1/device/filter" -Body '{}' -Headers $headers -Method Post
foreach ($device in $devices.filteredDevicesDataList) {
Write-Output $device.id >$null
Write-Output $device.platform >$null
}
foreach ($device in $devices.filteredDevicesDataList) {
$url = "https://${XMS}:4443/xenmobile/api/v1/device/" + $device.id + "/deliverygroups"
$global:dg = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
foreach($deliverygroups in $dg) {
Write-Output $dg.deliveryGroups.name >$null
}
}
foreach ($device in $devices.filteredDevicesDataList) {
if ($dg.deliveryGroups.name -match $dgroup) {
Write-Host $device.devicemodel
Send-Notification
} else {
$dgroup = 0
}
}
Info:
The main object of the code is to send notification to devices based on which group devices are member of.
Example:
iPad member of "DG 2"
iPhone member of "DG 1"
Result:
Do I miss something there?
In fact, I think I found the solution, I need to include my loop for notification in the other loop as:
foreach($device in $devices.filteredDevicesDataList)
{
$url = "https://${XMS}:4443/xenmobile/api/v1/device/" + $device.id + "/deliverygroups"
$Global:dg=Invoke-RestMethod -Uri $url -Headers $headers -Method Get
foreach($deliverygroups in $dg)
{
write-output $dg.deliveryGroups.name >$Null
If($dg.deliveryGroups.name -match $dgroup)
{
write-host $device.devicemodel
Send-notification
}
}
}