When working with APIs, you often need to convert between PowerShell objects and JSON. Web APIs accept requests in JSON notation, and your PowerShell script might have data represented as a PowerShell object. In order to use this data in a web request, you convert it to JSON.

In this post, you will learn how to convert PowerShell objects into JSON. You will also learn about the Depth parameter, which ensures you convert the entire object to JSON correctly.

Comparing PowerShell Objects and JSON

You define PowerShell objects using the at sign (@) and curly brackets ( { } ). Add the [PSCustomObject] type accelerator to make it an object; otherwise, you end up with a hash table. Within the object, define properties and their values. The property names do not need to be enclosed with quotes, but the values do if they are strings.

$myObject = [PSCustomObject]@{
    GroupName = 'My Group'
    GroupDescription = 'Demoing JSON Conversion'
    MemberCount = 3
}

You access properties of the object using the dot method. Enter the name of the object followed by a dot or period, then the name of the property.

powershell object properties
Using dot method to access object properties

In comparison, JSON is just a string with properties and values. However, you associate properties and their values using colons ( : ), and the property name is enclosed in quotes. Each property is separated by commas, whereas PowerShell objects are separated by newlines. Here is an example of a JSON-formatted string saved to a variable in PowerShell using a here-string for a multi-line string.

$myJson = @'
{
    "GroupName": "My Group",
    "GroupDescription": "Demoing JSON Conversion",
    "MemberCount": 3
}
'@

Unlike PowerShell objects, you cannot access the JSON properties and values since it is just a string of characters. The string is not aware of any properties or values in it. You can view the comparison of these two variables by piping each one to the Get-Member command. Note the difference in the TypeName, methods, and properties. The $myJson output is truncated in the screenshot.

powershell get-member
Comparing Get-Member against the PowerShell object and JSON string

If you have a PowerShell script using APIs, it is easier to work with a PowerShell object. You can access, add, and change properties. These tasks are more difficult working with a JSON string. When it comes time to make the API call, you convert the PowerShell object to JSON (more on this later).

More Complex PowerShell and JSON Properties

In the above examples, both the PowerShell and JSON code held strings and integers. However, both are capable of holding more complex data types, like lists and arrays. Let’s take a look at how these are represented.

In a PowerShell object, a property can hold an array of items. You designed the array using an at symbol (@) and parenthesis ( ). For the $myObject PowerShell object, add a Tags property with a list of keywords to describe the group.

$myObject = [PSCustomObject]@{
    GroupName = 'My Group'
    GroupDescription = 'Demoing JSON Conversion'
    MemberCount = 3
    Tags = @(
        'security',
        'production',
        'it'
    )
}

In JSON, you designate an array or list of items using square brackets [ ] with each item separated by commas.

{
  "GroupName": "My Group",
  "GroupDescription": "Demoing JSON Conversion",
  "MemberCount": 3,
  "Tags": [
    "security",
    "production",
    "it"
  ]
}

The array or list of items can contain more objects or hash tables of information. Back in the $myGroup PowerShell object, add a Members property that contains an array of objects about group members, such as Name and Title. The ContactInfo contains a hash table of available contact information, such as PhoneNumber, Address, and Email. Below the PowerShell example is the equivalent in JSON.

$myObject = [PSCustomObject]@{
    GroupName = 'My Group'
    GroupDescription = 'Demoing JSON Conversion'
    MemberCount = 3
    Tags = @(
        'security',
        'production',
        'IT'
    )
    Members = @(
        @{
            Name = 'Jeff Brown'
            Title = 'CEO'
            ContactInfo = @{
                PhoneNumber = '15559991234'
                Address = '123 Main St'
                Email = 'jeff@domain.com'
            }
        },
        @{
            Name = 'Maggie Brown'
            Title = 'COO'
            ContactInfo = @{
                PhoneNumber = '15551112222'
                Address = '456 Broadway'
                Email = 'maggie@domain.com'
            }
        }
    )
}
{
  "GroupName": "My Group",
  "GroupDescription": "Demoing JSON Conversion",
  "MemberCount": 3,
  "Tags": [
    "security",
    "production",
    "IT"
  ],
  "Members": [
    {
      "ContactInfo": {
        "Address": "123 Main St",
        "Email": "jeff@domain.com",
        "PhoneNumber": "15559991234"
      },
      "Name": "Jeff Brown",
      "Title": "CEO"
    },
    {
      "ContactInfo": {
        "Address": "456 Broadway",
        "Email": "maggie@domain.com",
        "PhoneNumber": "15551112222"
      },
      "Name": "Maggie Brown",
      "Title": "COO"
    }
  ]
}

