How to pass variables into an escaped json string? - json

I'm trying to pass json into a REST api call in order to start builds on VSTS.
The body has two parameters that are passed in as an escaped string and i'm struggling to update the parameters before invoking my request. An example of my body is below:
$body ='
{
"definition":
{
"id": ""
},
"parameters": "{\"environment\":\"uat\", \"browser\": \"ie\"}"
}
'
This is passed into the following where I update the definition id successfully:
$bodyJson=$body | ConvertFrom-Json
$bodyjson.definition.id = $buildDefId
$bodyString=$bodyJson | ConvertTo-Json -Depth 100
This works successfully but I can't access the parameters element of the json in order to pass the browser and environments in as variables.
Do you have any suggestions on how to do this?
I have tried the following without success:
$params = $bodyJson.Paramaters
$params -replace "uat","test"
$bodyString=$bodyJson | ConvertTo-Json -Depth 100
This updates the parameter in $params but it isn't passed back into the json when converted. I feel that i'm close but obviously missing a step.

Apparently you have a Json (parameters) string embedded in another Json string.
Meaning that you have to ConvertFrom-Json twice to deserialize everything and ConvertTo-Json twice to serialize it back with the new parameters:
(Note that I swapped the variable names $body and $bodyJson because $body is an object and $bodyJson is actually your Json string)
$bodyJson = '
{
"definition": {
"id": ""
},
"parameters": "{\"environment\":\"uat\", \"browser\": \"ie\"}"
}
'
$body = $bodyJson | ConvertFrom - Json
$paramJson = $body.parameters
$parameters = $paramJson | ConvertFrom - Json
$parameters
environment browser
----------- -------
uat ie
Change the parameter:
$parameters.environment = "test"
And rebuild the Json string:
$paramJson = $parameters | ConvertTo-Json -Compress
$body.parameters = $paramJson
$bodyJson = $body | ConvertTo-Json
$bodyJson
{
"definition": {
"id": ""
},
"parameters": "{\"environment\":\"test\",\"browser\":\"ie\"}"
}

Related

ConvertTo-JSON from string - access JSON fields by name in PowerShell

How can I access a field like $body.uuid?
This is what I have tried:
$body = #"
{ "uuid": "Test07",
"subject": "Template07-Subject",
}
"#
$bodyJSON = ConvertTo-Json $body
Write-Host $bodyJSON
Write-Host "uuid=$($bodyJSON.uuid)"
Write-Host "uuid=$($bodyJSON.$uuid)"
Results:
"{ \"uuid\": \"Test07\",\r\n \"subject\": \"Template07-Subject\",\r\n}"
uuid=
uuid=
Your $body variable contains a JSON string.
Unless your intent is to embed that string in another JSON string, do not call ConvertTo-Json on it - the latter's purpose is to convert objects to JSON strings.
In order to parse the JSON string into an object (graph), pass it to ConvertFrom-Json, which returns [pscustomobject] instance(s).
You can use regular property access, such as .uuid on the resulting object(s).
Note:
As bluuf points out, your original JSON contains an extraneous , after the "subject" property, which makes it technically malformed - this has been corrected below.
Note, however, that ConvertTo-Json in PowerShell (Core) 7+ still accepts such JSON, whereas Windows PowerShell does not.
# Create a string containing JSON
$body = #"
{
"uuid": "Test07",
"subject": "Template07-Subject"
}
"#
# Parse the JSON string into a PowerShell object (graph).
$bodyAsObject = ConvertFrom-Json $body
# Now you can use property access.
$bodyAsObject.uuid # -> 'Test07'

how to format json string for aws with powershell

