How to parse JSON from HtmlWebResponseObject - powershell

Here is the GET request I wrote in PowerShell:
$registry = Invoke-WebRequest -Uri "https://${web_ip}/v1/registry/" -Method GET -Headers #{Authorization="token $token"} -ContentType "application/json"
Write-Host $registry
It will show something like this:
[{"user": "corey", "project": "corey", "registry": "corey-registry"}]
I tried to parse the response to get the value from the key "registry", but it didn't work as my expectation.
# to get the first value in the list
$registry[0] => the output is the same as listed above
# check the type
$registry.GetType() => Microsoft.PowerShell.Commands.HtmlWebResponseObject
I don't know how to convert HtmlWebResponseObject to a json or list object, and I have no idea how to get the value "corey-registry" in code either, that's my main problem.
I stuck at this issue, any ideas? I would appreciate any help.

The response has the Content property which contains the raw JSON. Use ConvertFrom-Json to convert it into an object. You can then easily access the registry property.
Here is a (quite verbose) example with some explanations:
# get response
$response = Invoke-WebRequest -Uri "https://${web_ip}/v1/registry/" -Method GET -Headers #{Authorization="token $token"} -ContentType "application/json"
# get raw JSON
$json = $response.Content
# deserialize to object
$obj = ConvertFrom-Json $json
# you can now easily access the properties
$registry = $obj.registry

Related

Correctly format JSON for Powershell Post? (Missing '=' operator after key in hash literal.)

