Go over json data in Powershell - json

I have a JSON file that looks like this:
$jsondata = '{
"ips": {
"10.20.30.40": [
{
"rhost": "DNS Name1.",
"rdata": [
"10.20.30.40"
],
"rrtype": "A (1)",
"ttl": 86400,
"geo": null,
"source": "DNSProvider1"
}
],
"40.50.60.70": [
{
"rhost": "DNS Name2.",
"rdata": [
"40.50.60.70"
],
"rrtype": "A (1)",
"ttl": 86400,
"geo": null,
"source": "DNSProvider1"
}
]
}
}'
I want to get all the TTLs (for example) of every IP address in the list.
I converted this JSON to Powershell PSCustomObject:
$obj = $jsondata | convertFrom-Json
and now I want to get all the TTLs, I tried to get the list of the IPs (as a start):
foreach ($ip in $a.ips) {write-host $ip }
and I'm not getting strings as a result, that's why I (probably) can't go inside and get the TTLs.
So my question: how can I get all the IPs as strings?
I believe that once I'll get an answer for that, I'll understand how I can go over all the IPs in the list.
Thanks!

foreach($ip in $obj.ips | Get-Member -MemberType NoteProperty)
{
Write-Host -Verbose ("IP Address {0} has TTL {1}" -f $ip.Name, $obj.ips."$($ip.Name)".ttl)
}
Get-Member will get you the name of the property (which is the ip address) and not the value.

Thanks Rubanov, that really helped!
And just to document the whole answer:
foreach($ip in $obj.ips | Get-Member -MemberType NoteProperty)
{
Write-Host -Verbose $obj.ips.$($ip.Name).ttl
}
Or:
($obj.ips | Get-Member -MemberType NoteProperty).Name | % {$obj.ips.$_.ttl}

Related

How to remove nested JSON object members

I'm trying to remove the length value pair from the following JSON file:
{
"uuid": "6f74b1ba-0d7c-4c85-955b-2a4309f0e8df",
"records": {
"record1": [
{
"locale": "en_US",
"category": "alpha",
"contents": "My hovercraft is full of eels",
"length": 29
}
],
"record2": [
{
"locale": "cs_CZ",
"category": "alpha",
"contents": "Moje vznášedlo je plné úhořů",
"length": 28
}
]
}
}
Even though the length property is apparently found, it's not deleted, because the output file is identical to the input file.
I'm using the following code:
$infile = "C:\Temp\input.json"
$outfile = "C:\Temp\output.json"
$json = Get-Content $infile -Encoding UTF8 | ConvertFrom-Json
$records = $json.records
$records.PSObject.Properties | ForEach-Object {
if (($_.Value | Get-Member -Name "length")) {
Write-Host "length property found."
$_.Value.PSObject.Properties.Remove("length")
}
}
$json | ConvertTo-Json -Depth 3 | Out-File $outfile -Encoding UTF8
What am I doing wrong?
The record* properties are arrays, so you need a nested loop to process them:
foreach( $property in $records.PSObject.Properties ) {
foreach( $recordItem in $property.Value ) {
if( $recordItem | Get-Member -Name 'length' ) {
$recordItem.PSObject.Properties.Remove( 'length' )
}
}
}
For code clarity and performance I've replaced the ForEach-Object command by the foreach statement. Especially in nested loops, foreach helps to improve clarity as we no longer have to think about the context of the automatic $_ variable. Also the foreach statement is faster as it doesn't involve pipeline overhead.

How do I add a JSON element if and only if it does not already exist, using Powershell?

