My ConvertTo-Hashtable function allows you to convert JavaScript Object Notation (JSON) data format to a native PowerShell hash table.

We can think of PowerShell as automation glue. This language seems to be able to interact with just about every conceivable product. Part of this impartial ability to work with lots of products typically means working with application programming interfaces (APIs). Many services these days have a representational state transfer (REST) API.

PowerShell can easily query these REST APIs using the Invoke-RestMethod command or Invoke-Webrequest. But what then? Lots of APIs return JSON, which is great. But what if I'm going to use this data in other parts of my script? It's possible to carry around a JSON string all day in a script, but it's going to be tough to parse that out and get to the data you need. Instead, it's much better to convert that JSON string to a native hash table.

PowerShell has a native command called ConvertFrom-Json, but it doesn't convert data to a hash table. In simple situations, this may be fine. But I've found when you've got JSON data that contains deeply nested arrays, for example, you'll begin to see some problems. This command does some processing under the hood as well, like performing some escaping I sometimes don't want. So I decided to build a ConvertTo-Hashtable function that takes an object returned from ConvertFrom-Json and converts it to a hash table.

To demonstrate, let's take a JSON string as an example.

$json ='{
    "SQLDatabase": [
        {
            "Name": "FOO",
            "Type": "OnPrem",
            "Ensure": "Present"
        }
    ],
    "ADUser": [
        {
            "Name": "jjones",
            "DnsDomainName": "lab.local"
        }
    ],
    "ADGroup": [
        {
            "Name": "mygroup",
            "Scope": "DomainLocal",
            "DnsDomainName": "lab.local",
            "Members": [
                {
                    "Name": "jjones",
                    "Type": "User",
                    "DnsDomainName": "lab.local"
                }
            ]
        }
    ]
}'

I'll then assign that JSON data to a variable to create a string and then convert it to a PowerShell PSCustomObject using the ConvertFrom-Json command:

$jsonObj = $json | ConvertFrom-Json
ConvertFrom Json

ConvertFrom Json

I now have an object I can work with. I'll go ahead and assign the output to the $jsonObj variable. At this point, I want to convert this object to a hash table. If the object just had some simple string properties, this would not be a hard task at all. We'd simply enumerate all the properties of the object and create a new hash table from them.

$hash = @{}
foreach ($property in $jsonObj.PSObject.Properties) {
    $hash[$property.Name] = $property.Value
}

We'd be done here if it weren't for the possibility that these properties can be a lot of different types other than just strings. To build a robust conversation function, we need to account for these situations. This is where I'd usually break out each piece of the code and explain it independently. Since this code is so tightly integrated as well as being a recursive function, it will be easier to explain what's going on inside the function comments themselves.

Subscribe to 4sysops newsletter!

function ConvertTo-Hashtable {
    [CmdletBinding()]
    [OutputType('hashtable')]
    param (
        [Parameter(ValueFromPipeline)]
        $InputObject
    )

    process {
        ## Return null if the input is null. This can happen when calling the function
        ## recursively and a property is null
        if ($null -eq $InputObject) {
            return $null
        }

        ## Check if the input is an array or collection. If so, we also need to convert
        ## those types into hash tables as well. This function will convert all child
        ## objects into hash tables (if applicable)
        if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
            $collection = @(
                foreach ($object in $InputObject) {
                    ConvertTo-Hashtable -InputObject $object
                }
            )

            ## Return the array but don't enumerate it because the object may be pretty complex
            Write-Output -NoEnumerate $collection
        } elseif ($InputObject -is [psobject]) { ## If the object has properties that need enumeration
            ## Convert it to its own hash table and return it
            $hash = @{}
            foreach ($property in $InputObject.PSObject.Properties) {
                $hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value
            }
            $hash
        } else {
            ## If the object isn't an array, collection, or other object, it's already a hash table
            ## So just return it.
            $InputObject
        }
    }
}
We can then call this function via pipeline:
$json | ConvertFrom-Json | ConvertTo-HashTable

Performing conversions like this can be challenging and will sometimes require lots of trial and error. I created this function in just this way. An object can be in so many variations. Thus, the only true way to create code that doesn't break will be simply to run as much input through it as possible and monitor the results.

12 Comments
  1. Leonard 5 years ago

    Thanks for the explanation and great code. It works perfectly on a json configuration block with nested hashtables and arrays.

    A minor correction on the end of the script. The last line should be $jsonString, not $jsonObj
    $jsonString | ConvertFrom-Json | ConvertTo-HashTable

    • Where did you get the $jsonString variable from?

      • Leo 5 years ago

        $jsonObj is the json-decoded object, as seen on the article’s line “I now have an object I can work with. I’ll go ahead and assign the output to the $jsonObj variable.

        $jsonString is, basically, the $json variable

        • You are right, the article was somewhat incomplete and contained errors. I fixed it now. The crucial line for you is the last one:

          $json | ConvertFrom-Json | ConvertTo-HashTable

  2. MatthGyver 5 years ago

    Hi,

    I’m working on Powershell module to manage Grafana application and plan to put it on Github in opensource.

    Can I use your code as is by mentioning your name and this url page please ?

    Thank you

  3. rock 5 years ago

    When we conver it back to Json, why it  have additional  “value” , and “count”?
    $jsonObj = $json | ConvertFrom-Json |ConvertTo-Hashtable |ConvertTo-Json

    {

    “ADGroup”:  {

    “value”:  [

    {

    “Scope”:  “DomainLocal”,

    “Name”:  “mygroup”,

    “Members”:  {

    “value”:  “System.Collections.Hashtable”,

    “Count”:  1

    },

    “DnsDomainName”:  “lab.local”

    }

    ],

    “Count”:  1

    },

    “SQLDatabase”:  {

    “value”:  [

    {

    “Name”:  “FOO”,

    “Ensure”:  “Present”,

    “Type”:  “OnPrem”

    }

    ],

    “Count”:  1

    },

    “ADUser”:  {

    “value”:  [

    {

    “DnsDomainName”:  “lab.local”,

    “Name”:  “jjones”

    }

    ],

    “Count”:  1

    }

    }

  4. Patrick 4 years ago

    Thanks for the code Adam, very helpful and nicely documented.

  5. TamusJRoyce 3 years ago

    You have to remove all non NoteProperty properties. See https://github.com/PlagueHO/CosmosDB/issues/382

  6. TamusJRoyce 3 years ago

                ## Convert it to its own hash table and return it
                $hash = @{}
                foreach ($property in $InputObject.PSObject.Properties) {
                    if ($property.MemberType -eq "NoteProperty") { 
                      $hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value
                    }
                }
                $hash

     

    You should skip if it isn't a "NoteProperty" property. These are internal PSObject properties. Specifically add the below.

    if ($property.MemberType -eq "NoteProperty") { 

  7. Ronald Bode 3 years ago

    "If the object isn't an array, collection, or other object, it's already a hash table", what if one of the values in that hash table contains another `PSCustomObject`?

  8. Maciej 2 years ago

    My output is

    Name Value
    —- —–
    ADGroup {System.Collections.Hashtable}
    SQLDatabase {System.Collections.Hashtable}
    ADUser {System.Collections.Hashtable}

    Why the value is {System.Collections.Hashtable} ????
    How to see “Members”: [
    {
    “Name”: “jjones”,
    “Type”: “User”,
    “DnsDomainName”: “lab.local” by hashtable ?

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account