i want to send an event to aws via a cli command in a powershell script. Here is the Json i need to send to the eventbridge:
[
{
"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}",
"Source":"google.com"
}
]
Thats what a tried in powershell:
$json='[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]'|ConvertTo-Json -Compress
aws events put-events --entries $json --region "eu-central-1"
That does not work. I even tried to write it to a json file and read it and send it from the file but it doesnt work. It somehow leads to too many "\" slashes or no slashes for my "Sensor" where it is necessary. I even tried to create a object and just convert the Sensor object to Json and then the whole object again to have the escaping, but it is not working.
EDIT:
i tried also this as mentioned in the answer:
$RequestObject = [pscustomobject] #(#{
Sensor = [pscustomobject] #{
id = "880/2021-04-13"
attribute = "green"
Name = "SensorGreen"
state = "SUCCEEDED"
}
Source = "google.com"
})
$RequestObject.Get(0).Sensor=$RequestObject.Get(0).Sensor | ConvertTo-Json -Compress
$Json = $RequestObject | ConvertTo-Json -Compress
aws events put-events --entries $Json --region "eu-central-1"
i included the #() to have an array and converted the sensor object twice to json to include the slashes. but the result is:
Error parsing parameter '--entries': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
if i use the command line interface only with the aws command and put the object directly into the command, then it works.. but the powershell does not.
You're passing a JSON string to an external program (aws)
Irrespective of how you constructed that string - directly as a string, or from an object / hashtable via ConvertTo-Json - as of PowerShell 7.1 - manual escaping of embedded " as \" is required, which, in turn requires escaping the preexisting \ preceding the embedded " as \\.
Note: None of this should be necessary, but due to a long-standing bug in PowerShell is - see this answer for details.
PowerShell Core 7.2.0-preview.5 now includes experimental feature PSNativeCommandArgumentPassing with an attempted fix, but, unfortunately, it looks like it will lack important accommodations for high-profile CLIs on Windows - see this summary from GitHub issue #15143. However, it would fix calls to aws.exe, the Amazon Web Services CLI.
# The JSON string to be passed as-is.
$json = #'
[
{
"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}",
"Source":"google.com"
}
]
'#
# Up to at least PowerShell 7.1:
# Manually perform the required escaping, to work around PowerShell's
# broken argument-passing to external programs.
# Note:
# -replace '\\', '\\' *looks* like a no-op, but replaces each '\' with '\\'
$jsonEscaped = $json -replace '\\', '\\' -replace '"', '\"'
# Now pass the *escaped* JSON string to the aws CLI:
aws events put-events --entries $jsonEscaped --region "eu-central-1"
ConvertTo-Json is for converting objects in PowerShell, not a string that you have tried to already write in Json. Your $Json variable produces this.
"[{\"Sensor\":\"{\\\"id\\\":\\\"880/2021-04-13\\\",\\\"attributes\\\":\\\"green\\\",\\\"Name\\\":\\\"SensorGreen\\\",\\\"state\\\":\\\"SUCCEEDED\\\"}\",\"Source\":\"google.com\"}]"
If you want to create the object in PowerShell and convert it to Json, then you can do this.
$RequestObject = [pscustomobject] #{
Sensor = [pscustomobject] #{
id = "880/2021-04-13"
attribute = "green"
Name = "SensorGreen"
state = "SUCCEEDED"
}
Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress
aws events put-events --entries $Json --region "eu-central-1"
Your Json will look like this if you print your variable out.
{"Sensor":{"id":"880/2021-04-13","attribute":"green","Name":"SensorGreen","state":"SUCCEEDED"},"Source":"google.com"}
Which I think is like the Json that the command is expecting. Not entirely sure why you need the strings escaping or the array. Here it is uncompressed.
{
"Sensor": {
"id": "880/2021-04-13",
"attribute": "green",
"Name": "SensorGreen",
"state": "SUCCEEDED"
},
"Source": "google.com"
}
Just noticed the powershell-2.0 tag. If you are using it, then you should do this instead to create your Json.
$Sensor = New-Object psobject -Property #{
id = "880/2021-04-13"
attribute = "green"
Name = "SensorGreen"
state = "SUCCEEDED"
}
$RequestObject = New-Object psobject -Property #{
Sensor = $Sensor
Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress
EDIT
If you absolutely must escape the strings in that way and have a single item array, then you should just pass the Json that you have written in your answer without any further conversion.
$json='[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attributes\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]'
If you want to make PowerShell do that for you then you would need to perform some string replacement on the Sensor object first.
PowerShell 2.0
$Sensor = New-Object psobject -Property #{
id = "880/2021-04-13"
attribute = "green"
Name = "SensorGreen"
state = "SUCCEEDED"
}
$SensorJson = $Sensor | ConvertTo-Json -Compress
$SensorJson.Replace("`"","\`"")
$RequestObject = New-Object psobject -Property #{
Sensor = $SensorJson
Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress
PowerShell 3.0+
$Sensor = [pscustomobject] #{
id = "880/2021-04-13"
attribute = "green"
Name = "SensorGreen"
state = "SUCCEEDED"
}
$SensorJson = $Sensor | ConvertTo-Json -Compress
$SensorJson.Replace("`"","\`"")
$RequestObject = [pscustomobject] #{
Sensor = $SensorJson
Source = "google.com"
}
$Json = $RequestObject | ConvertTo-Json -Compress
Then your AWS command
# Add the array around the compressed Json string.
aws events put-events --entries "[$Json]" --region "eu-central-1"
"[$Json]" prints
[{"Sensor":"{\"id\":\"880/2021-04-13\",\"attribute\":\"green\",\"Name\":\"SensorGreen\",\"state\":\"SUCCEEDED\"}","Source":"google.com"}]