You can see that the information starts to get complicated with nested arrays and objects. Why is all this important? When converting PowerShell objects to JSON, the conversion can end up truncating these nested properties. Let take a look.

Converting PowerShell Objects to JSON

PowerShell provides the ConvertTo-Json command for turning PowerShell objects into JSON formatted strings. Take one of the earlier examples of the $myObject PowerShell object and use the ConvertTo-Json command to turn it into a JSON-formatted string.

$myObject = [PSCustomObject]@{
    GroupName = 'My Group'
    GroupDescription = 'Demoing JSON Conversion'
    MemberCount = 3
}
ConvertTo-Json -InputObject $myObject
powershell convertto-json

PowerShell can handle this conversion quite easily. Now let’s take the more complex example and try to convert it to JSON. The more complex example contains many nested properties.

$myObject = [PSCustomObject]@{
    GroupName = 'My Group'
    GroupDescription = 'Demoing JSON Conversion'
    MemberCount = 3
    Tags = @(
        'security',
        'production',
        'IT'
    )
    Members = @(
        @{
            Name = 'Jeff Brown'
            Title = 'CEO'
            ContactInfo = @{
                PhoneNumber = '15559991234'
                Address = '123 Main St'
                Email = 'jeff@domain.com'
            }
        },
        @{
            Name = 'Maggie Brown'
            Title = 'COO'
            ContactInfo = @{
                PhoneNumber = '15551112222'
                Address = '456 Broadway'
                Email = 'maggie@domain.com'
            }
        }
    )
}
ConvertTo-Json -InputObject $myObject
powershell convertto-json

In the list of members, the conversion is missing the ContactInfo property. Instead, the JSON string displays that it is a hash table of information. The ConvertTo-Json command has left this information out. What gives? It’s all about depth.

Going into Depth of JSON Conversion

The PowerShell has nested information, three layers deep to be precise. There are the top or first-level items, such as GroupName, GroupDescription, MemberCount, Tags, and Members. The Tags property contains a list of items, and Members contains a list of members. These are the second layers in the object.

Finally, within each member, there is ContactInfo, which contains the third layer of information in the object. Exam the screenshot below, taking note of the comments and colored boxes indicating the layers.

powershell object

So here is the issue:

By default, the ConvertTo-Json command converts only the first two levels of the object.

If you perform the conversion in PowerShell 5.1, PowerShell does not warn you about this conversion truncation. It will display what you see in the screenshot above with just the data type.

However, PowerShell 7 is a bit more forgiving as it will display a warning that it truncated the JSON output as it exceeds a depth of 2.

powershell 7 convertto-json warning

Converting Additional Levels

The solution is built into the ConvertTo-Json command in the form of the -Depth parameter. Use this parameter and specify how many levels of the object PowerShell should convert. In the complex example, three levels should be sufficient.

ConvertTo-Json -InputObject $myObject -Depth 3
powershell convertto-json

Closing

You may not realize that PowerShell JSON conversion defaults to 2 levels, so converting objects to JSON may cause some problems. Luckily, there is a built-in solution for the issue in the command. I intentionally added more complex data types so you can also see the comparison of how lists and key/value are displayed between PowerShell objects and JSON.

Enjoyed this article? Check out more of my PowerShell articles!