I'm accessing some JSON data using Invoke-RestMethod and I want to iterate through it, performing another Invoke-RestMethod per id and using the apiHost value for each call. A simplified example of the data is below:
"items": [
{
"id": "1234",
"apiHost": "thishost.com"
},
{
"id": "5678",
"apiHost": "anotherhost.com"
},
Here is the function as i have it so far. The Write-Host line (for troubleshooting this) displays ALL the apiHost values per id and explains why the next lines don't work. How do I refer to the relevant apiHost per iteration through the id so that the next lines will work?
function Get-ID {$headers = #{
'Authorization' = $auth_string
'Org' = $organization
}
$response = Invoke-RestMethod -Method Get -Headers $headers -Uri $a_url
foreach($id in $response.items.id) {
$itemheaders = #{
'Authorization' = $auth_string
'Dept-ID' = $id
}
write-host $response.items.apiHost
$apihost = $response.items.apiHost + '/here/there'
$outfile = 'c:\temp\' + $id + '_details.json'
$response = Invoke-RestMethod -Method Get -Headers $itemheaders -Uri $apihost -outfile $outfile
}
}
This post seems to suggest what I'm doing is correct, but I think I'm missing something obvious.
Related
I am using the Azure Management Rest API in Powershell , to create an NSG with some rule properties at the creation time. (yes I am aware that there is a PS module that can do that as well)
I have constructed the body of my PUT request as per the Microsoft documentation.
$url = "https://management.azure.com/subscriptions/$subid/resourceGroups/$rg/providers/Microsoft.Network/networkSecurityGroups/$nsg2" +"?api-version=2022-05-01"
$body = #{
"name" = "NSG-Test";
"location" = "useast";
"properties"= #{
"securityRules" = #(
#{
"name" = "rule1"
"properties"= #{
"protocol" = "*"
"sourcePortRange"= "*"
"destinationPortRange" = "80"
"sourceAddressPrefix"= "*"
"destinationAddressPrefix"= "*"
"access" = "Allow"
"priority" = 130
"direction"="Inbound"
}
}
)
}
} | ConvertTo-Json
try{
$Result = (Invoke-RestMethod -Uri $url -Headers $Headers -Method PUT -Body $body -Verbose -ContentType "application/json")
Write-Host $Result
}
Unfortunately I am greeted with the following error when executing this code :
{
"error": {
"code": "InvalidRequestFormat",
"message": "Cannot parse the request.",
"details": [
{
"code": "InvalidJson",
"message": "Error converting value \"System.Collections.Hashtable\" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.Se
curityRule'. Path 'properties.securityRules[0]', line 4, position 75."
}
]
}
}
So the reason behind this is the nested dictionary #{"name"="rule1"..} inside the securityRules attribute value.
When removing this hashtable, the request executes and the NSG gets created, however without any properties of course.
Is there any way to circumvent this issue and have the REST API accept my JSON body with it's properties?
I tried to reproduce the same in my environment I got the same error as below:
To resolve this issue, Make sure to add -Depth 4 in the ConvertTo-Json .
When I added ConvertTo-Json -Depth 4 the error was resolved.
Code:
$AppId="<clientID>"
$AppSecret="75X8Q~2RXXXXXX"
$TokenURI="https://login.microsoftonline.com/2f2ebbbc-e970-XXXXXXXX/oauth2/token"
$Resource="https://management.core.windows.net"
#OAUTH
$BodyRequest="grant_type=client_credentials&client_id=$AppId&client_secret=$AppSecret&resource=$Resource"
$AccessToken=Invoke-RestMethod -Method Post -Uri $TokenURI `
-Body $BodyRequest -ContentType 'application/x-www-form-urlencoded'
$subid ="<SubscriptionID>"
$rg="imran"
$nsg2="nsg2"
#$Headers=#{}
#$Headers.Add("Authorization ","Bearer " + $AccessToken.access_token)
$RequestURI = "https://management.azure.com/subscriptions/$subid/resourceGroups/$rg/providers/Microsoft.Network/networkSecurityGroups/$nsg2" + "?api-version=2022-07-01"
$body=#{
"name" = "nsg2";
"location" = "East us";
"properties"= #{
"securityRules" = #(
#{
"name" = "rule1"
"properties"= #{
"protocol" = "*"
"sourcePortRange"= "*"
"destinationPortRange" = "80"
"sourceAddressPrefix"= "*"
"destinationAddressPrefix"= "*"
"access" = "Allow"
"priority" = 130
"direction"="Inbound"
}
}
)
}
} | ConvertTo-Json -Depth 4
$Headers=#{}
$Headers.Add("Authorization","Bearer " + $AccessToken.access_token)
$Result = (Invoke-RestMethod -Uri $RequestURI -Headers $Headers -Method PUT -Body $body -Verbose -ContentType 'application/json' )
Write-Host $Result
Result:
To confirm in portal rule1 is added successfully like below:
I need generate token with "hostIDs" and "Fields" data. If I use only "hostIDs" it works but that token is invalid.
Below is the JSON body code which works with Postman but not in PowerShell.
{
"hostIds":[8876767,6736742,0986374],
"fields": ["ServiceTag","HardwareManufacturer","HardwareModel"]
}
Below JSON body works with Powershell only with 'hostIDs'. I also want to add another line to this body 'fields' which will fulfill the token generation. How to add multi-line?
$body = ConvertTo-Json #{
hostIds = 8876767,6736742,0986374
}
PowerShell code I am using for this API:-
#Credentials
$username = "xxxxxxx"
$password = "xxxxxxxxxxx"
$headers = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username,$password)))
#JSON Body
$body = ConvertTo-Json #{
hostIds = 8876767, 6736742,0986374
}
$EndPointURI = 'https://secure.logmein.com/public-api/v1/inventory/system/reports'
$response = Invoke-RestMethod -Uri $EndPointURI -Method Post -Headers #{Authorization=("Basic {0}" -f $headers)} -Body $body -ContentType 'application/json'
$token = $response.token
The syntax would be like this:
$body = ConvertTo-Json #{
hostIds = #('8876767', '6736742', '0986374')
fields = #('ServiceTag', 'HardwareManufacturer', 'HardwareModel')
}
Or like this:
$body = ConvertTo-Json #{
hostIds = #('8876767', '6736742', '0986374');
fields = #('ServiceTag', 'HardwareManufacturer', 'HardwareModel');
}
I am using Powershell to dynamically create a payload of data to be packaged up and sent on in a REST API Post Request.
My problem is that when it is recived by the API, it is listed as System.Collections.Hashtable. I am clearly doing something wrong here in how the data is being formatted, but nothing seems to work for me.
Here's how it is received by the API
{
"properties": {
"recip_test": [
"System.Collections.Hashtable",
"System.Collections.Hashtable"
],
"offending_shifts": "MAX, OnCall-Default Shift",
"group_name": "Alarmpoint Administrators"
}
}
I've tried ConvertTo-Json as well as += () / .Add() but none of those seem to work.
I am looping through an array of data which represent ID's in that array. For each item in that array (in the loop) I need to make a hash table which looks like this,
$recipient = #{
'id' = $y
'recipientType' = 'PERSON'
}
And then take that hash and shovel it into the payload field for recipients which then needs to be passed in the POST request. Below is the full code.
foreach($x in $collated_group_data) {
if ($x.group_name -ne 'Alarmpoint Administrators') {
next
}
$uuid = "***********/triggers?apiKey=**************"
$webhook_path = "$base/api/integration/1/functions/$uuid"
$payload = #{
'properties' = #{
'group_name' = $x.group_name
'offending_shifts' = $x.offending_shifts.Substring(0, $x.offending_shifts.Length - 2)
'recipients' = #()
}
}
foreach($y in $x.supervisor_ids) {
$payload.properties.recipients += #{'id' = $y; 'recipientType' = 'PERSON'}
}
$payload = $payload | ConvertTo-Json
Invoke-WebRequest -Uri $webhook_path -Method POST -Body $payload -ContentType 'application/json'
}
You must use the -Depth parameter with a value of 3 or greater in the ConvertTo-Json command in this case.
$payload = $payload | ConvertTo-Json -Depth 3
By default, the -Depth parameter is set to 2. The parameter specifies how many levels of contained objects are included in the JSON representation. You have three levels in your example.
I have to use PowerShell to manage a Websense server via API. I am using Invoke-RestMethod and I am using a json format to make the changes. The comand to the server is as follows:
Invoke-RestMethod -Uri $uriCreate -Method Post -Headers $headers -Body ($jsonCat | ConvertTo-Json) -ContentType "application/json"
My variables are as follows:
$uriCreate = https://<ipaddress>:<port>/api/web/v1/categories
$headers = #{ Authorization = <credentials> }
$jsonCat = [ordered]#{
"Transaction ID" = $transID
Categories = #(
[ordered]#{
"Category Name" = $catName
"Category Description" = $catDesc
"Parent" = $catID
}
)
}
When I attempt to create the category via Powershell I get the following error returned:
Invoke-RestMethod : {
"Error" : [ "Could not parse JSON: Value is not convertible to Int." ]
}
Any idea what I am doing wrong?
I'm trying to manipulate a json object and send it as content into the body of a put / post web request. The source of my json is a file on my disk.
This is my Powershell script:
$urlBase = 'https://mysite.myapp.com/service/api/Item/'
$myJson = (Get-Content 'file.json' | ConvertFrom-JSON)
# Then I manipulate my object
$id = $myJson.id
$myJson.version = '1.2.3.4'
# Request
$response = Invoke-RestMethod -Uri ($urlBase + $id) -Method Put -Body $myJson -ContentType 'application/json' -Headers $hdrs
When I execute my script y get this error message:
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:18 char:17
+ ... $response = Invoke-RestMethod -Uri ($urlBase + $id) -Method Put -Body ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
If I change my $myJson asignment for this the request works fine...
$myJson = Get-Content 'file.json'
... , but then I can't manipulate my json before send it.
Edited:
If I try to convert back using ConvertTo-Json I get the same error:
$convertedBack = $myJson | ConvertTo-Json
# Request
$response = Invoke-RestMethod -Uri ($urlBase + $id) -Method Put -Body $convertedBack -ContentType 'application/json' -Headers $hdrs
As pointed out in the comments: you need to convert your object back to JSON using the ConvertTo-Json cmdlet.
I see that you've tried that now and had the same problem. So I ask you this: is the value of $convertedBack exactly what you expected? Dump it to file and check!
The reason I am suspicious of this detail is that ConvertTo-Json has a little gotcha in it. Specifically the -Depth parameter which can cause some data loss.
-Depth
Specifies how many levels of contained objects are included in the JSON representation. The default value is 2.
Example Without -Depth
$basicJsonObject = #"
{
"name": "George",
"properties": {
"mood": "jovial",
"coffee": {
"hasCoffee": true,
"mugContents": {
"milk": false,
"doubleShot": true
}
}
}
}
"#
$psObject = ConvertFrom-Json -InputObject $basicJsonObject
Write-Host "Freshly Imported"
Write-Host "DoubleShot = $($psObject.properties.coffee.mugContents.doubleShot)"
$convertedBack = ConvertTo-Json -InputObject $psObject
$reConverted = ConvertFrom-Json -InputObject $convertedBack
Write-Host "Re-Converted"
Write-Host "DoubleShot = $($reConverted.properties.coffee.mugContents.doubleShot)"
Results
Freshly Imported
DoubleShot = True
Re-Converted
DoubleShot =
Example With -Depth
Change one line of code:
$convertedBack = ConvertTo-Json -InputObject $psObject -Depth 5
Results
Freshly Imported
DoubleShot = True
Re-Converted
DoubleShot = True
Note how the new results include the value from the $reConverted variable. This is because the data is not lost further upstream!