I have some difficulties to understand how works JSON in PowerShell... I want to create and implement a JSON but I think I do something wrong.
This code not works :
$json = #"
{
"Volume" : [
]
}
"# | ConvertFrom-Json | Select-Object -Expand Volume
foreach ($i in 0..2) {
$blockvalue = #"
{ "UUID" : "uuid-$($i)",
"Details" : [ { "Name" : "Name-$($i)" }, { "SVM" : "SVM-$($i) " }, { "LastSnapshot" : "snap-$($i)" }, { "Date" : "date-$($i) " } ] }
"#
$json += (ConvertFrom-Json -InputObject $blockvalue)
}
$json | Select UUID,#{Name="Volume";E={$_.Details | Select -Expand Name}},#{Name="SVM";E={$_.Details | Select -Expand SVM}},#{Name="Date";E={$_.Details | Select -Expand Date}},#{Name="LastSnapshot";E={$_.Details | Select -Expand LastSnapshot}} | FT
Output :
Method invocation failed because [System.Management.Automation.PSObject] does
not contain a method named 'op_Addition'.
At line:14 char:5
+ $json += (ConvertFrom-Json -InputObject $blockvalue)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], Runtime
Exception
+ FullyQualifiedErrorId : MethodNotFound
Method invocation failed because [System.Management.Automation.PSObject] does
not contain a method named 'op_Addition'.
At line:14 char:5
+ $json += (ConvertFrom-Json -InputObject $blockvalue)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], Runtime
Exception
+ FullyQualifiedErrorId : MethodNotFound
UUID Volume SVM Date LastSnapshot
---- ------ --- ---- ------------
uuid-0 Name-0 SVM-0 date-0 snap-0
So I find a "solution", I use this next code, it's work but it's not clean (and the worst it's idk why it's works) :
$json2 = #"
{
"Volume" : [
{},
{}
]
}
"# | ConvertFrom-Json | Select-Object -Expand Volume
foreach ($i in 0..2) {
$blockvalue = #"
{ "UUID" : "uuid-$($i)",
"Details" : [ { "Name" : "Name-$($i)" }, { "SVM" : "SVM-$($i) " }, { "LastSnapshot" : "snap-$($i)" }, { "Date" : "date-$($i) " } ] }
"#
$json2 += (ConvertFrom-Json -InputObject $blockvalue)
}
$json2 | Select UUID,#{Name="Volume";E={$_.Details | Select -Expand Name}},#{Name="SVM";E={$_.Details | Select -Expand SVM}},#{Name="Date";E={$_.Details | Select -Expand Date}},#{Name="LastSnapshot";E={$_.Details | Select -Expand LastSnapshot}} | FT
Output :
UUID Volume SVM Date LastSnapshot
---- ------ --- ---- ------------
uuid-0 Name-0 SVM-0 date-0 snap-0
uuid-1 Name-1 SVM-1 date-1 snap-1
uuid-2 Name-2 SVM-2 date-2 snap-2
See what I'm expected :
UUID Volume SVM Date LastSnapshot
---- ------ --- ---- ------------
uuid-0 Name-0 SVM-0 date-0 snap-0
uuid-1 Name-1 SVM-1 date-1 snap-1
uuid-2 Name-2 SVM-2 date-2 snap-2
I'm sure that it easy to solve but I not gifted with PS...
Thanks by advance for your help :)
It's generally a bad practice to use += to append an array. This approach causes a new array to be created. The contents of the original plus the right operand will be copied to the new array. For small jobs this is no big deal, but with larger data sets it causes exponential performance degredation.
For anything other than quick POC or console type work, I advise you to avoid using += on arrays . The most common approach and usually the fastest is to simply allow PowerShell to accumulate the output for you. An adjustment to Bernard's fine answer :
$json2 =
foreach ($i in 0..2) {
#"
{ "UUID" : "uuid-$($i)",
"Details" : [ { "Name" : "Name-$($i)" }, { "SVM" : "SVM-$($i) " }, { "LastSnapshot" : "snap-$($i)" }, { "Date" : "date-$($i) " } ] }
"# | ConvertFrom-Json
}
$json2 |
Select-Object UUID,
#{ Name = "Volume"; Expression = { $_.Details | Select-Object -ExpandProperty Name } },
#{ Name = "SVM"; Expression = { $_.Details | Select-Object -ExpandProperty SVM } },
#{ Name = "Date"; Expression = { $_.Details | Select-Object -ExpandProperty Date } },
#{ Name = "LastSnapshot"; Expression = { $_.Details | Select-Object -ExpandProperty LastSnapshot } } |
Format-Table
I wanted to suggest a little more syntax sugar; normally you don't need to repeatedly invoke Select-Object -ExpandProperty ... on flat strings. That section of code could look more like
$json2 |
Select-Object UUID,
#{ Name = "Volume"; Expression = { $_.Details.Name } },
#{ Name = "SVM"; Expression = { $_.Details.SVM } },
#{ Name = "Date"; Expression = { $_.Details.Date } },
#{ Name = "LastSnapshot"; Expression = { $_.Details.LastSnapshot } } |
Format-Table
However, this was generating unusual results. Unrolling the properties like above was resulting in arrays like Name-0, Null, Null, Null. I traced that back to the JSON text/structure . I'm not sure it was your intention, but the resulting objects were structured like:
#{UUID=uuid-0; Details=System.Object[]}
|- UUID = uuid-0
| |- Length = 6
|- Details
| |- Details[0] = #{Name=Name-0}
| | |- Name = Name-0
| |- Details[1] = #{SVM=SVM-1}
| | |- SVM = SVM-1
| |- Details[2] = #{LastSnapShot=LastSnapShot-2}
| | |- LastSnapShot = LastSnapShot-2
| |- Details[3] = #{Date=Date-3}
| |- Date = Date-3
The Details property is an object array containing a series of more objects each with a single property, respectively Name, SVM, etc... I think the intention may have been to have Details be an object with Name, SVM, LastSnapShot & Date as properties. If that's correct the JSON creation might look more like below, where there's only 1 outer set of curly braces.
$json2 =
ForEach( $i in 0..2 ) {
#"
{ "UUID" : "uuid-$($i)",
"Details" : [ { "Name" : "Name-$($i)", "SVM" : "SVM-$($i) ", "LastSnapshot" : "snap-$($i)", "Date" : "date-$($i) " } ] }
"# | ConvertFrom-Json
}
$json2 |
Select-Object UUID,
#{ Name = "Volume"; Expression = { $_.Details.Name } },
#{ Name = "SVM"; Expression = { $_.Details.SVM } },
#{ Name = "Date"; Expression = { $_.Details.Date } },
#{ Name = "LastSnapshot"; Expression = { $_.Details.LastSnapshot } } |
Format-Table
In this case the more concise and probably faster property unrolling syntax can be used.
Apart from the complexity of the script you are using, simply declare an array so items can be added to it:
$json2 = #()
foreach ($i in 0..2) {
$blockvalue = #"
{ "UUID" : "uuid-$($i)",
"Details" : [ { "Name" : "Name-$($i)" }, { "SVM" : "SVM-$($i) " }, { "LastSnapshot" : "snap-$($i)" }, { "Date" : "date-$($i) " } ] }
"#
$json2 += (ConvertFrom-Json -InputObject $blockvalue)
}
$json2 |
Select-Object UUID,
#{ Name = "Volume"; Expression = { $_.Details | Select-Object -Expand Name } },
#{ Name = "SVM"; Expression = { $_.Details | Select-Object -Expand SVM } },
#{ Name = "Date"; Expression = { $_.Details | Select-Object -Expand Date } },
#{ Name = "LastSnapshot"; Expression = { $_.Details | Select-Object -Expand LastSnapshot } } |
Format-Table
Related
I have a JSON file with the below given sample structure. How can I convert this into CSV and get the content of CSV as the below given expected output?
{
"code":"A123",
"name":"ABC",
"parties":[
{
"businessTeam":{
"code":"B123",
"name":"Plaza"
},
"TotalNumber":"1000"
},
{
"businessTeam":{
"code":"B125",
"name":"Marina"
},
"TotalNumber":"2000"
},
{
"businessTeam":{
"code":"B130",
"name":"Marriot"
},
"TotalNumber":"2500"
}
]
}
Expected Output:
Code, Name,BusinessPartyCode,BusinessPartyName,Capacity
A123,ABC,B123,Plaza,1000
A123,ABC,B125,Marina,2000
A123,ABC,B130,Marriot,2500
I have tied with the below script and was able to extract the array values as a single delimiter concatenated values.
$deploy = Get-Content 'C:\psscripts\sample.json' -Raw | ConvertFrom-Json
$items = #()
foreach ($server in $deploy) {
foreach ($item in $server) {
$items += New-Object -TypeName PSObject -Property (
[ordered]#{
code = #($item.Code) -replace '"','#' -join '~'
businessparty = #($item.parties.businessteam.code) -join '-'
businesspartyName = #($item.parties.businessteam.name) -join '-'
Capacity = #($item.parties.businessteamtotalnumber) -join '-'
}
)
}
}
$items
-> output A123,ABC,B123-B125-B130,Plaza-Marina-Marriot,1000-2000-2500
Regards,
Sandeep
You're missing an inner loop to expand the values of businessTeam:
Get-Content 'C:\psscripts\sample.json' -Raw | ConvertFrom-Json | ForEach-Object {
foreach($item in $_.parties) {
foreach($team in $item.businessTeam) {
[pscustomobject]#{
Code = $_.code
Name = $_.name
BusinessPartyCode = $team.code
BusinessPartyName = $team.name
Capacity = $item.TotalNumber
}
}
}
} | Format-Table
Using the Json in question, the array of objects generated using this code would be:
Code Name BusinessPartyCode BusinessPartyName Capacity
---- ---- ----------------- ----------------- --------
A123 ABC B123 Plaza 1000
A123 ABC B125 Marina 2000
A123 ABC B130 Marriot 2500
I have a json structure in a file my.json that looks similar to below:
{
"key1":{
"key1A":{
"someKey":"someValue"
},
"key1B":{
"someKey":"someValue"
}
},
"key2":{
"key2A":{
"someKey":"someValue"
},
"key2B":{
"someKey":"someValue"
}
},
"key3":{
"key3A":{
"someKey":"someValue"
},
"key3B":{
"someKey":"someValue"
}
}
}
Using powershell I would like to search for "node" key1B and select it. The assumptions are
key1B only occurs once in the whole tree
The search term (key1B) can either be a root element or a child of a root element.
If I were to know the parent under which node key1B is I could use below:
Get-Content -Raw my.json | ConvertFrom-Json | Select-Object -ExpandProperty key1 | Select-Object -ExpandProperty key1B
How can I make above select generic so that the node I'm searching for can be either in the root or a child of the root?
# convert as a Hashtable
$json = Get-Content -Raw .\my.json | ConvertFrom-Json -AsHashtable
# a root element
$json.key1B
# a child of a root element
$json.Values.key1B
# descendant
function findByKey {
param($json, $key)
if ($json.$key) { $json.$key }
else {
$json.Values | ? values | % { findByKey $_ $key } | select -First 1
}
}
findByKey $json "key1B"
jq has a recursive descent .. operator that can search all the keys like xpath //.
get-content file.json | jq '.. | .key1B? | select(. != null)'
{
"someKey1b": "someValue1b"
}
You can find Key1A or whatever key you are looking for by looking at the definition column of Get-Member.
Let's define your JSON As variable $TestJson:
$testJson = #"
{
"key1":{
"key1A":{
"someKey":"someValue"
},
"key1B":{
"someKey":"someValue"
}
},
"key2":{
"key2A":{
"someKey":"someValue"
},
"key2B":{
"someKey":"someValue"
}
},
"key3":{
"key3A":{
"someKey":"someValue"
},
"key3B":{
"someKey":"someValue"
}
}
}
"#
$testJson = $testJson | ConvertFrom-Json
We are looking for Key1A in $testJson which we do not know is under the parent node key1, we can do this by looking at the output of $testJson | gm
$testJson | gm
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
key1 NoteProperty System.Management.Automation.PSCustomObject key1=#{key1A=; key1B=}
key2 NoteProperty System.Management.Automation.PSCustomObject key2=#{key2A=; key2B=}
key3 NoteProperty System.Management.Automation.PSCustomObject key3=#{key3A=; key3B=}
We can see here that all of the nodes and their sub-nodes are listed in the definitions tab, with bigger JSONs, we wouldn't be able to see the whole definitions tab with this so we could wither to one of these two things:
$testJson | gm | select-object "Definition"
($testJson | gm).Definition
So if we want to find Key1A we can do
$testJson | gm | ? {$_.Definition -imatch "key1A"}
Which finds the definition in where key1a is in (case-insensitive as specified by -i instead of -c) which gives us the output of
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
key1 NoteProperty System.Management.Automation.PSCustomObject key1=#{key1A=; key1B=}
Where as you can see the parent node is key1 and we can grab that as well with
($testJson | gm | ? {$_.Definition -imatch "key1A"}).name
key1
And to view the content of key1 we can do
$($testJson).$(($testJson | gm | ? {$_.Definition -imatch "key1A"}).name)
key1A key1B
----- -----
#{someKey=someValue} #{someKey=someValue}
And key1a
$($testJson).$(($testJson | gm | ? {$_.Definition -imatch "key1A"}).name).key1a
someKey
-------
someValue
I am new to Powershell so please excuse any errors I may have.
I need to write a Powershell script to convert a JSON variable file to CSV.
I need to iterate through the file and pick out all the variables for Name and Id fields.
Firstly I convert the json file to a String.But I am not sure how to iterate through the json file and pick out any of the Name field items. I then export it to a csv file.
This converts the json file to a String
$data = (Get-Content "C:\Users\QVL6\Downloads\express-ordering-web-
variables.json" | ConvertFrom-Json)
This exports it to a csv file:
$data | Select-Object -Name, Description | Export -Csv -Path .\data.csv
- NoClobber -NoTypeInformation
I need help with a for each loop that will iterate through the file and place any of the Name field values to the csv file under a heading Name.
Below is the first 3 objects of the json file:
{
"Id": "f73bdd3d-0449-036d-c2b6-b5fde280b05f",
"Name": "CIFolderPermissionGroup",
"Description": null,
"Scope": {},
"IsEditable": true,
"Prompt": null,
"Type": "String",
"IsSensitive": false
},
{
"Id": "f138f849-1647-4346-6ac4-cee4bdbd808a",
"Name": "CustomInstallFolder",
"Value": "c:\\inetpub\\wwwroot",
"Description": null,
"Scope": {},
"IsEditable": true,
"Prompt": null,
"Type": "String",
"IsSensitive": false
},
{
"Id": "99d478fb-6ef3-cc21-7997-4a9b12f3ad00",
"Name": "eimasConfiguartion",
"Value": "{\"issuelocal/":true}",
"Description": null,
"Scope": {
"Environment": [
"Environments-63"
]
}
This is my code so far:
$json = (Get-Content "C:\Users\QVL6\Downloads\express-ordering-web-
variables.json" | ConvertFrom-Json)
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMembers {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]#{Key = $key; Value = $obj."$key"}
}
}
#Produce a list of output objects with Name, Type, Value and Description
$ | ConvertFrom-Json | Get-ObjectMembers | foreach {
$_.Value | Get-ObjectMembers | where Key -match "Name" | foreach {
[PSCustomObject]#{
Name = $_.value.data.value | select
Type = $_.Value.data | value | select
Value = $_.Value.data | value | select
Description = $_.Value.data | value | select
}
}
}
$path = C:\Users\QVL6\
$data | Select-ObjectMambers -Property Name, Type, Value, Description |
Export -Csv -Path .\data.csv -NoClobber -NoTypeInformation
I have a JSON file that looks like this:
{
"id": 10011,
"title": "Test procedure",
"slug": "slug",
"url": "http://test.test",
"email": "test#test.com",
"link": "http://test.er",
"subject": "testing",
"level": 1,
"disciplines": [
"discipline_a",
"discipline_b",
"discipline_c"
],
"areas": [
"area_a",
"area_b"
]
},
I was trying to use the following command to convert that into the CSV file:
(Get-Content "PATH_TO\test.json" -Raw | ConvertFrom-Json)| Convertto-CSV -NoTypeInformation | Set-Content "PATH_TO\test.csv"
However, for disciplines and areas I am getting System.Object[] in the resulting CSV file.
Is there a way to put all those nested values as a separate columns in CSV file like area_1, area_2 etc. And the same for disciplines.
2017-11-20, Completely rewrote function to improve performance and add features as -ArrayBase and support for PSStandardMembers and grouped objects.
Flatten-Object
Recursively flattens objects containing arrays, hash tables and (custom) objects. All added properties of the supplied objects will be aligned with the rest of the objects.
Requires PowerShell version 2 or higher.
Cmdlet
Function Flatten-Object { # Version 00.02.12, by iRon
[CmdletBinding()]Param (
[Parameter(ValueFromPipeLine = $True)][Object[]]$Objects,
[String]$Separator = ".", [ValidateSet("", 0, 1)]$Base = 1, [Int]$Depth = 5, [Int]$Uncut = 1,
[String[]]$ToString = ([String], [DateTime], [TimeSpan]), [String[]]$Path = #()
)
$PipeLine = $Input | ForEach {$_}; If ($PipeLine) {$Objects = $PipeLine}
If (#(Get-PSCallStack)[1].Command -eq $MyInvocation.MyCommand.Name -or #(Get-PSCallStack)[1].Command -eq "<position>") {
$Object = #($Objects)[0]; $Iterate = New-Object System.Collections.Specialized.OrderedDictionary
If ($ToString | Where {$Object -is $_}) {$Object = $Object.ToString()}
ElseIf ($Depth) {$Depth--
If ($Object.GetEnumerator.OverloadDefinitions -match "[\W]IDictionaryEnumerator[\W]") {
$Iterate = $Object
} ElseIf ($Object.GetEnumerator.OverloadDefinitions -match "[\W]IEnumerator[\W]") {
$Object.GetEnumerator() | ForEach -Begin {$i = $Base} {$Iterate.($i) = $_; $i += 1}
} Else {
$Names = If ($Uncut) {$Uncut--} Else {$Object.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames}
If (!$Names) {$Names = $Object.PSObject.Properties | Where {$_.IsGettable} | Select -Expand Name}
If ($Names) {$Names | ForEach {$Iterate.$_ = $Object.$_}}
}
}
If (#($Iterate.Keys).Count) {
$Iterate.Keys | ForEach {
Flatten-Object #(,$Iterate.$_) $Separator $Base $Depth $Uncut $ToString ($Path + $_)
}
} Else {$Property.(($Path | Where {$_}) -Join $Separator) = $Object}
} ElseIf ($Objects -ne $Null) {
#($Objects) | ForEach -Begin {$Output = #(); $Names = #()} {
New-Variable -Force -Option AllScope -Name Property -Value (New-Object System.Collections.Specialized.OrderedDictionary)
Flatten-Object #(,$_) $Separator $Base $Depth $Uncut $ToString $Path
$Output += New-Object PSObject -Property $Property
$Names += $Output[-1].PSObject.Properties | Select -Expand Name
}
$Output | Select ([String[]]($Names | Select -Unique))
}
}; Set-Alias Flatten Flatten-Object
Syntax
<Object[]> Flatten-Object [-Separator <String>] [-Base "" | 0 | 1] [-Depth <Int>] [-Uncut<Int>] [ToString <Type[]>]
or:
Flatten-Object <Object[]> [[-Separator] <String>] [[-Base] "" | 0 | 1] [[-Depth] <Int>] [[-Uncut] <Int>] [[ToString] <Type[]>]
Parameters
-Object[] <Object[]>
The object (or objects) to be flatten.
-Separator <String> (Default: .)
The separator used between the recursive property names. .
-Depth <Int> (Default: 5)
The maximal depth of flattening a recursive property. Any negative value will result in an unlimited depth and could cause a infinitive loop.
-Uncut <Int> (Default: 1)
The number of object iterations that will left uncut further object properties will be limited to just the DefaultDisplayPropertySet. Any negative value will reveal all properties of all objects.
-Base "" | 0 | 1 (Default: 1)
The first index name of an embedded array:
1, arrays will be 1 based: <Parent>.1, <Parent>.2, <Parent>.3, ...
0, arrays will be 0 based: <Parent>.0, <Parent>.1, <Parent>.2, ...
"", the first item in an array will be unnamed and than followed with 1: <Parent>, <Parent>.1, <Parent>.2, ...
-ToString <Type[]= [String], [DateTime], [TimeSpan]>
A list of value types (default [String], [DateTime], [TimeSpan]) that will be converted to string rather the further flattened. E.g. a [DateTime] could be flattened with additional properties like Date, Day, DayOfWeek etc. but will be converted to a single (String) property instead.
Note:
The parameter -Path is for internal use but could but used to prefix property names.
Examples
Answering the specific question:
(Get-Content "PATH_TO\test.json" -Raw | ConvertFrom-Json) | Flatten-Object | Convertto-CSV -NoTypeInformation | Set-Content "PATH_TO\test.csv"
Result:
{
"url": "http://test.test",
"slug": "slug",
"id": 10011,
"link": "http://test.er",
"level": 1,
"areas.2": "area_b",
"areas.1": "area_a",
"disciplines.3": "discipline_c",
"disciplines.2": "discipline_b",
"disciplines.1": "discipline_a",
"subject": "testing",
"title": "Test procedure",
"email": "test#test.com"
}
Stress testing a more complex custom object:
New-Object PSObject #{
String = [String]"Text"
Char = [Char]65
Byte = [Byte]66
Int = [Int]67
Long = [Long]68
Null = $Null
Booleans = $False, $True
Decimal = [Decimal]69
Single = [Single]70
Double = [Double]71
Array = #("One", "Two", #("Three", "Four"), "Five")
HashTable = #{city="New York"; currency="Dollar"; postalCode=10021; Etc = #("Three", "Four", "Five")}
Object = New-Object PSObject -Property #{Name = "One"; Value = 1; Text = #("First", "1st")}
} | Flatten
Result:
Double : 71
Decimal : 69
Long : 68
Array.1 : One
Array.2 : Two
Array.3.1 : Three
Array.3.2 : Four
Array.4 : Five
Object.Name : One
Object.Value : 1
Object.Text.1 : First
Object.Text.2 : 1st
Int : 67
Byte : 66
HashTable.postalCode : 10021
HashTable.currency : Dollar
HashTable.Etc.1 : Three
HashTable.Etc.2 : Four
HashTable.Etc.3 : Five
HashTable.city : New York
Booleans.1 : False
Booleans.2 : True
String : Text
Char : A
Single : 70
Null :
Flatting grouped objects:
$csv | Group Name | Flatten | Format-Table # https://stackoverflow.com/a/47409634/1701026
Flatting common objects:
(Get-Process)[0] | Flatten-Object
Or a list (array) of objects:
Get-Service | Flatten-Object -Depth 3 | Export-CSV Service.csv
Note that a command as below takes hours to compute:
Get-Process | Flatten-Object | Export-CSV Process.csv
Why? because it results in a table with a few hundred rows and several thousand columns. So if you if would like to use this for flatting process, you beter limit the number of rows (using the Where-Object cmdlet) or the number of columns (using the Select-Object cmdlet).
For the latest Flatten-Object version, see: https://powersnippets.com/flatten-object/
The CSV conversion/export cmdlets have no way of "flattening" an object, and I may be missing something, but I know of no way to do this with a built-in cmdlet or feature.
If you can guarantee that disciplines and areas will always have the same number of elements, you can trivialize it by using Select-Object with derived properties to do this:
$properties=#('id','title','slug','url','email','link','subject','level',
#{Name='discipline_1';Expression={$_.disciplines[0]}}
#{Name='discipline_2';Expression={$_.disciplines[1]}}
#{Name='discipline_3';Expression={$_.disciplines[2]}}
#{Name='area_1';Expression={$_.areas[0]}}
#{Name='area_2';Expression={$_.areas[1]}}
)
(Get-Content 'PATH_TO\test.json' -Raw | ConvertFrom-Json)| Select-Object -Property $properties | Export-CSV -NoTypeInformation -Path 'PATH_TO\test.csv'
However, I am assuming that disciplines and areas will be variable length for each record. In that case, you will have to loop over the input and pull the highest count value for both disciplines and areas, then build the properties array dynamically:
$inputData = Get-Content 'PATH_TO\test.json' -Raw | ConvertFrom-Json
$counts = $inputData | Select-Object -Property #{Name='disciplineCount';Expression={$_.disciplines.Count}},#{Name='areaCount';Expression={$_.areas.count}}
$maxDisciplines = $counts | Measure-Object -Maximum -Property disciplineCount | Select-Object -ExpandProperty Maximum
$maxAreas = $counts | Measure-Object -Maximum -Property areaCount | Select-Object -ExpandProperty Maximum
$properties=#('id','title','slug','url','email','link','subject','level')
1..$maxDisciplines | % {
$properties += #{Name="discipline_$_";Expression=[scriptblock]::create("`$_.disciplines[$($_ - 1)]")}
}
1..$maxAreas | % {
$properties += #{Name="area_$_";Expression=[scriptblock]::create("`$_.areas[$($_ - 1)]")}
}
$inputData | Select-Object -Property $properties | Export-CSV -NoTypeInformation -Path 'PATH_TO\test.csv'
This code hasn't been fully tested, so it may need some tweaking to work 100%, but I believe the ideas are solid =)
I am extracting a JSON from Facebook, this is what it looks like:
pressions_by_paid_non_paid_unique/day
{
"data": [
{
"name": "page_impressions_by_paid_non_paid_unique",
"period": "day",
"values": [
{
"value": {
"total": 549215,
"unpaid": 549215,
"paid": 0
},
"end_time": "2017-06-02T07:00:00+0000"
},
What I would like is to create a CSV that would either looks like this:
total,unpaid,paid,endtime
549215,549215,0,2017-06-02T07:00:00+0000
or
value,num,end_time
total,549215,2017-06-02T07:00:00+0000
unpaid,549215,2017-06-02T07:00:00+0000
paid,0,2017-06-02T07:00:00+0000
What I came up with is:
$file = "D:\BI_LP\001-Solutions_Sources\script\Powershell\curl\facebook21.json"
Get-Content $file -Raw |
ConvertFrom-Json |
Select -Expand data |
Select -Expand values | % {
$end_time = $_.end_time
$value = $_.value
$_.value | select #{n='end_time';e={$end_time}}, #{n='value';e={$value}}
}
Which gives me:
end_time value
-------- -----
2017-05-21T07:00:00+0000 #{total=608837; unpaid=608837; paid=0}
2017-05-22T07:00:00+0000 #{total=682090; unpaid=682090; paid=0}
2017-05-23T07:00:00+0000 #{total=885274; unpaid=885274; paid=0}
2017-05-24T07:00:00+0000 #{total=810845; unpaid=810845; paid=0}
2017-05-25T07:00:00+0000 #{total=755453; unpaid=755453; paid=0}
2017-05-26T07:00:00+0000 #{total=629096; unpaid=629096; paid=0}
Does anyone have any suggestions?
I think you are almost there. You could try creating the output object a bit like this in the foreach loop:
[pscustomobject]#{
total = $_.value.total
unpaid = $_.value.unpaid
paid = $_.value.paid
end_time = $_.end_time
}
Based on your code:
#"
{
"data": [
{
"name": "page_impressions_by_paid_non_paid_unique",
"period": "day",
"values": [
{
"value": {
"total": 549215,
"unpaid": 549215,
"paid": 0
},
"end_time": "2017-06-02T07:00:00+0000"
}
]
}
]
}
"# | ConvertFrom-Json | Select -Expand data | Select -Expand values | % {
$end_time = $_.end_time
$value = $_.value
$_.value | select #{n='endtime'; e={$value.total}}, #{n='unpaid'; e={$value.unpaid}}, #{n='paid'; e={$value.paid}}, #{n='end_time';e={$end_time}}
} | ft -autosize
Gives the following output:
endtime unpaid paid end_time
------- ------ ---- --------
549215 549215 0 2017-06-02T07:00:00+0000
And to export to csv, change the ft -autosize to Export-Csv -Path c:\...
FYI: Your json sample is missing a lot of closing brackets.
Thanks Charlie, you got me in the right direction :)
$file = "D:\BI_LP\001-Solutions_Sources\script\Powershell\curl\facebook21.json"
Get-Content $file -Raw |
ConvertFrom-Json |
Select -Expand data |
Select -Expand values | % {
$end_time = $_.end_time
$total = $_.value.total
$unpaid = $_.value.unpaid
$paid = $_.value.paid
$_.value | select #{n='end_time';e={$end_time}}, #{n='total';e={$total}},#{n='unpaid';e={$unpaid}},#{n='paid';e={$paid}}
}