I have a JSON file I need to edit, conditionally. It may be an empty object:
{}
or it may contain other data.
I need to see if the data I'd like to add already exists, and if not, add it to that JSON file.
The content in question looks like this (entire JSON file):
{
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
In this case, if "2020.3.19f" does not exist, I need to add that block.
I looked at these docs but really, lost. Any tips appreciated: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.2
This seems close but I'm lost on the syntax of checking for null or empty, and how that translates to PS: PowerShell : retrieve JSON object by field value
Edit: So, for example if the original file is:
{}
Then I need to overwrite that file with:
{
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
And if the file already contained something, I need to keep that, just add the new block:
{
{
"2019.4.13f1": {
"version": "2019.4.13f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2019.3.13f1\\Editor\\Unity.exe"
],
"manual": true
},
{
"2020.3.19f1": {
"version": "2020.3.19f1",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f1\\Editor\\Unity.exe"
],
"manual": true
}
}
FWIW: I did find the condition I need:
$FileContent = Get-Content -Path "C:\Users\me\AppData\Roaming\UnityHub\editors.json" -Raw | ConvertFrom-Json
if ( ($FileContent | Get-Member -MemberType NoteProperty -Name "2020.3.19f1") -ne $null )
{
echo "it exists"
}
else
{
echo "add it"
# DO SOMETHING HERE TO CREATE AND (OVER)WRITE THE FILE
}
You can convert the json as object and add properties as you want.
$json = #"
{
"2020.3.19f2": {
"version": "2020.3.19f2",
"location": [
"C:\\Program Files\\Unity\\Hub\\Editor\\2020.3.19f2\\Editor\\Unity.exe"
],
"manual": true
}
}
"#
$obj = ConvertFrom-Json $json
if (-not $obj.'2020.3.19f1') {
Add-Member -InputObject $obj -MemberType NoteProperty -Name '2020.3.19f1' -Value $(
New-Object PSObject -Property $([ordered]#{
version = "2020.3.19f1"
location = #("C:\Program Files\Unity\Hub\Editor\2020.3.19f1\Editor\Unity.exe")
manual = $true
})
) -Force
$obj | ConvertTo-Json
}

How to modify Json using Powershell

I have the following JSON held in a file "test.json":
{
"metadata": [
{
"src": [
{
"files": [
"src/**.csproj"
]
}
],
"dest": "api",
"disableGitFeatures": false,
"disableDefaultFilter": false
}
]
}
I'd like to modify the "src" element. Instead of:
"src": [
{
"files": [
"src/**.csproj"
]
}
],
It needs to be:
"src": [
{
"files": [
"*.csproj"
],
"cwd":".."
}
],
Where I modify the first element of "files" and add "cwd". This should be straight forward but I'm struggling to achieve this in powershell. Can anyone point me in the right direction of any examples of this?
Thanks for any pointers in advance.
You can do the following:
$JSONObject = Get-Content test.json -Raw | ConvertFrom-Json
$JSONObject.metadata.src.files = ,'*.csproj'
$JSONObject.metadata.src | Add-Member -Name 'cwd' -Value '..' -MemberType NoteProperty
$JSONObject | ConvertTo-Json -Depth 5 | Set-Content test.json
The tricky part is to make sure the .files value is an array of a single element. You can do this with the array subexpression operator #() or the unary operator ,.

Powershell - json to text or csv

I have a folder with hundreds of json files in it & need to read them & create an output file with the various fields & values in it.
{
"id": "02002010",
"booktitle": "",
"pagetitle": "Demo Page",
"parent": "02002000",
"img": [
{
"imgfile": "02A.png",
"imgname": "02A.png"
}
],
"fmt": "",
"entries": [
{
"itemid": "1",
"partnumber": "1234567",
"partdescription": "Washer",
"partqty": "2",
"Manufacturer": "ACME",
"partdescriptionlocal": "Washer"
},
{
"itemid": "2",
"partnumber": "98765-B",
"partdescription": "Screw",
"partqty": "8",
"Vendor": "Widget Inc",
"TYPE": "Galv",
"partdescriptionlocal": "Screw"
}]
}
The json files will have generally the same structure, except that the "entries" may contain various fields in it that may not be the same from one entry to the next, or one json file to the next. Some may have fields within entry that I do not know the name of. There will be a few common fields in each "entries" section, but they could vary, and could be in a different order than what is shown.
I would like to write the output to a text/csv file that would be delimited that could then be imported into Excel. One column header with all fields listed. As new "entries" fields are found, tack them on to the end of each row & add to the header also.
you mean to do something like this?
$json = gc C:\temp\file.json | ConvertFrom-Json
$props = $json.entries | % {$_ | gm -MemberType NoteProperty} | select -exp name -Unique
$results = #()
foreach ($entry in $json.entries) {
$obj = $json | select *
foreach ($prop in $props) {
$obj | Add-Member -MemberType NoteProperty -Name $prop -Value $($entry | select -exp $prop -ea 0)
}
$results += $obj
}
$results | epcsv C:\temp\file.csv -NoTypeInformation -Encoding ASCII
$results

PowerShell : retrieve JSON object by field value

Consider JSON in this format :
"Stuffs": [
{
"Name": "Darts",
"Type": "Fun Stuff"
},
{
"Name": "Clean Toilet",
"Type": "Boring Stuff"
}
]
In PowerShell 3, we can obtain a list of Stuffs :
$JSON = Get-Content $jsonConfigFile | Out-String | ConvertFrom-Json
Assuming we don't know the exact contents of the list, including the ordering of the objects, how can we retrieve the object(s) with a specific value for the Name field ?
Brute force, we could iterate through the list :
foreach( $Stuff in $JSON.Stuffs ) {
But I am hopeful there exists a more direct mechanism ( similar to Lync or Lambda expressions in C# ).
$json = #"
{
"Stuffs":
[
{
"Name": "Darts",
"Type": "Fun Stuff"
},
{
"Name": "Clean Toilet",
"Type": "Boring Stuff"
}
]
}
"#
$x = $json | ConvertFrom-Json
$x.Stuffs[0] # access to Darts
$x.Stuffs[1] # access to Clean Toilet
$darts = $x.Stuffs | where { $_.Name -eq "Darts" } #Darts
I just asked the same question here: https://stackoverflow.com/a/23062370/3532136
It has a good solution. I hope it helps ^^.
In resume, you can use this:
The Json file in my case was called jsonfile.json:
{
"CARD_MODEL_TITLE": "OWNER'S MANUAL",
"CARD_MODEL_SUBTITLE": "Configure your download",
"CARD_MODEL_SELECT": "Select Model",
"CARD_LANG_TITLE": "Select Language",
"CARD_LANG_DEVICE_LANG": "Your device",
"CARD_YEAR_TITLE": "Select Model Year",
"CARD_YEAR_LATEST": "(Latest)",
"STEPS_MODEL": "Model",
"STEPS_LANGUAGE": "Language",
"STEPS_YEAR": "Model Year",
"BUTTON_BACK": "Back",
"BUTTON_NEXT": "Next",
"BUTTON_CLOSE": "Close"
}
Code:
$json = (Get-Content "jsonfile.json" -Raw) | ConvertFrom-Json
$json.psobject.properties.name
Output:
CARD_MODEL_TITLE
CARD_MODEL_SUBTITLE
CARD_MODEL_SELECT
CARD_LANG_TITLE
CARD_LANG_DEVICE_LANG
CARD_YEAR_TITLE
CARD_YEAR_LATEST
STEPS_MODEL
STEPS_LANGUAGE
STEPS_YEAR
BUTTON_BACK
BUTTON_NEXT
BUTTON_CLOSE
Thanks to mjolinor.
David Brabant's answer led me to what I needed, with this addition:
x.Stuffs | where { $_.Name -eq "Darts" } | Select -ExpandProperty Type
Hows about this:
$json=Get-Content -Raw -Path 'my.json' | Out-String | ConvertFrom-Json
$foo="TheVariableYourUsingToSelectSomething"
$json.SomePathYouKnow.psobject.properties.Where({$_.name -eq $foo}).value
which would select from json structured
{"SomePathYouKnow":{"TheVariableYourUsingToSelectSomething": "Tada!"}
This is based on this accessing values in powershell SO question
. Isn't powershell fabulous!
In regards to PowerShell 5.1 ...
Operating off the assumption that we have a file named jsonConfigFile.json with the following content from your post:
{
"Stuffs": [
{
"Name": "Darts",
"Type": "Fun Stuff"
},
{
"Name": "Clean Toilet",
"Type": "Boring Stuff"
}
]
}
This will create an ordered hashtable from a JSON file to help make retrieval easier:
$json = [ordered]#{}
(Get-Content "jsonConfigFile.json" -Raw | ConvertFrom-Json).PSObject.Properties |
ForEach-Object { $json[$_.Name] = $_.Value }
$json.Stuffs will list a nice hashtable, but it gets a little more complicated from here. Say you want the Type key's value associated with the Clean Toilet key, you would retrieve it like this:
$json.Stuffs.Where({$_.Name -eq "Clean Toilet"}).Type
It's a pain in the ass, but if your goal is to use JSON on a barebones Windows 10 installation, this is the best way to do it as far as I've found.
This is my json data:
[
{
"name":"Test",
"value":"TestValue"
},
{
"name":"Test",
"value":"TestValue"
}
]
Powershell script:
$data = Get-Content "Path to json file" | Out-String | ConvertFrom-Json
foreach ($line in $data) {
$line.name
}