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
Related
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
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
My JSON looks like this:
{
"data": [
{
"name": "engagement",
"period": "lifetime",
"values": [
{
"value": 52
}
],
"title": "Engagement",
"description": "Total number of likes and comments on the media object",
"id": "1798601712/insights/engagement/lifetime"
},
{
"name": "impressions",
"period": "lifetime",
"values": [
{
"value": 796
}
],
"title": "Impressions",
"description": "Total number of times the media object has been seen",
"id": "1798601712/insights/impressions/lifetime"
}
]
}
What I managed to achieve at this moment:
"1798601712/insights/engagement/lifetime","engagement","52"
"1798601712/insights/impressions/lifetime","impressions","796"
"1798601712/insights/reach/lifetime","reach","422"
Using the following code:
$Ident = Import-Csv -Path ".\src\Process.txt" -Header $Header |
Select-Object -Skip 2
foreach ($idka in $ident) {
$sid = $idka.id
$request_n = "https://api/"+ $sid +"/data=20190101&file=json"
foreach($dane1 in $request_n) {
Invoke-WebRequest $dane1 |
ConvertFrom-Json |
Select -ExpandProperty data |
Select id, name, #{label = "values";Expression ={$_.values.value}} |
Export-Csv $filename -NoTypeInformation -Append
}
}
I need my csv to look like this:
id engagement impressions reach
1798601712 52 796 422
1786717942 34 428 346
1787997335 29 376 281
1788199840 30 532 439
1788311007 48 1053 867
1788353947 28 609 497
1788403484 43 809 460
After expanding the data array group the nested objects by the ID you extract from the id field. For each group build a hashtable in which you map the values from each nested object to their name property. Create a custom object from the hashtable, then export the result to the output CSV.
...|
Select-Object -Expand data |
Group-Object { $_.id.Split('/')[0] } |
ForEach-Object {
$prop = #{
'id' = $_.Name
}
$_.Group | ForEach-Object {
$prop[$_.name] = $_.values.value
}
New-Object -Type PSObject -Property $prop
} |
Select-Object id, engagement, impressions, reach |
Export-Csv $filename -NoType -Append
Note that with PowerShell v3 or newer you can use an ordered hashtable and the [PSCustomObject] type accelerator instead of New-Object, which would allow you to omit the last Select-Object (whose sole purpose is getting the output fields in the desired order).
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}}
}