1

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 :)

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This kind of explanation takes time but is so so helpful. Thanks for the elaboration!
0

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

1 Comment

It's works, thank you ! I guess I can make more simply but like I sayed I'm not gifted w/ PS ^^

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.