I am attempting to use Powershell to perform some "POST" requests. However, I can't seem to get the JSON correctly formatted. How do I accomplish this?
>> $JSON=#{name:"TestName"}
>> Invoke-WebRequest -Uri http://localhost:7071/api/HttpTrigger1 -Method POST -Body $JSON
>> $response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" -Method Post -Body $JSON -ContentType "application/json"
ParserError:
Line |
1 | $JSON=#{name:"TestName"}
| ~
| Missing '=' operator after key in hash literal.
So, there are two ways you can do this:
The first, as suggested by Santiago, is
$json = '{name:"TestName"}'
$response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" `
-Method Post -Body $json -ContentType "application/json"
The second, using (roughly) the syntax you were using, is
#create a Powershell object (note the use of '=' instead of ':' for assignment)
#(such a simple example is not an improvement over the example above)
$json = #{ name = "TestName" } | ConvertTo-JSON
$response = Invoke-WebRequest -Uri "http://localhost:7071/api/HttpTrigger1" `
-Method Post -Body $json -ContentType "application/json"
The first method is certainly cleaner and more direct. The second is useful when the source data for the request comes as the result of manipulating Powershell objects, and you want to convert them for use in a web request.

Azure devops Work Item types API returns string instead of JSON

When I try to get work item types via PowerShell, I get a string instead of the expected JSON.
This is my PowerShell code:
$Token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))
$JsonContentType = 'application/json-patch+json'
$Header = #{Authorization = 'Basic ' + $Token;accept=$JsonContentType}
$BaseUri = "https://dev.azure.com/$($Organisation)/"
$Uri = $BaseUri + "$Project/_apis/wit/workitemtypes?api-version=5.1"
$Result = Invoke-RestMethod -Uri $uri -Method GET -Headers $Header
$Result
I also tried with the newer version 6.0, but it also returns a string instead of JSON.
Other responses are fine, for example:
$Uri = "https://dev.azure.com/$($Organisation)/_apis/projects?api-version=5.1"
$Projects = Invoke-RestMethod -Uri $Uri -Method get -Headers $Header
This correctly returns JSON, or if I request a work item, I also get JSON.
I cannot figure out why this is...
Any ideas anyone?
The Invoke-Rest-Method tries to return a PSCustomObject, which does not support properties without names and thus the conversion fail and you get the plain string back:
From Invoke-RestMethod fails to parse JSON response
The problem is that by default, Invoke-RestMethod tries to convert the
json to a PSCustomObject. However, PSCustomObject doesn't support a
property without a name. In your script, add -AsHashTable to get an
object that supports this.
However, I think that a warning instead of an error may be better here
and have the resulting object not contain that property by default.
Solution for Powershell 6 and above
You can convert the string yourself to a data structure that supports empty properties (like a hashtable). This can be done using the ConvertFrom-Json method as shown below
$Token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($PAT)"))
$Header = #{Authorization = 'Basic ' + $Token}
$BaseUri = "https://dev.azure.com/$($Organization)/"
$Project = "test"
$Uri = $BaseUri + "$Project/_apis/wit/workitemtypes?api-version=5.1"
$Result = Invoke-RestMethod -Uri $uri -Method GET -Headers $Header
# Check if type is string, then convert to a hashtable
if ($Result.GetType().Name -eq "String") {
$jsonRes = ConvertFrom-Json -AsHashtable -InputObject $Result
} else {
$jsonRes = $Result
}
$jsonRes
Solution for Powershell 5 and below
If you are using an older verison of powershell you will need to parse the string into a hashmap yourself or using a thrid party tool. (I am not aware of any built in cmdlet that does this at least).
One option could be to use the JavaScriptSerializer .NET class, which is done in the Poshstache module. The code is available on the link so you should be able to review it and possibly customize it to fit your needs

Insert document on CosmosDB through Powershell

I am using Invoke-RestMethod to make a post request to create a new document in CosmosDB. So far I followed theses links: Invoking Rest API using PowerShell - CosmosDb
, Add a Document to CosmosDB via the REST API using PowerShell and the official documentation.
My script retrieves an object like this from external service:
{
"ObjectId": "bd33f6b5-a066-4f0f-8d1b-291a6a2b90ba",
"Date": "\/Date(1589379850000)\/",
"Data": "{\"CreationTime\":\"2019-06-13T13:21:55\",\"Id\":\"e985f142-9359-4ebf-a319-7fa30b6c9987\", \"Fields\":[{\"Name\":\"foo\",\"Value\":\"bar\"}]}"
}
My objective is to post the field Data into cosmos. To this I extract this field using: $payload | Select-Object -expand Data. (I have the above json as PowerShell object). Since this extracted object is a string, I passed it to Invoke-RestMethod:
Invoke-RestMethod -Method $Verb -Uri $queryUri -Headers $headers -Body $payload
But I keeping getting a Bad Request status. I've also tried the following:
Invoke-RestMethod -Method $Verb -Uri $queryUri -Headers $headers -Body ($payload | ConvertTo-Json -Depth 100)
Invoke-RestMethod -Method $Verb -Uri $queryUri -Headers $headers -Body ($payload | ConvertFrom-Json | ConvertTo-Json -Depth 100)
Note: I was able to deserialize this string in C# using newtonsoft (I made a function to receive the PowerShell request). I also was able to insert this document via Postman. Looks like the issue is in the body of the request, since using the PowerShell code generated by Postman worked for me.
Edit: I am passing the content type ("application/json") in header of the request. It also fails when pass it I directly to the Invoke-RestMethod
Can someone give a light? To me it should work fine.
Your payload is missing the required id attribute:
Remember that the REST API is for the Core SQL API operations. Your payload seems to be for a Mongo document?
Make sure you are also passing the partition key. Reference: https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/PowerShellRestApi/PowerShellScripts/CreateItem.ps1
The data seems to be double converted, to extract it you can use this:
$json = '{"ObjectId": "bd33f6b5-a066-4f0f-8d1b-291a6a2b90ba", "Date": "\/Date(1589379850000)\/", "Data": "{\"CreationTime\":\"2019-06-13T13:21:55\",\"Id\":\"e985f142-9359-4ebf-a319-7fa30b6c9987\", \"Fields\":[{\"Name\":\"foo\",\"Value\":\"bar\"}]}"}'
$data = $json | ConvertFrom-Json | Select-Object -ExpandProperty "Data" | ConvertFrom-Json
$body = $data | ConvertTo-Json -Depth 10
So now $body is a proper JSON object which can be send by the Invoke-RestMethod:
Invoke-RestMethod -Method $verb -Uri $queryUri -Headers $headers -Body $payload -ContentType "application/json"

Powershell API Data Extraction

I'm getting data back from an API for a system of ours using Powershell but it doesn't quite return it correctly. It is putting the data all under one header as seen below. I'm trying to extract the downloadLink part only
Tried converting to JSON to see if I could get anywhere else with it.
$token = ".."
$web = Invoke-RestMethod -uri $url -Method Get -Headers #{'Authorization' = $token}
echo $web
I get this as the outcome:
documents
---------
{#{documentName=Name.docx.pdf; downloadLink=https://app.xxx.com/api/docs/employees/111/shared/111}, {#{documentName=Name.docx.pdf; downloadLink=https://app.xxx.com/api/docs/employees/111/shared/111} ...
What I need to get is the downloadLink, but as it's all coming under the documents header I can't do a simple select or get on it.
Have you tried converting the results from JSON using ConvertFrom-Json? See the code example below.
Please note the change I made to the ContentType to the Invoke-RestMethod as well.
$token = ".."
$web = Invoke-RestMethod -uri $url -Method Get -ContentType "application/json" -Headers #{'Authorization' = $token}
$webResults = $web | ConvertFrom-Json
echo ($json | ConvertFrom-Json).downloadLink

Assign a REST method response to a value

I have a powershell script and I am trying to assign the response of the GET method to value $a. Bellow I have my code but it does not work. How can I assign the response to this value?
Thank you
$a = Invoke-RestMethod -Uri "https://cloud.skytap.com/templates/555949" -Method GET -ContentType "application/json" -Headers $headers | out-null
Write-Host "$a"
You're sending your code to out-null, which removes the output!
Remove | Out-Null and you'll find that your assignment to $a is working. Or perhaps you'll find an error message instead. If so, let me know and I'll do my best to help you.
To clarify, you should be running this instead.
$a = Invoke-RestMethod -Uri "https://cloud.skytap.com/templates/555949" -Method GET -ContentType "application/json" -Headers $headers