weird powershell bug with printing variables and json?

When I run this in a powershell script, $data2 prints out nothing (and I can’t pipe it to where, etc). But if I copy and paste it to the prompt, it works fine (or I run it in another script):

$data1 = (Get-Content ./file1.json | ConvertFrom-Json).data1
$data1

$data2 = (Get-Content ./file2.json | ConvertFrom-Json).data2
$data2

file1.json contains:

{
    "data1": [
      {
        "value1": 6
      }
    ]
}

file2.json contains:

{
    "data2": [
      {
        "value2": 12
      }
    ]
}

script output:

value1
------
     6
      


Yes, this is a weird one I have stumbled across myself, too. It has something to do with how the PowerShell formatting system works under the hood. (see here for more info
How PowerShell Formatting and Outputting REALLY works):
You can get around it by piping your output to Out-Host or Out-Default.

$data1 = (Get-Content c:\users\dirk_bremen\desktop\file1.json | ConvertFrom-Json).data1
$data1 | Out-Host

$data2 = (Get-Content c:\users\dirk_bremen\desktop\file2.json | ConvertFrom-Json).data2
$data2

I think this is a simpler version of it. Apparently you can’t output or process more than once type of object in the same script:

$var1 = New-Object PSObject -Prop @{data1=6}
$var1
$var2 = New-Object PSObject -Prop @{data2=12}
$var2


data1
------
6
$var1 = New-Object PSObject -Prop @{data1=6}
$var1 | Out-Host
$var2 = New-Object PSObject -Prop @{data2=12}
$var2 | Out-Host

Here’s a weirder example. Powershell just seems to keep a list of properties for each script, and only lets those out:

$var1 = New-Object PSObject -prop @{data1=6;data3=5}
$var1
$var2 = New-Object PSObject -prop @{data2=12;data3=6}
$var2


data1 data3
----- -----
    6     5
          6

You should really take a look at the link Dirk provided.

$var1 = New-Object PSObject -prop @{data1=6;data3=5}
$var2 = New-Object PSObject -prop @{data2=12;data3=6}

Write-Host "Both Objects as a collection to Out-Host" -ForegroundColor Green
$var1, $var2 | Out-Host

Write-Host "Individual Objects to Out-Host" -ForegroundColor Green
$var1 | Out-Host
$var2 | Out-Host

Write-Host "Both Objects as a collection to Format Table" -ForegroundColor Green
$var1, $var2 | Format-Table

Write-Host "Both Objects as a collection to Format List" -ForegroundColor Green
$var1, $var2 | Format-List

Results

Both Objects as a collection to Out-Host
data3 data1
----- -----
    5     6
    6      

Individual Objects to Out-Host
data3 data1
----- -----
    5     6

data2 data3
----- -----
   12     6

Both Objects as a collection to Format Table
data3 data1
----- -----
    5     6
    6      

Both Objects as a collection to Format List
data3 : 5
data1 : 6

data2 : 12
data3 : 6

Quote from the page at the link provided by Dirk.
“Now, if there is not a registered view for a datatype, then Out-Default looks at the FIRST OBJECT IN THE STREAM to determine how many properties the object has 5 or more properties, it send the ENTIRE STREAM to Format-List, otherwise it sends the ENTIRE STREAM to Format-Table. When it sends the stream to Format-Table, that command needs to generate columns. It does this by looking at the properties of the FIRST OBJECT – those become the columns. If the first Object has 2 properties, you’ll get a 2 column table even if all the other objects in the stream have 10 properties.”

Thanks for the quote. I didn’t know format-table was involved. I skimmed that page, but I didn’t notice that section.

You can also rename one of the properties:

$var1 = New-Object PSObject -prop @{data1=6;data3=5}
$var1
$var2 = New-Object PSObject -prop @{data2=12;data3=6}
$var2 | select @{name='data1'; expression = {$_.data2}},data3


data3 data1
----- -----
    5     6
    6    12