How to iterate through a unknown JSON data/object? - json

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.

Related

How to convert XML into a PsCustomObject to allow final export as JSON?

I am looking for a Powershell function to convert XML into a PsCustomObject which can finally exported as JSON. For this I created this small XML Test object:
[xml]$Xml = #"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"#
This gives my an XML DocumentElement which I finally need to convert into the same object like the one from this call:
$Json = convertfrom-json #"
{
"Action": {
"name": "Test", "id": "1", "Text": "sample",
"sub": [
{"name": "s1","id": "2"},
{"name": "s2","id": "3"}
],
"End": {"details": "no"}
}
}
"#
Is there any smart way to get this done? I tested multiple functions from similar questions here but nothing really works as expected.
Because of the ambiguities, there is no standard way of converting XML to JSON. So you really have to roll your own function that interprets the XML in the way that matches your desired output.
Here is a generic solution:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
# Create an ordered hashtable
$ht = [ordered] #{}
# Copy the XML attributes to the hashtable
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
$node.ChildNodes.ForEach{
if( $_.FirstChild -is [xml.XmlText] ) {
# Add content of XML text node
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value $_.FirstChild.InnerText
}
elseif( $_ -is [xml.XmlElement] ) {
# Add nested hashtable for the XML child elements (recursion)
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value (ConvertFrom-MyXml $_)
}
}
$ht # Output
}
Function Add-DictionaryArrayItem( $Dict, $Key, $Value ) {
if( $Dict.Contains( $Key ) ) {
$curValue = $Dict[ $Key ]
# If existing value is not already a list...
if( $curValue -isnot [Collections.Generic.List[object]] ) {
# ...turn it into a list.
$curValue = [Collections.Generic.List[object]] #($curValue)
$Dict[ $Key ] = $curValue
}
# Add next value to the array. This updates the array in the hashtable,
# because $curValue is a reference.
$curValue.Add( $Value )
}
else {
# Key doesn't exist in the hashtable yet, so simply add it.
$Dict[ $Key ] = $Value
}
}
[xml]$Xml = #"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"#
ConvertFrom-MyXml $Xml | ConvertTo-Json -Depth 100
Output:
{
"Action": {
"name": "Test",
"id": "1",
"Text": "sample",
"sub": [
{
"name": "s1",
"id": "2"
},
{
"name": "s2",
"id": "3"
}
],
"end": {
"details": "no"
}
}
}
Function ConvertFrom-MyXml outputs an ordered hashtable. There is no need to convert to PSCustomObject as ConvertFrom-Json works with hashtables as well. So we can keep the code simpler.
ConvertFrom-MyXml loops over attributes and elements (recursively) of the given XML node. It calls the helper function Add-DictionaryArrayItem to create an array if a key already exists in the hashtable. Actually this is not a raw, fixed-size array (like #(1,2,3) creates), but a dynamically resizable List, which behaves very similar to an array but is much more efficient when adding many elements.
Note that a single sub element won't be turned into an array. If some elements should always be converted to arrays, you'd have to pass some kind of schema to the function (e. g. a list of element names) or add metadata to the XML itself.
As suggested by OP, here is an alternative version of the code, that consists of only a single function:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
$ht = [ordered] #{}
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
foreach( $child in $node.ChildNodes ) {
$key = $child.LocalName
$value = if( $child.FirstChild -is [xml.XmlText] ) {
$child.FirstChild.InnerText
} elseif( $child -is [xml.XmlElement] ) {
ConvertFrom-MyXml $child
} else {
continue
}
if( $ht.Contains( $Key ) ) {
$curValue = $ht[ $Key ]
if( $curValue -isnot [Collections.Generic.List[object]] ) {
$curValue = [Collections.Generic.List[object]] #($curValue)
$ht[ $Key ] = $curValue
}
$curValue.Add( $Value )
}
else {
$ht[ $Key ] = $Value
}
}
$ht # Output
}
Might not be exactly what you're looking for but I would personally do this with classes:
class Sub {
[string] $Name
[Int] $Id
Sub([string] $Name, [int] $Id) {
$this.Name = $Name
$this.Id = $Id
}
}
# Windows PowerShell will not like it named End :)
class End2 {
[string] $Details
End2 ([string] $Details) {
$this.Details = $Details
}
}
class Action {
[string] $Name
[int] $Id
[string] $Text
[Sub[]] $Sub
[End2] $End
Action () { }
Action ([string] $Name, [int] $Id, [string] $Text, [object[]] $Sub, [End2] $End) {
$this.Name = $Name
$this.Id = $Id
$this.Text = $Text
$this.Sub = #( $Sub )
$this.End = $End
}
[string] ToJson() {
return #{ Action = $this } | ConvertTo-Json -Depth 99
}
}
Now you can instantiate and convert to to Json your Action class like this:
[Action]::new(
'Test', 1, 'Sample',
#(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
),
'No'
).ToJson()
Or like this:
([Action]#{
Name = 'Test'
Id = 1
Text = 'Sample'
Sub = #(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
)
End = 'No'
}).ToJson()
Both would output the following Json:
{
"Action": {
"Name": "Test",
"Id": 1,
"Text": "Sample",
"Sub": [
{
"Name": "s1",
"Id": 2
},
{
"Name": "s2",
"Id": 3
}
],
"End": {
"Details": "No"
}
}
}
Look at this
may help
class sub {
[string] $name;
[int] $id;
}
class end {
[string] $details;
}
class Action {
[string] $Text;
[sub] $sub1;
[sub] $sub2;
[end] $end;
[string] $name;
[int] $id;
}
<#
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
#>
$firstitem = [Action]#{
text = 'sample';
name = "test";
id = "1";
sub1=#{
name = "s1";
id = "2";}
sub2 = #{
name = "s2";
id = "3";}
end = #{
details = "no";}
}
$firstitem | ConvertTo-Json
<#
Output =
{
"Text": "sample",
"sub1": {
"name": "s1",
"id": 2
},
"sub2": {
"name": "s2",
"id": 3
},
"end": {
"details": "no"
},
"name": "test",
"id": 1
}
#>

