Powershell: Add option to ConvertFrom-Json as a Hashtable

Created on 22 Apr 2017  路  8Comments  路  Source: PowerShell/PowerShell

Currently ConvertFrom-Json returns a PSCustomObject. It would be nice in some cases if you could choose to return a Hashtable instead, perhaps using an -As parameter. Hashtables are often much faster for processing Json document databases compared to having to iterate through object properties.

This would also be a possible way to address #1755 .

Area-Cmdlets-Utility Hacktoberfest Issue-Enhancement Resolution-Fixed Up-for-Grabs

Most helpful comment

Yes, the case sensitivity is one area, empty property names are another area.

On the performance side, I would suggest that adding, removing and enumerating properties are all slower/more difficult on a pscustomobject than a hashtable.

$hashTable = @{
    "1" = 1
    "2" = 2
}

$object = [pscustomobject]$hashTable
Measure-command {
    Foreach($number in 3..10000)
    {
        $hashTable.Add("$number", $number)
    }
}



Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 63
Ticks             : 631145
TotalDays         : 7.30491898148148E-07
TotalHours        : 1.75318055555556E-05
TotalMinutes      : 0.00105190833333333
TotalSeconds      : 0.0631145
TotalMilliseconds : 63.1145
Measure-Command {
    Foreach($number in 3..10000)
    {
        $object | Add-Member -MemberType NoteProperty -Name "$number" -Value $number
    }
}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 76
Ticks             : 10769741
TotalDays         : 1.24649780092593E-05
TotalHours        : 0.000299159472222222
TotalMinutes      : 0.0179495683333333
TotalSeconds      : 1.0769741
TotalMilliseconds : 1076.9741

All 8 comments

Can you provide a concrete example where hashtables are superior to an object tree?

Apart from object size and performance, it may matter with case sensitivity. I have run into issues where I couldn't use the PowerShell cmdlets because the json contained 'Property' and 'property'.

Yes, the case sensitivity is one area, empty property names are another area.

On the performance side, I would suggest that adding, removing and enumerating properties are all slower/more difficult on a pscustomobject than a hashtable.

$hashTable = @{
    "1" = 1
    "2" = 2
}

$object = [pscustomobject]$hashTable
Measure-command {
    Foreach($number in 3..10000)
    {
        $hashTable.Add("$number", $number)
    }
}



Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 63
Ticks             : 631145
TotalDays         : 7.30491898148148E-07
TotalHours        : 1.75318055555556E-05
TotalMinutes      : 0.00105190833333333
TotalSeconds      : 0.0631145
TotalMilliseconds : 63.1145
Measure-Command {
    Foreach($number in 3..10000)
    {
        $object | Add-Member -MemberType NoteProperty -Name "$number" -Value $number
    }
}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 76
Ticks             : 10769741
TotalDays         : 1.24649780092593E-05
TotalHours        : 0.000299159472222222
TotalMinutes      : 0.0179495683333333
TotalSeconds      : 1.0769741
TotalMilliseconds : 1076.9741

I like the idea of an -AsHashtable option or something similar. Whenever I enumerate all the property names and then walk them, it is very inefficient. Even more so when I am recursively walking the object to turn it into a nested hashtable.

There is also not a simple way to test for a property on an object. Sometimes you can't just test for $null because the value could be $null. The existence of a property is different than a $null property value.

[bool]( $object.PSobject.Properties.name -match $property )
$hashtable.ContainsKey($property)

I also don't like using a dot property to a variable to access properties this way. A minor gripe but something that I like to avoid because at a glance it is hard to tell if that is intentional or a typo.

$object.$property
$hashtable[ $property ]

Alternatively, we could make PSCustomObject better at property enumeration, addition, and removal.

@KevinMarquette That is not exactly true that there is no simple way to test for a property.

$obj = New-Object pscustomobject -Property @{a = 1; b = 2}
$obj.psobject.Properties.Match("a")
$obj.psobject.Properties.Match("c")

Seems simple enough?

Thank you for that example. I had previously overlooked the match keyword there. I will start using that one.

+1 for this request.

For my use case, I tend to leverage JSON for config files shared between different languages (or even module settings for certain things); I typically will have a function (let's say Export-Config) that accepts a hashtable as input and pipes to ConvertTo-Json prior to setting in a file. PSObjects and Hashtables result in the same JSON structure for my use case, so I opt to have the input as a Hashtable to save some characters and allow me to build that input value with less keystrokes.

When I want to reimport that config and make updates with a separate function (let's say Update-Config), I have to adjust the function logic and deal with Add-Member vs just stating $config["Map"] = $NewSettings. Also in agreeance with Kevin in that having $hashtable[ $property ] buried in a script is easier to identify as what it is compared to $object.$property.

Speed differences between the two are also evident when dealing with very large object arrays vs large hashtables to the point where I will almost always build a hashtable from the resulting object array for lookup speed gains compared to looking up against the object array directly.

Leave a comment

Was this page helpful?
0 / 5 - 0 ratings