Converting JSON to a hashtable
Table of Contents
- Table of Contents
- What’s the problem?
- That’s a Wrap
- The Code
- Example Usage
What’s the problem?
The ConvertFrom-Json and ConvertTo-Json cmdlets are great. JSON is a pretty common standard that isn’t going anywhere, and the ability to work with JSON data as native PowerShell objects provides first-class support for this format in PowerShell. It’s far simpler for PS to use JSON than to use XML.
However, there are times when the PSCustomObject returned by ConvertFrom-Json is less than ideal, and it would be more helpful to use a hashtable instead:
Strict mode and missing properties
When using Strict mode, checking whether the JSON contained a key uses this fairly tedious snippet:
Hashtables make this far easier:
Extending and combining objects
PSCustomObjects have to be extended using Add-Member:
Hashtables can have additional properties added implicitly, even if the key doesn’t exist:
Hashtables can also be combined easily:
Is there a convenient way for us to create a hashtable from JSON?
That’s a Wrap
Add-Type, loading an assembly is trivial (notice that the MSDN page tells us exactly what DLL file to reference). Thanks to Kevin Marquette’s article on hashtables for pointing me in this direction!
This is only half of the problem, though. We could write a function to wrap this class, but then any code where we need to reference our JSON-to-hashtable logic would need to include or reference that function. We’d need to do a find/replace to change all references of
ConvertFrom-Json to our custom function name.
Instead, PowerShell’s command precedence allows us to define a custom function that “overrides” a built-in cmdlet. PowerShell resolves commands in this order:
- Native cmdlets
- Binaries (anything in the PATH variable)
Because of this, we can create a custom function and name it
ConvertFrom-Json, and it will take precedence over the native cmdlet (a function takes precedence over a cmdlet). This is the same reason typing
dir in PowerShell resolves to an alias to
Get-ChildItem before it resolves to
dir.exe - an alias takes precedence over a binary. This means when we load a custom function called
ConvertFrom-Json, it will magically be used by default anywhere we call
ConvertFrom-Json in that PowerShell session.
You can create a wrapper function yourself line-by-line if you’d like, but I found Jeff Hicks’ Copy-Command function gave me a pretty good starting point:
-UseForwardHelp switch generates some metadata that points
Get-Help ConvertFrom-Json to the cmdlet itself, rather than our function. This means we don’t need to mess with comment-based help here. (We don’t have help for the new parameter,
-As, but that’s what this article is for, right?)
-IncludeDynamic switch causes the
Copy-Command function to copy any dynamic parameter blocks from the cmdlet to our new wrapper function. As it turns out, this doesn’t matter in this case, but it doesn’t hurt - and it’s helpful if the cmdlet you wrap does include dynamic parameters.
Here’s the full code for my custom wrapper function around
Notice that the default behavior doesn’t change - if we don’t specify what we want to do with the JSON, it will be converted to an object as usual. This prevents any disruption to code that uses the built-in cmdlet and expects an object in response.
It might be worthwhile to wrap the JSON.NET library rather than the .NET class I referenced, since even MSDN has a note that serialization should be done with JSON.NET rather than that class. Since that would introduce a dependent library, though, it would be a candidate for a more full-featured module instead of a quick wrapper function. In fact, PowerShell Core seems to be referencing this library already!
Finally, if you plan to use this wrapper in code that gets pushed anywhere other than your local machine, it would be prudent to include the wrapper function as a private function in your module. That way, you don’t have to assume that the other system has this function available in its PowerShell profile.
I hope this is helpful!