【问题标题】:Hashtables from ConvertFrom-json have different type from powershells built-in hashtables, how do I make them the same?ConvertFrom-json 中的哈希表与 powershells 内置哈希表的类型不同,如何使它们相同?
【发布时间】:2014-03-27 00:00:23
【问题描述】:

我有一个看起来像这样的 json 文件 (test.json):

{
    "root":
    {
        "key":"value"
    }
}

我正在使用类似这样的方式将其加载到 powershell 中:

PS > $data = [System.String]::Join("", [System.IO.File]::ReadAllLines("test.json")) | ConvertFrom-Json

root
----
@{key=value}

我希望能够枚举由 json 文件定义的“哈希表”类对象的键。因此,理想情况下,我希望能够做一些事情喜欢:

$data.root.Keys

然后取回 ["key"]。我可以使用 powershell 中的内置哈希表来执行此操作,但是使用从 json 加载的哈希表执行此操作不太明显。

在解决此问题时,我注意到 ConvertFrom-json 返回的字段类型与 Powershell 哈希表的类型不同。例如,在内置哈希表上调用 .GetType() 会显示它是“哈希表”类型:

PS > $h = @{"a"=1;"b"=2;"c"=3}
PS > $h.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object

对我的 json 对象执行相同操作会产生 PSCustomObject:

PS > $data.root.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

有没有办法将此对象转换或转换为典型的 powershell Hashtable?

【问题讨论】:

标签: json powershell


【解决方案1】:

我把它放在一起处理嵌套的 json 到哈希表

    function ConvertJSONToHash{
    param(
        $root
    )
    $hash = @{}

    $keys = $root | gm -MemberType NoteProperty | select -exp Name

    $keys | %{
        $key=$_
        $obj=$root.$($_)
        if($obj -match "@{")
        {
            $nesthash=ConvertJSONToHash $obj
            $hash.add($key,$nesthash)
        }
        else
        {
           $hash.add($key,$obj)
        }

    }
    return $hash
}

我只测试了 4 个级别但递归直到它有完整的哈希表。

【讨论】:

  • 非常感谢我想要的。我认为这应该被接受为答案。
【解决方案2】:

这是一个将 PSObject 转换回哈希表的快速函数(支持嵌套对象;旨在与 DSC ConfigurationData 一起使用,但可以在任何需要的地方使用)。

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
        }
    }
}

【讨论】:

  • 这对我有用,但如果 $InputObject 已经是或包含 HashTable 或有序字典,则不行。我在if ($null -eq $InputObject... 之后添加了以下内容 - 添加这一行:if ($InputObject -is [Hashtable] -or $InputObject.GetType().Name -eq 'OrderedDictionary') { return $InputObject }
【解决方案3】:

@Duncan:如果您需要将 JSON 输入用于需要哈希图的命令(例如 SET-ADUSER),请尝试以下操作:

function SetADProperties{
    param($PlannedChanges)
    $UserName = $PlannedChanges.Request.User
    $Properties = @{}
    foreach ($key in ($PlannedChanges.SetADProperties | Get-Member -MemberType NoteProperty).Name)
    {
        $Properties[$key] = $PlannedChanges.SetADProperties.$key
    }
    # Call Set-ADUser only once, not in a loop
    Set-ADUser -Identity $UserName -Replace $Properties
}

$content = Get-Content -encoding UTF8 $FileName
$PlannedChanges = $content | ConvertFrom-Json
SetADProperties $PlannedChanges | Write-Output

示例 JSON:

{"SetADProperties":{"postalCode":"01234","l":"Duckburg","employeenumber":"012345678"},
"Request":{"Action":"UserMove","User":"WICHKIND","Change":"CH1506-00023"}}

【讨论】:

    【解决方案4】:

    ConvertFrom-Json cmdlet 为您提供了一个自定义对象,因此您必须使用点符号而不是作为下标来访问它们。通常你会知道你期望 JSON 中有哪些字段,所以这实际上比获取哈希表更有用。我建议您使用它,而不是通过转换回哈希表来对抗系统。

    您可以使用带有通配符属性名称的select 来获取属性:

    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
    

    Get-Member,如果您想提取可以迭代的属性名称列表:

    PS D:\> ($data.root | Get-Member -MemberType NoteProperty).Name
    another
    key
    key2
    

    将其放入循环中会产生如下代码:

    PS D:\> foreach ($k in ($data.root | Get-Member k* -MemberType NoteProperty).Name) {
        Write-Output "$k = $($data.root.$k)"
        }
    key = value
    key2 = value2
    

    【讨论】:

    • 谢谢邓肯,这正是我所需要的!
    【解决方案5】:

    该示例适用于相对较浅的源对象(不是属性中的嵌套对象)。

    这是一个深入到源对象的 2 个级别的版本,并且应该可以处理您的数据:

    $data = @{}
    
    foreach ($propL1 in $x.psobject.properties.name)
       {
         $data[$propL1] = @{}
         foreach ($propL2 in $x.$propL1.psobject.properties.name)
            {
              $data[$PropL1][$PropL2] = $x.$propL1.$propL2
            }
        }
    
    
    $data.root.keys
    
    key
    

    【讨论】:

      猜你喜欢
      • 2018-03-23
      • 2019-05-03
      • 2020-06-24
      • 1970-01-01
      • 2019-09-20
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      • 1970-01-01
      相关资源
      最近更新 更多