I am running Invoke-RestMethod to get a response from an API. That response is in JSON format and I am trying to figure out how to get access to the individual properties in my Powershell code.
Given these two lines:
$response = Invoke-RestMethod -Uri $paymentJournalUri -Method 'GET' -Headers $headers | ConvertTo-Json
Write-Host $response
my output looks like this:
{
"#odata.context": "https://api....yments",
"value": [
{
"#odata.etag": "W/\"JzI....Dsn\"",
"id": "b86ac....8fab",
"journalId": "59....b3ca",
"journalDisplayName": "EFT",
"lineNumber": 30000,
"vendorId": "a4c...552",
...
So how can I loop over the 'value' array and get access to each of those properties?
I have tried something like this:
$PSObj = $response | ConvertTo-Json
#Write-Host $PSObj
$PSObj.value | ForEach-Object {
Write-Host $_.journalDisplayName
}
Related
I'm getting the following response through an API and I'm trying to pull data out of the JSON response. I'm interested in only pulling the clone.href when clone.name = ssh.
response: {
"links": {
"clone": [
"#{href=ssh://sampleurl.com; name=ssh}",
"#{href=https://sampleurl.com; name=http}"
],
"self": [
"#{href=https://sampleurl.com}"
]
}
}
I'm using the following to call the API:
Invoke-RestMethod -Uri $uri -Headers $Header -Method POST -Body $Body|ConvertTo-Json
You can do this:
$result = Invoke-RestMethod -Uri $uri -Headers $Header -Method POST -Body $Body|ConvertTo-Json
$href = $result.links.clone | Where-Object Name -eq ssh | ForEach-Object href
$href # Output to console
This uses Where-Object to filter the clone array and ForEach-Object to extract the href property, using short form of ForEach-Object -MemberName href.
Alternatively you can use the following syntax:
$href = $result.links.clone.Where{ $_.Name -eq 'ssh' }.href
It uses PowerShell intrinsic method Where for filtering.
I am trying to use a REST API to configure some alerts in RecoverPoint for Virtual Machines (RP4VM). I am trying to enter multiple filters at the same using json. The json file looks like this:
[
{
"JsonSubType": "SystemEventLogsFilter",
"level": "WARNING",
"scope": "NORMAL",
"eventsIDs": [],
"filterUID": {
"id": 1570417688566256135
},
"name": "RPA_issue",
"topic": "RPA",
"groupsToInclude": null
},
{
"JsonSubType": "SystemEventLogsFilter",
"level": "WARNING",
"scope": "ADVANCED",
"eventsIDs": [],
"filterUID": {
"id": -1728986321682574312
},
"name": "cluster_events",
"topic": "CLUSTER",
"groupsToInclude": null
}
]
When I try to run the script I get an error:
Unexpected token (START_ARRAY), expected START_OBJECT: need JSON Object to contain As.PROPERTY type information (for class com.emc.fapi.version5_2.commons.SystemEventLogsFilter)
at [Source: org.apache.catalina.connector.CoyoteInputStream#75b592c2; line: 1, column: 1]
If I remove the square brackets it does the first value but not the second. Is this an issue with my code or an issue with theirs?
The script:
$rp4vmcl = import-csv -Path .\test_clusters.csv
$credential = Get-Credential
$username = $credential.GetNetworkCredential().UserName
$password = $credential.GetNetworkCredential().password
$credPair = "$($username):$($password)"
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair))
$headers = #{
Authorization = "Basic $encodedCredentials";
"Accept" = "application/json";
"Content-Type" = "application/json"
}
$comp = "/system/event_logs_filters"
$json = Get-Content .\event_log_filter.json -Raw
foreach ($s in $rp4vmcl) {
$cluster = $s.cluster_name
$uid = $s.cluster_uid
$curl = $s.cluster_url
$url = "$curl$comp"
$cluster
$results = Invoke-RestMethod -Method POST -uri $url -SkipCertificateCheck -Headers $headers -Body $json
}
If the recipient expect one Call per Json Object it will not be able to handle arrays. It's totally dependant from the implementation of the webservice. Btw, better change the body:
$results = Invoke-RestMethod -Method POST -uri $url -SkipCertificateCheck -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($json))
Try this first, and if this is doesnt help, loop through the elemnts and call the webservice individual:
$jsonObject = $json | ConvertFrom-Json
$results = #()
$jsonObject | foreach {
$json = $_ | ConvertTo-Json -Depth 99
$results += Invoke-RestMethod -Method POST -uri $url -SkipCertificateCheck -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($json))
}
Btw, the invoke-restmethod is buggy in powershell < 6 Version, so if youre will with the standard V5 Windows Version, check the response headers via invoke-webservice, and if the response header is:
"application/json"
and not
"application/json; charset=utf-8"
powershell will misinterpret this as a windows encoding. So if youree experiencing encoding issues, you have four options:
1.) if you can modify the webservice, change the response header
2.) switch to a newer powershell version (v7 is recommended)
3.) build your own webservice call directly via the .net cmdlets
4.) use the invoke-webservice, write the answer directly into a file with the OutFile Paramater
see also:
Powershell Invoke-RestMethod incorrect character
Suppose I have script1.ps1 with the following code:
Function Renew_Token($token) {
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-Vault-Token", $token)
$response = Invoke-RestMethod -method POST -uri "https://vault.com:8243/v1/auth/token/renew-self" -ContentType 'application/json' -headers $headers
$response| ConvertTo-Json -depth 100
}
Function getValues($token) {
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-Vault-Token", $token)
$response = Invoke-RestMethod -method GET -uri "https://vault.com:8243/v1/secret/vault/development" -ContentType 'application/json' -headers $headers
$response.data| ConvertTo-Json -depth 100
}
Renew_Token $token
write-host "token renewed!"
write-host "Vault Values:"
getValues $token
This gives me back a response like this:
{
"request_id": "ghgdf5-yuhgt886-gfd76trfd",
"lease_id": "",
"renewable": false,
"lease_duration": 0,
"data": null,
"wrap_info": null,
"warnings": null,
"auth": {
"client_token": "i657ih4rbg68934576y",
"accessor": "t543qyt54y64y654y",
"policies": [
"default",
"vault"
],
"token_policies": [
"default",
"vault"
],
"metadata": null,
"lease_duration": 2000,
"renewable": true,
"entity_id": ""
}
}
token renewed!
Vault Values:
{
"abc": "1234",
"def": "897",
"klm": "something12"
}
Now consider in a Script2.ps1, I call script1
$second_response = & ".\Script1.ps1"
of course, $second_response will store the 2 responses above as output.
How can i store JUST the second response as keys/values say in a table in Script2? i.e. this part:
{
"abc": "1234",
"def": "897",
"klm": "something12"
}
$HashTable = #{ }
$HashTable.Add($second_response.key, $second_response.value)
in other words, somehow the $second_response variable should only store this output:
{
"abc": "1234",
"def": "897",
"klm": "something12"
}
Note: that second response is considerably dynamic. meaning there could be different values on different environments. therefore, i want to be able to DYNAMICALLY store whatever is in this response, not hardcode the values
Also, I need the 2 responses in script 1 because i use script1 for other purposes, such as say i want to only view the vault content. script2 will have operations on the response from script1, so i have them separated for this convenience and flexibility
UPDATE: Following #kuzimoto suggestion, i removed the output and converting the response back from JSON, i get this output from Script2:
abc: 1234
def: 897
klm: something12
I can't comment yet, but here's a couple possibilities:
Edit script1.ps1
You don't mention if you need the first set of results. If you don't, just simply delete or comment out this line $response| ConvertTo-Json -depth 100 from the Renew_Token function.
Parse the output of script1.ps1 as json
You're passing the output of script1 to script2 as plain text. Simply change $second_response = & ".\Script1.ps1" to $second_response = & ".\Script1.ps1" | ConvertFrom-Json. Then when you want to access the second response, use $second_response[1] as both sets of JSON get added to a custom PS Object and can be accessed individually like you would an array.
I'm trying to send a request to an API that requires the body to be a json array. How can I convert the parameters hash table into a json array?
$parameters =#{
"sn" = "CND3210W9M"
"pn" = "D5H49AV"
}
$post = Invoke-RestMethod -Uri "https://blah.com/queries" -Method Post -Body ($parameters | ConvertTo-Json) -Headers $headers -ContentType 'application/json'
The API example shows the array below as a valid body
[
{
"sn": "CND3210W9M",
"pn": "D5H49AV"
}
]
If your request is expecting valid json, it might look something like this:
$body = #{
parameters =
#( # Make this an array
#{ # of hashtables
"sn" = "CND3210W9M"
"pn" = "D5H49AV"
} ) }
$body | ConvertTo-Json
Output:
{
"parameters": [
{
"pn": "D5H49AV",
"sn": "CND3210W9M"
}
]
}
#Eris, I tried using your code but it returned an extra {} which the API didn't like.
In the end I ended up just using a here string and moving on. It's not very elegant but couldn't get the API to respond properly otherwise.
$body = #"
[
{
"sn": "$sn",
"pn": "$pn"
}
]
"#
I am trying to POST a data to receive an input using powershell but it's throwing error.
Url: https://www.example.com/api/login
JSON data = {"username": "emailid", "password": "password"}
Once the post is successful, i will receive an output in JSON format something like:
{"account": "some-guid", "Token": "xxx", "selflink": "https://www.example.com/api/me", "username": "emailid"}
When I am posting the JSON data, I'm getting syntax error.
I'm using the below code to invoke
$url = "https://somedomain.com/api/login"
$params = #{"username"="abcd#pqr.com";
"password"="123456";
}
$response = Invoke-WebRequest -Uri $url -Method POST -Body $params -ContentType "application/json"
I changed the $param to | ConvertTo-Json
$JSON = #{
"username" = "abcd#xyz.com"
"password" = "123456"
} | ConvertTo-Json
and it worked fine.