Search code examples
jsonpowershellpscustomobject

PowerShell - JSON/PsCustomObject - Why does my array get flattened into a single object?


The owners key in my output (see OutputFile) I'm expecting as a line separated array, but it's outputting as a single-line space separated object/string

Script:

function Add-ApplicationOwner
{
    param (
        [string] $App,
        [object] $OutputObject
    )

    # add values to our json output
    $owners = (Get-AzureAdApplicationOwner -ObjectId $App).UserPrincipalName
    $OutputObject | Add-Member -MemberType NoteProperty -Name owners -Value $owners
}

$inputFile = Get-Content -Path "AppInput.json" -Raw | ConvertFrom-Json
$outputFile = New-Object -TypeName PsObject

foreach ($object in $inputFile.PSObject.Properties)
{
    $outputAppList = New-Object -TypeName PsObject

    foreach ($app in $inputFile.New.PsObject.Properties)
    {           

        # create app
        $appRegistration = New-AzureADApplication -DisplayName "TestSPN1"

        #add application info into json object
        $outputAppValues = [PsCustomObject]@{
            app_id = $appRegistration.AppId
        }

        #add application owners by object id
        Add-ApplicationOwner -App $appRegistrationObjectId -OutputObject $outputAppValues

        $outputAppList | Add-Member -MemberType NoteProperty -Name "TestSPN1" -Value $outputAppValues
             
    }

    # add all created apps into json output file
    $outputFile | Add-Member -MemberType NoteProperty -Name "New Applications" -Value $outputAppList

}

$outputFile | ConvertTo-Json | Out-File "AzADAppRegistrationInfo.json" -Append

OutputFile:

{
    "New Applications":  {
                             "TestSPN1":  {
                                              "app_id":  "dsfadfdafa-3afadfdafadsfasd-343",
                                              "owners":  "user1 user2 user3"
                                          }
                         }
}

Desired Output:

{
    "New Applications":  {
                             "TestSPN1":  {
                                              "app_id":  "dsfadfdafa-3afadfdafadsfasd-343",
                                              "owners":  [
                                                   "user1",
                                                   "user2",
                                                   "user3"
                                               ]
                                          }
                         }
}

$owners Variable Examined:

$owners
user1
user2
user3

$owners.gettype()

IsPublic IsSerial Name                                     BaseType                                                                                                                                                                  
-------- -------- ----                                     --------                                                                                                                                                                  
True     True     Object[]                                 System.Array     

When I look at $outputFile.'New Applications' it's as expected

$outputFile.'New Applications' | convertto-json
{
    "TestSPN1":  {
                     "app_id":  "asdfdsfad",
                     "owners":  [
                                    "user1",
                                    "user2",
                                    "user3"
                                ]
                 }
}

When I look at $outputFile it's flattened

$outputFile | convertto-json
{
    "New Applications":  {
                             "TestSPN1":  {
                                              "app_id":  "cc6dgfsdgdsgfsdgfdsa5562614",
                                              "owners":  "user1 user2 user3"
                                          }
                         }
}

Solution

  • The most likable explanation for your issue is that -Depth is using the default Value. I have stored $outputFile.'New Applications' in the $json variable for below example.

    [pscustomobject]@{
        'New Applications' = $json
    } | ConvertTo-Json
    

    Results in:

    WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2.
    {
      "New Applications": {
        "TestSPN1": {
          "app_id": "asdfdsfad",
          "owners": "user1 user2 user3"
        }
      }
    }
    

    Worth pointing out that the Warning Message is only displayed on newer versions of PowerShell (PS 7.1+ to be precise, thanks mklement0 for pointing it out). Windows PowerShell defaults to truncate the JSON without any warning.


    However if we add 1 depth level (Default -Depth value is 2):

    [pscustomobject]@{
        'New Applications' = $json
    } | ConvertTo-Json -Depth 3
    

    Results in:

    {
      "New Applications": {
        "TestSPN1": {
          "app_id": "asdfdsfad",
          "owners": [
            "user1",
            "user2",
            "user3"
          ]
        }
      }
    }