How to parse/access JSON returned by Invoke-WebRequest in Powershell 4

I have the following call to an API in a powershell script (Powershell 4.0):
$Json = Invoke-WebRequest -Uri $RequestURL -UseBasicParsing -Headers $headers -ContentType 'application/json; charset=utf-8' -Method POST -Body $postParams -TimeoutSec 40
...and the content of the response (which is a string in JSON format) is written to a file:
Set-Content $path -Value $Json.Content
An example of a typical response...
{
"MyArray": [{
"MyField": "A1",
"MyField2": "A2"
}, {
"MyField": "B1",
"MyField2": "B2"
}]
}
All well and good, but now I have a requirement to parse the returned content as JSON and query some properties from within this Powershell script.
I presume I need to convert my string to 'proper' JSON and then to a powershell object in order to access the properties...so I have tried combinations of ConvertTo-Json and ConvertFrom-Json but can't ever seem to access it in anything other than a string. For example...
$x = $Json.Content | ConvertTo-Json
Write-Host $x.MyArray[0].MyField
$y = $x | ConvertFrom-Json
Write-Host $y[0].MyArray[0].MyField
In both cases above I get an error "Cannot index into a null array" suggesting that MyArray is null.
How do I convert my $Json response object into an object I can drill down into?
See ConvertFrom-Json
Converts a JSON-formatted string to a custom object or a hash table.
The ConvertFrom-Json cmdlet converts a JavaScript Object Notation
(JSON) formatted string to a custom PSCustomObject object that has a
property for each field in the JSON string.
Once you get the response converted to custom object or a hash table, you can access the individual properties
The link includes coding examples
This seems to work...
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$x = (New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer -Property #{MaxJsonLength=67108864}).DeserializeObject($Json.Content)
Write-Host $x.MyArray[0].MyField
...although not sure why yet.

How to write a value in json file using if conditions in powershell?

I am trying to add value in key pair json file using Powershell. I am getting an error. Need some guidance on PS Scripting.
Powershell 5.1 version and json file with key pair inside it.
MYJSON File:
{ "Theme":{"Res_List": {
"Method": "POST",
"Name":""}}}
PowerShell Script:
$file_path="C:\Users\RelativeConfig.json"
$json = Get-Content $file_path | Out-String | ConvertFrom-Json
$timestamp = Get-Date -Format ddMMHHmm
$namevalue = 'resource'+$timestamp+'e3'
echo $namevalue ##prints resource16sep2019 I want this to write in json as value for Name Key
$files = $json | Get-Member -MemberType Properties | Select-Object - ExpandProperty Name
$result = Foreach ($file in $json)
{
if ($file.Name -eq "Name") { $file.Value = $namevalue}
}
$result | ConvertTo-Json | Set-Content $json
Error:
No error but json is not updated with new values.
Expected:
{ "Theme":{"Res_List": {
"Method": "POST",
"Name":"resource16sep2019 "}}}
Actual:
{ "Theme":{"Res_List": {
"Method": "POST",
"Name":""}}}
To update your value in json you can do something like below
$bucket_name = "resource16sep2019" ## I want this to write in json as value for Name Key
$json.Theme.Res_List.Name = $bucket_name
It will directly replace the $bucket_name value with the Name value in JSON.
If you want to write this to the respective file use the below command,
$json | ConvertTo-Json -depth 32| set-content $file_path
Hope it helps! Cheers

ConvertFrom-Json : Cannot convert the JSON string because a dictionary that was converted from the string contains the duplicated keys

The following JSON is getting returned from OData API service:
{
"d": {
"results": [
{
"FileSystemObjectType": 0,
"Id": 1,
"ContentTypeId": "0x0100BC97B2F575CB0C42B79549F3BABD32A8",
"Title": "Nokia California",
"Address": "200 South Matilda Avenue\nW Washington Ave\n94086 Sunnyvale, California\nUnited States of America",
"ID": 1,
"Modified": "2014-02-24T10:06:39Z",
"Created": "2014-02-24T10:06:39Z",
"AuthorId": 12,
"EditorId": 12,
"OData__UIVersionString": "1.0",
"Attachments": false,
"GUID": "d12aafad-502a-4968-a69e-36a7ea05ec80"
}
]
}
}
and saved as a string into variable named $data
An attempt to convert a JSON-formatted string to a custom object using ConvertFrom-Json cmdlet:
$results = $data | ConvertFrom-Json
gives the following error:
ConvertFrom-Json : Cannot convert the JSON string because a dictionary
that was converted from the string contains the duplicated keys 'Id'
and 'ID'.
Is there any way to convert the specified JSON-formatted string in PowerShell?
This is how I have done with it:
$results = $data.ToString().Replace("ID", "_ID") | ConvertFrom-Json
Note, both examples assume the JSON is stored in the $jsonstring variable.
In PowerShell Core, ConvertFrom-Json -AsHashtable is the easiest alternative:
$json = $jsonstring | ConvertFrom-Json -AsHashtable
$json['d']['results']
Name Value
---- -----
Modified 2/24/2014 10:06:39 AM
Title Nokia California
Attachments False
ID 1
ContentTypeId 0x0100BC97B2F575CB0C42B79549F3BABD32A8
GUID d12aafad-502a-4968-a69e-36a7ea05ec80
Created 2/24/2014 10:06:39 AM
EditorId 12
AuthorId 12
Address 200 South Matilda Avenue…
Id 1
OData__UIVersionString 1.0
FileSystemObjectType 0
In Windows PowerShell, you can use the Deserialize(String, Type) method from the JavaScriptSerializer Class.
Add-Type -AssemblyName System.Web.Extensions
$serializer = [Web.Script.Serialization.JavaScriptSerializer]::new()
$json = $serializer.Deserialize($jsonstring, [hashtable])
$json['d']['results']
In PowerShell V1.0, or in PowerShell V2.0 when the JSON is too big, I still use a convertion to XML :
Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization
function Convert-JsonToXml
{
PARAM([Parameter(ValueFromPipeline=$true)][string[]]$json)
BEGIN
{
$mStream = New-Object System.IO.MemoryStream
}
PROCESS
{
$json | Write-String -stream $mStream
}
END
{
$mStream.Position = 0
try
{
$jsonReader = [System.Runtime.Serialization.Json.JsonReaderWriterFactory]::CreateJsonReader($mStream,[System.Xml.XmlDictionaryReaderQuotas]::Max)
$xml = New-Object Xml.XmlDocument
$xml.Load($jsonReader)
$xml
}
finally
{
$jsonReader.Close()
$mStream.Dispose()
}
}
}
Using this code you can loop thru your items you can test :
$a = Get-Content C:\temp\jsontest.txt
$b.root.d.results.Item
$b.root.d.results.Item[7].Id[0].InnerText
(Edited)
In you case I would only replace the expected duplicate ID/Id
$data = Get-Content C:\temp\jsontest.txt -Raw
$datacorrected = $a -creplace '"Id":','"Id-minus":'
$psJsonIn = $datacorrected | ConvertFrom-Json
If really you've got unexpected duplicate you can write a function that trap the convertion error due to duplicated key and replace one.
ConvertFrom-JSON it going to try to create a PS Custom Object from the JSON string. PowerShell object property names are case-insensitive, so "ID" and "id" represent the same property name. You're going to have to do something with those duplicate property names in your JSON before you try to do that conversion, or it's going to fail.
I used the ToLower() before converting the json to object, resolved my issue.
$sdf = $data.ToLower() | ConvertFrom-Json