PowerShell How to Add to JSON Array - json

How do you add to a JSON array in PowerShell? I'm trying with the following code, but it's complaining with a "Collection was of a fixed size" exception:
$json = #"
[
{
"name": "First"
},
{
"name": "Second"
}
]
"#
$toAdd =#"
{
"name": "Third"
}
"#
$jobj = ConvertFrom-Json -InputObject $json
$jobj.Add((ConvertFrom-Json -InputObject $toAdd))

Just use += instead of Add():
$jobj += (ConvertFrom-Json -InputObject $toAdd)

This works.
$js = #"
[
{
"name":"First"
},
{
"name":"Second"
}
]
"#
$toAdd = #"
[
{
"name":"Third"
}
]
"#
$jobj = ConvertFrom-Json -InputObject $js
$jsrc = ConvertFrom-Json -InputObject $toAdd
$jobj = $jobj + $jsrc

Related

Powershell - Remove from Json

I have the following Json file:
{
"Id":1,
"Name":"john",
"Addresses":[
{
"Id":1,
"Street":"1st Street",
"City":"Riyadh"
},
{
"Id":2,
"Street":"2nd Street",
"City":"Dammam"
}
]
}
I want to remove the second address in the array using powershell.
I tried the following:
$filePath = 'C:\temp\Settings.json'
$settings = $filePath | ConvertFrom-Json
foreach($item in $settings.Addresses)
{
if($item.Id -eq 2)
{
$settings.Addresses.Remove($item)
}
}
Any ideas?
The following commented code snippet could help:
$filePath = 'C:\temp\Settings.json'
$settings = Get-Content -Path $filePath | ConvertFrom-Json
# $settings.Addresses # is an array of fixed size
# $settings.Addresses.IsFixedSize # returns True
# $settings.Addresses.Remove($item) # isn't possible; hence, let's build new array:
$NewAddresses = [System.Collections.ArrayList]::new()
foreach($item in $settings.Addresses)
{
if ($item.Id -ne 2)
{
[void]$NewAddresses.Add( $item )
}
}
# and replace old one:
$settings.Addresses = $NewAddresses
$settings | ConvertTo-Json ### | Out-File -FilePath $filePath -Force -Encoding utf8
Output: .\SO\66855002.ps1
{
"Id": 1,
"Name": "john",
"Addresses": [
{
"Id": 1,
"Street": "1st Street",
"City": "Riyadh"
}
]
}

How to add a value and key into existing JSON file over powershell?

I would like to add an additional key with value into my existing JSON file. Unfortunately I'm not able. Here an short overview:
My JSON-File before powershell script is run:
[
{
"id": "1",
"description": [
{
"country": "Brazil"
},
{
"country": "Mexico"
}
]
},
{
"id": "2",
"description": [
{
"country": "Argentina"
}
]
}
]
My wish, how the JSON-File should look like, after my powershell script is run:
[
{
"id": "1",
"description": [
{
"country": "Brazil",
"city": "Rio de Janeiro"
},
{
"country": "Mexico",
"city": "Mexico City"
}
]
},
{
"id": "2",
"description": [
{
"country": "Argentina",
"city": "Buenos Aires"
}
]
}
]
My powershell script:
function GetCity($country) {
$x = "not available"
If ( $country -eq "Brazil" ) { $x = "Rio de Janeiro" }
If ( $country -eq "Mexico" ) { $x = "Mexico City" }
If ( $country -eq "Argentina" ) { $x = "Buenos Aires" }
return $x
}
# Source the JSON content
$jsonFile = 'C:\Temp\test.json'
$jsonContent = Get-Content -Path $jsonFile
# Convert JSON to PSObjects
$jsonAsPsObjects = $jsonContent | ConvertFrom-Json
foreach ($info in $jsonAsPsObjects) {
$result = GetCity($info.description.country)
jsonContent | Add-Member -Type NoteProperty -Name "City" -Value $result
}
# Save JSON back to file
$json | ConvertTo-Json | Set-Content $jsonFile
Error:
jsonContent : The term 'jsonContent' is not recognized as the name of
a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path
is correct and try again.
How can I solve this issue?
There at two problems:
jsonContent should be $jsonContent in statement jsonContent | Add-Member ...
You're neglecting to loop over the array elements of the description property, to each of which a city property is to be added.
I suggest streamlining your code as follows:
function Get-City {
param([string] $country)
# Use a `switch` statement:
switch ($country) {
'Brazil' { return 'Rio de Janeiro' }
'Mexico' { return 'Mexico City' }
'Argentina' { return 'Buenos Aires' }
default { return 'not available' }
}
}
$jsonFile = 'C:\Temp\test.json'
(Get-Content -Raw $jsonFile | ConvertFrom-Json) | ForEach-Object {
# Add a 'city' property to each object in the 'description' property.
$_.description.ForEach({
Add-Member -InputObject $_ city (Get-City $_.country)
})
$_ # output the modified object
} | ConvertTo-Json -Depth 3 # | Set-Content $jsonFile