Filter out all occurrences of given properties from json object

I'm using PowerShell to extract data from an API call, update it and then pass it back to the API.
What I would like to know is whether or not there is a simple way to modify the JSON object, to filter out all the properties which are not desired at any location within the JSON structure?
I've tried the following, however the resultant JSON only has the lowest level properties removed (ie. "p2")
$example = ConvertFrom-Json '{"a":{"p1": "value1"},"p2": "value2", "b":"valueb"}'
$exclude = "p1", "p2"
$clean = $example | Select-Object -Property * -ExcludeProperty $exclude
ConvertTo-Json $clean -Compress
Result => {"a":{"p1":"value1"},"b":"valueb"}
I would like to have all $exlude entries removed, regardless of where they are located within the JSON. Is there a simple solution?
Update
Here is another (more complicated) JSON example:
{
"a": {
"p1": "value 1",
"c": "value c",
"d": {
"e": "value e",
"p2": "value 3"
},
"f": [
{
"g": "value ga",
"p1": "value 4a"
},
{
"g": "value gb",
"p1": "value 4b"
}
]
},
"p2": "value 2",
"b": "value b"
}
The expected result (all p1 and p2 keys removed):
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": [
{
"g": "value ga"
},
{
"g": "value gb"
}
]
},
"b": "value b"
}
Unfortunately there doesn't appear to be an easy way. It actually proved quite challenging to correctly handle arrays. My approach is to recursively unroll the input (JSON) object, including any arrays, so we can easily apply filtering, then build a new object from the filtered properties.
Steps one and three are wrapped in the following reusable helper functions, one for unroll (ConvertTo-FlatObjectValues) and one for rebuilding the object (ConvertFrom-FlatObjectValues). There is a third function (ConvertFrom-TreeHashTablesToArrays), but it is only used internally by ConvertFrom-FlatObjectValues.
Function ConvertTo-FlatObjectValues {
<#
.SYNOPSIS
Unrolls a nested PSObject/PSCustomObject "property bag".
.DESCRIPTION
Unrolls a nested PSObject/PSCustomObject "property bag" such as created by ConvertFrom-Json into flat objects consisting of path, name and value.
Fully supports arrays at the root as well as for properties and nested arrays.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline)] $InputObject,
[string] $Separator = '.',
[switch] $KeepEmptyObjects,
[switch] $KeepEmptyArrays,
[string] $Path, # Internal parameter for recursion.
[string] $Name # Internal parameter for recursion.
)
process {
if( $InputObject -is [System.Collections.IList] ) {
if( $KeepEmptyArrays ) {
# Output a special item to keep empty array.
[PSCustomObject]#{
Path = ($Path, "#").Where{ $_ } -join $Separator
Name = $Name
Value = $null
}
}
$i = 0
$InputObject.ForEach{
# Recursively unroll array elements.
$childPath = ($Path, "#$i").Where{ $_ } -join $Separator
ConvertTo-FlatObjectValues -InputObject $_ -Path $childPath -Name $Name `
-Separator $Separator -KeepEmptyObjects:$KeepEmptyObjects -KeepEmptyArrays:$KeepEmptyArrays
$i++
}
}
elseif( $InputObject -is [PSObject] ) {
if( $KeepEmptyObjects ) {
# Output a special item to keep empty object.
[PSCustomObject]#{
Path = $Path
Name = $Name
Value = [ordered] #{}
}
}
$InputObject.PSObject.Properties.ForEach{
# Recursively unroll object properties.
$childPath = ($Path, $_.Name).Where{ $_ } -join $Separator
ConvertTo-FlatObjectValues -InputObject $_.Value -Path $childPath -Name $_.Name `
-Separator $Separator -KeepEmptyObjects:$KeepEmptyObjects -KeepEmptyArrays:$KeepEmptyArrays
}
}
else {
# Output scalar
[PSCustomObject]#{
Path = $Path
Name = $Name
Value = $InputObject
}
}
}
}
function ConvertFrom-FlatObjectValues {
<#
.SYNOPSIS
Convert a flat list consisting of path and value into tree(s) of PSCustomObject.
.DESCRIPTION
Convert a flat list consisting of path and value, such as generated by ConvertTo-FlatObjectValues, into tree(s) of PSCustomObject.
The output can either be an array (not unrolled) or a PSCustomObject, depending on the structure of the input data.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipelineByPropertyName)] [string] $Path,
[Parameter(Mandatory, ValueFromPipelineByPropertyName)] [AllowNull()] $Value,
[Parameter()] [string] $Separator = '.'
)
begin {
$tree = [ordered]#{}
}
process {
# At first store everything (including array elements) into hashtables.
$branch = $Tree
do {
# Split path into root key and path remainder.
$key, $path = $path.Split( $Separator, 2 )
if( $path ) {
# We have multiple path components, so we may have to create nested hash table.
if( -not $branch.Contains( $key ) ) {
$branch[ $key ] = [ordered] #{}
}
# Enter sub tree.
$branch = $branch[ $key ]
}
else {
# We have arrived at the leaf -> set its value
$branch[ $key ] = $value
}
}
while( $path )
}
end {
# So far we have stored the original arrays as hashtables with keys like '#0', '#1', ... (possibly non-consecutive).
# Now convert these hashtables back into actual arrays and generate PSCustomObject's from the remaining hashtables.
ConvertFrom-TreeHashTablesToArrays $tree
}
}
Function ConvertFrom-TreeHashTablesToArrays {
<#
.SYNOPSIS
Internal function called by ConvertFrom-FlatObjectValues.
.DESCRIPTION
- Converts arrays stored as hashtables into actual arrays.
- Converts any remaining hashtables into PSCustomObject's.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline)] [Collections.IDictionary] $InputObject
)
process {
# Check if $InputObject has been generated from an array.
$isArray = foreach( $key in $InputObject.Keys ) { $key.StartsWith('#'); break }
if( $isArray ) {
# Sort array indices as they might be unordered. A single '#' as key will be skipped, because it denotes an empty array.
$sortedByKeyNumeric = $InputObject.GetEnumerator().Where{ $_.Key -ne '#' } |
Sort-Object { [int]::Parse( $_.Key.SubString( 1 ) ) }
$outArray = $sortedByKeyNumeric.ForEach{
if( $_.Value -is [Collections.IDictionary] ) {
# Recursion. Output array element will either be an object or a nested array.
ConvertFrom-TreeHashTablesToArrays $_.Value
}
else {
# Output array element is a scalar value.
$_.Value
}
}
, $outArray # Comma-operator prevents unrolling of the array, to support nested arrays.
}
else {
# $InputObject has been generated from an object. Copy it to $outProps recursively and output as PSCustomObject.
$outProps = [ordered] #{}
$InputObject.GetEnumerator().ForEach{
$outProps[ $_.Key ] = if( $_.Value -is [Collections.IDictionary] ) {
# Recursion. Output property will either be an object or an array.
ConvertFrom-TreeHashTablesToArrays $_.Value
}
else {
# Output property is a scalar value.
$_.Value
}
}
[PSCustomObject] $outProps
}
}
}
Usage example:
$example = ConvertFrom-Json #'
{
"a": {
"p1": "value 1",
"c": "value c",
"d": {
"e": "value e",
"p2": "value 3"
},
"f": [
{
"g": "value ga",
"p1": "value 4a"
},
{
"g": "value gb",
"p1": "value 4b"
}
]
},
"p2": "value 2",
"b": "value b"
}
'#
$exclude = "p1", "p2"
$clean = ConvertTo-FlatObjectValues $example | # Step 1: unroll properties
Where-Object Name -notin $exclude | # Step 2: filter
ConvertFrom-FlatObjectValues # Step 3: rebuild object
$clean | ConvertTo-Json -Depth 9
Output:
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": [
{
"g": "value ga"
},
{
"g": "value gb"
}
]
},
"b": "value b"
}
Usage Notes:
Child objects are removed if they don't contain any properties after filtering. Empty arrays are removed as well. You can prevent this by passing -KeepEmptyObjects and/or -KeepEmptyArrays to function ConvertTo-FlatObjectValues.
If the input JSON is an array at the root level, make sure to pass it as an argument to ConvertTo-FlatObjectValues, instead of piping it (which would unroll it and the function would no longer know it's an array).
Filtering can also be done on the whole path of a property. E. g. to remove the P1 property only within the a object, you could write Where-Object Path -ne a.p1. To see how paths look like, just call ConvertTo-FlatObjectValues $example which outputs the flat list of properties and array elements:
Path Name Value
---- ---- -----
a.p1 p1 value 1
a.c c value c
a.d.e e value e
a.d.p2 p2 value 3
a.f.#0.g g value ga
a.f.#0.p1 p1 value 4a
a.f.#1.g g value gb
a.f.#1.p1 p1 value 4b
p2 p2 value 2
b b value b
Implementation Notes:
During unrolling ConvertTo-FlatObjectValues creates separate path segments (keys) for array elements which look like "#n" where n is the array index. This allows us to treat arrays and objects more uniformly, when rebuilding the object in ConvertFrom-FlatObjectValues.
ConvertFrom-FlatObjectValues first creates nested hashtables for all objects and arrays in its process section. This makes it easy to recollect properties into their respective objects. In this part of the code there is still no special treatment of arrays. The intermediate result now looks like this:
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": {
"#0": {
"g": "value ga"
},
"#1": {
"g": "value gb"
}
}
},
"b": "value b"
}
Only in the end section of ConvertFrom-FlatObjectValues, the arrays are rebuilt from the hashtables, which is done by function ConvertFrom-TreeHashTablesToArrays. It turns hashtables that have keys starting with "#" back into actual arrays. Due to filtering, the indices might be non-consecutive, so we could just collect the values and ignore the indices. Though not necessary for the given use case, the array indices will be sorted to make the function more robust and support indices that are received in any order.
Recursion in PowerShell functions is comparatively slow, because of the parameter-binding overhead. If performance is paramount, the code should be rewritten in inline C# or use data structures like Collections.Queue to avoid recursion (at the expense of code readability).

