I have a json file (test.json) that looks something like this:
{
"root":
{
"key":"value"
}
}
I'm loading it into powershell using something like this:
PS > $data = [System.String]::Join("", [System.IO.File]::ReadAllLines("test.json")) | ConvertFrom-Json
root
----
@{key=value}
I'd like to be able to enumerate the keys of the 'hashtable' like object that is defined by the json file. So, Ideally, I'd like to be able to do something like:
$data.root.Keys
and get ["key"] back. I can do this with the built-in hashtables in powershell, but doing this with a hashtable loaded from json is less obvious.
In troubleshooting this, I've noticed that the fields returned by ConvertFrom-json have different types than those of Powershell's hashtables. For example, calling .GetType() on a built-in hashtable makes shows that it's of type 'Hashtable':
PS > $h = @{"a"=1;"b"=2;"c"=3}
PS > $h.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Hashtable System.Object
doing the same for my json object yields PSCustomObject:
PS > $data.root.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
Is there any way to cast or transform this object into a typical powershell Hashtable?
Here's a quick function to convert a PSObject back into a hashtable (with support for nested objects; intended for use with DSC ConfigurationData, but can be used wherever you need it).
function ConvertPSObjectToHashtable
{
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
{
$collection = @(
foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object }
)
Write-Output -NoEnumerate $collection
}
elseif ($InputObject -is [psobject])
{
$hash = @{}
foreach ($property in $InputObject.PSObject.Properties)
{
$hash[$property.Name] = ConvertPSObjectToHashtable $property.Value
}
$hash
}
else
{
$InputObject
}
}
}
The ConvertFrom-Json
cmdlet gives you a custom object so you have to access them using dot notation rather than as a subscript. Usually you would know what fields you expect in the JSON so this is actually more useful in general than getting a hash table. Rather than fighting the system by converting back to a hash table, I suggest you work with it.
You can use select
with wildcard property names to get at the properties:
PS D:\> $data = @"
{
"root":
{
"key":"value", "key2":"value2", "another":42
}
}
"@ | ConvertFrom-Json
PS D:\> $data.root | select * | ft -AutoSize
key key2 another
--- ---- -------
value value2 42
PS D:\> $data.root | select k* | ft -AutoSize
key key2
--- ----
value value2
and Get-Member
if you want to extract a list of property names that you can iterate over:
PS D:\> ($data.root | Get-Member -MemberType NoteProperty).Name
another
key
key2
Putting that into a loop gives code like this:
PS D:\> foreach ($k in ($data.root | Get-Member k* -MemberType NoteProperty).Name) {
Write-Output "$k = $($data.root.$k)"
}
key = value
key2 = value2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With