Append Members to an Array in JSON with PowerShell

I need to use Powershell to insert data into a json file within an array. Here is the json original structure
{
"Array": [
{
"servername": "foo"
},
{
"servername": "boo"
}
]
}
Here is the new structure:
{
"Array": [
{
"servername": "Foo",
"Disk": "100"
},
{
"servername": "Boo",
"Disk": "500"
}
]
}
Why does this not work?
$json = #"
{
"Array": [
{
"servername": "Foo"
},
{
"servername": "Boo"
}
]
}
"#
$jsonServerFoo=#"
{
"Disk": "100"
}
"#
$jsonServerBoo=#"
{
"Disk": "500"
}
"#
$jsonObj = $JSON | ConvertFrom-Json
$jsonServerFooObj = $jsonServerFoo | ConvertFrom-Json
$jsonServerBooObj = $jsonServerBoo | ConvertFrom-Json
$i = 1
$jsonObj.Array | Foreach-object {
if ( $i -eq 1 ) {
$_ | Add-Member -MemberType NoteProperty -Name "Disk" -Value $jsonServerFooObj.Disk
$i++
}
else {
$_ | Add-Member -MemberType NoteProperty -Name "Disk" -Value $jsonServerBooObj.Disk
}
}
$jsonObj
$jsonObj | ConvertTo-Json -Depth 100
I get the desired output
{
"Array": [
{
"servername": "Foo",
"Disk": "100"
},
{
"servername": "Boo",
"Disk": "500"
}
]
}
Use Add-Member to add members to a PSCustomObject. ConvertFrom-Json returns a PSCustomObject, not a Hashtable.
$jsonObj | Add-Member -MemberType NoteProperty -MemberName MyPropertyName -Value "some value, doesn't have to be a string"
You don't have to work with the base $jsonObj either, you can also add members to nested members of $jsonObj as well. In your case, with the Array member:
$jsonObj.Array | Foreach-object {
if( $i -eq 1 ) {
$_ | Add-Member -MemberType NoteProperty -Name Disk -Value $jsonServerFooObj.Disk
$i++
} else {
$_ | Add-Member -MemberType NoteProperty -Name Disk -Value $jsonServerBooObj.Disk
}
}
You may also want to consider calling ConvertTo-Json -Depth 100 so you don't get the default object depth which is low, 3 I think.
As noted by #user2864740, in PowerShell 6 ConvertFrom-Json has the -AsHashtable parameter if you would rather work with a Hashtable than a PSCustomObject.

How to iterate through a unknown JSON data/object?