Appending to an array in json file using powershell script is giving error

{
"$schema": "a",
"contentVersion": "b",
"extensions": [
{
"Name": "c",
"Type": "d",
"Version": "e",
"ConnectionProperties": {
"MaxExecutionTime": "f",
"Authentication": {
"Type": "g",
"Reference": {
"Provider": "h",
"Parameters": {
"SecretId": "i"
}
},
"Properties": {
"ApplicationId": "j",
"TenantId": "k"
}
}
},
"payloadProperties": {
"ConnectionString": {
"Value": "l"
},
"KqlSasUri": {
"reference": {
"path": "m",
"enableScopeTagBindings": "n"
}
},
"DatabaseName": {
"Value": "o"
}
},
"repeatOver": [
{
"name": "p",
"file": "q",
"database": "r"
}
]
}
]
}
Above is the json file, I wish to append to repeatOver array using powershell script
$getContentfromDestinationJson = Get-Content $pathToDestinationJson -Raw | ConvertFrom-Json
$destinationExtension = $getContentfromDestinationJson.extensions
Write-Host $destinationExtension
Output is --
#{Name=a; Type=b; Version=c; ConnectionProperties=; payloadProperties=; repeatOver=System.Object[]}
Also, when I try to write append to this repeatOver array in this json.
Note- the below code is in a for loop, I want to append this multiple times to the array..
for ($i=0; $i -le 3; $i++) {
$toWrite= [PSCustomObject]#{
name = 'd'
file = 'e'
database = 'f'
}
$destinationExtension.repeatOver += (ConvertTo-Json -InputObject $toWrite -Depth 3)
}
I see this error :
Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'.
Also, how do I skip adding a $toWrite value if it already exists, by comparing the name field?
You would need to access the psobject Properties to update that property, I would love to see if there is an easier way of doing this.
Assuming I have the JSON stored in the $json variable, if I try to update .extensions.repeatOver:
PS /> $json.extensions.repeatOver
name file database
---- ---- --------
p q r
PS /> $json.extensions.repeatOver = #()
The property 'repeatOver' cannot be found on this object. Verify that the property exists and can be set.
At line:1 char:1
+ $json.extensions.repeatOver = #()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
To update it you can do it like this:
# Here I'm appending the value from repeatOver with random data
$toAppend = #(
$json.extensions.repeatOver
for($i=0; $i -le 3; $i++)
{
[PSCustomObject]#{
name = Get-Random -Maximum 9
file = Get-Random -Maximum 9
database = Get-Random -Maximum 9
}
}
)
$json.psobject.Properties.where({ $_.Name -eq 'extensions' }).Value.repeatOver = $toAppend
Testing if it works:
PS /> $json.extensions
Name : c
Type : d
Version : e
ConnectionProperties : #{MaxExecutionTime=f; Authentication=}
payloadProperties : #{ConnectionString=; KqlSasUri=; DatabaseName=}
repeatOver : {#{name=p; file=q; database=r}, #{name=3; file=4; database=2}, #{name=5; file=3; database=6}, #{name=1; file=0; database=7}...}
PS /> $json.extensions.repeatOver
name file database
---- ---- --------
p q r
3 4 2
5 3 6
1 0 7
6 3 8
I think this is also relevant: https://github.com/PowerShell/PowerShell/issues/3159
Since the extensions is also an array, you need to loop over that to append your object array to the repeatOver array.
# read the json file and convert it
$json = Get-Content -Path 'Path\To\The\JSON_file.json' -Raw | ConvertFrom-Json
# create your new object array
$toWrite = for ($i=0; $i -le 3; $i++) {
[PSCustomObject]#{
name = "d$i"
file = "e$i"
database = "f$i"
}
}
# loop over the extensions array and append to repeatOver
$json.extensions | ForEach-Object { $_.repeatOver += $toWrite }
$json | ConvertTo-Json -Depth 6 # | Set-Content -Path 'Path\To\The\Extended_JSON_file.json'
P.S. PowerShell does not produce 'pretty' json. If you need to convert it to properly spaced json, see my function Format-Json

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": [ ... ] }'

How to increment a key value pair in JSON file

I have a JSON file that I would need a certain value to be incremented. Here is the JSON file structure I have.
{
"Body": {
"Content": {
},
"Lines": [{
"LineNumber": "1",
"DateOfService": "10/20/2017"
},
{
"LineNumber": "1",
"DateOfService": "10/20/2017"
},
{
"LineNumber": "1",
"DateOfService": "10/20/2017"
}]
}
}
I want the "LineNumber" values to be set from 1 and incremented by 1 subsequently. I have close to a 1000 lines.
Thanks for your assistance.
$InputFile = "path\name.json.txt"
$OutPutFile = "path\name.new.json"
$objJsonFile = Get-Content -Raw -Path $InputFile | ConvertFrom-Json
$intLine = 1
foreach ($itmLine in $objJsonFile.Claim.Lines)
{
$itmLine.LineNumber = [string]$intLine++
}
$objJsonFile | ConvertTo-Json -Depth 3 | Out-File $OutPutFile
You could try to do so using the following code.
$fileContent = Get-Content PATH\TO\FILE.json;
$json = $fileContent | ConvertFrom-Json;
$counter = 1;
ForEach($line in $json.Body.Lines) {
$line.LineNumber = $counter;
$counter++;
}
# write json back to file!?