Given the two JSON examples
{
"A": {
"name": "noname",
"key": "nokey"
}
and then
{
"B": {
"property1": "value3",
"country": "australia"
}
}
Is it possible to create a Powershell script that could take either one of the JSON examples and loop through them without knowing any names/keys upfront? (Using Windows 2016)
Something similar to what is posted as an answer here How do I loop through or enumerate a JavaScript object?
var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
for (var key in p) {
if (p.hasOwnProperty(key)) {
console.log(key + " -> " + p[key]);
}
}
Not working
Did try this, but it works only for the first level
$json = #"
{"A": {"property1": "value1", "property2": "value2"}, "B": {"property1":
"value3", "property2": "value4"}}
"#
$parsed = $json | ConvertFrom-Json
$parsed.PSObject.Properties | ForEach-Object {
$next = $_
$name = $_.Name
$value = $_.value
echo "$name = $value"
$next.PSObject.Properties | ForEach-Object {
$name = $_.Name
$value = $_.value
echo "Second level: $name = $value"
}
}
ConvertFrom-Json uses a nested structure of PSCustomObjects to represent the data - you can use $x.psobject.properties to get a collection of json property names and values for each item in the structure, and then you can loop over them however you want.
For example:
$x = ConvertFrom-Json "{ 'A': {'name': 'noname', 'key': 'nokey'} }"
foreach( $rootProperty in #($x.psobject.properties | where-object {$_.MemberType -eq "NoteProperty"}) )
{
write-host "'$($rootProperty.Name)' = '$($rootProperty.Value)'"
foreach( $childProperty in #($rootProperty.Value.psobject.properties | where-object {$_.MemberType -eq "NoteProperty"}) )
{
write-host "'$($childProperty.Name)' = '$($childProperty.Value)'"
}
}
outputs the following:
'A' = '#{name=noname; key=nokey}'
'name' = 'noname'
'key' = 'nokey'
You could also walk the structure recursively to an arbitrary depth if you convert the above into a function that calls itself on nested PSCustomObjects, but I'm not sure if you need to be able to do that or just go 2 levels like in your example json documents.

Json to CSV in Powershell

I'm working with Powershell, querying Azure Log analytics with the LogAnalyticsQuery module using Invoke-LogAnalyticsQuery.
I have the results
{
"tables": [
{
"name": "PrimaryResult",
"columns": [
{"name": "Computer","type": "string"},
{"name": "TimeGenerated","type": "datetime"},
{"name": "AggregatedValue","type": "real"
}
],
"rows": [
["VPN-Server","2018-02-20T07:30:00Z",5.083333333333333],
["SARMAD-SurfacePro4","2018-02-20T07:30:00Z",14.598250052664012],
["VPN-Server","2018-02-20T07:00:00Z",4.9523809523809526],
["SARMAD-SurfacePro4","2018-02-20T07:00:00Z",12.104500129109331],
["SARMAD-SurfacePro4","2018-02-20T08:00:00Z",20.936097813082174],
["VPN-Server","2018-02-20T08:00:00Z",4.245614035087719]
]
}
]
}
From the sample above, how I can use powershell to convert it to something like this?:
Reportname, Computer, TimeGenerated, AggregatedValue
Manual Value, JsonValue, JsonValue, JsonValue
You can use convertfrom-json and can finally use export-csv to export:
$a='{"tables":[{"name":"PrimaryResult","columns":[{"name":"Computer","type":"string"},{"name":"TimeGenerated","type":"datetime"},{"name":"AggregatedValue","type":"real"}],"rows":[["VPN-Server","2018-02-20T07:30:00Z",5.083333333333333],["SARMAD-SurfacePro4","2018-02-20T07:30:00Z",14.598250052664012],["VPN-Server","2018-02-20T07:00:00Z",4.9523809523809526],["SARMAD-SurfacePro4","2018-02-20T07:00:00Z",12.104500129109331],["SARMAD-SurfacePro4","2018-02-20T08:00:00Z",20.936097813082174],["VPN-Server","2018-02-20T08:00:00Z",4.245614035087719]]}]}'
($a | ConvertFrom-Json).tables.columns.name
Hope it helps.
You can do it similar to this:
function Get-Tables
{
param([Parameter(ValueFromPipeline=$true)]$Json)
process
{
foreach ($table in ($Json | ConvertFrom-Json).tables)
{
foreach ($row in $table.rows)
{
$result = New-Object PSObject
$columnIndex = 0
foreach ($column in $table.columns)
{
Add-Member -InputObject $result -MemberType NoteProperty -Name $column.Name -Value ($row[$columnIndex++])
}
$result
}
}
}
}
$json | Get-Tables | Export-Csv
Where $json is string variable with value from the question example.
$json = '{ "tables": [ ... ] }'