PowerShell读写JSON文件时如何保留元素原始顺序?
问题
读取一个JSON文件,更新部分值后将其写回,但部分元素顺序发生了错乱。使用的PowerShell代码如下:
$manifest = (gc $manifestPath -raw) | ConvertFrom-Json -AsHashtable $manifest.name = "$($manifest.name)-sxs" $manifest | ConvertTo-Json -depth 100 | Out-File $manifestPath -Encoding utf8NoBOM
原始文件中的JSON片段:
{ "name": "vsVersion", "type": "pickList", "label": "Visual Studio Version", "required": false, "helpMarkDown": "If the preferred version cannot be found, the latest version found will be used instead.", "defaultValue": "latest", "options": { "latest": "Latest", "17.0": "Visual Studio 2022", "16.0": "Visual Studio 2019", "15.0": "Visual Studio 2017", "14.0": "Visual Studio 2015", "12.0": "Visual Studio 2013", "11.0": "Visual Studio 2012" } },
写回后的JSON片段:
{ "required": false, "type": "pickList", "name": "vsVersion", "options": { "11.0": "Visual Studio 2012", "12.0": "Visual Studio 2013", "14.0": "Visual Studio 2015", "17.0": "Visual Studio 2022", "15.0": "Visual Studio 2017", "16.0": "Visual Studio 2019", "latest": "Latest" }, "helpMarkDown": "If the preferred version cannot be found, the latest version found will be used instead.", "label": "Visual Studio Version", "defaultValue": "latest" },
请问有没有办法保留元素的原始顺序?
解决方案
问题根源
你使用了-AsHashtable参数,PowerShell中的常规哈希表(Hashtable)不保留键的原始顺序,转成JSON时键的排列会被打乱。要保留顺序,需使用有序结构来处理JSON数据。
方法一:直接使用PSCustomObject(最简单)
去掉-AsHashtable参数,ConvertFrom-Json默认会将JSON对象转换为PSCustomObject,它会严格保留原始键的顺序:
$manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json $manifest.name = "$($manifest.name)-sxs" $manifest | ConvertTo-Json -Depth 100 | Out-File $manifestPath -Encoding utf8NoBOM
这种方式适合大多数场景,PSCustomObject支持点语法修改属性,嵌套层级的顺序也会自动保留。
方法二:递归转换为有序字典(灵活控制场景)
如果需要更灵活的哈希表操作(比如动态增删键),可以将JSON递归转换为OrderedDictionary(有序字典),确保所有层级的键顺序都被保留:
# 递归转换PSCustomObject为有序字典的函数 function ConvertTo-OrderedJson { param( [Parameter(ValueFromPipeline)] $InputObject ) process { if ($InputObject -is [PSCustomObject]) { $orderedDict = [ordered]@{} foreach ($prop in $InputObject.PSObject.Properties) { $orderedDict[$prop.Name] = $prop.Value | ConvertTo-OrderedJson } return $orderedDict } elseif ($InputObject -is [array]) { return $InputObject | ForEach-Object { $_ | ConvertTo-OrderedJson } } else { return $InputObject } } } # 读取并处理JSON $manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json | ConvertTo-OrderedJson $manifest.name = "$($manifest.name)-sxs" $manifest | ConvertTo-Json -Depth 100 | Out-File $manifestPath -Encoding utf8NoBOM
注意事项
- PowerShell 5.1及以上版本中,
ConvertTo-Json处理PSCustomObject或OrderedDictionary时,会保留键的原始顺序 - 绝对避免使用常规Hashtable存储JSON数据,它的键顺序由哈希算法决定,无法保证一致性
内容的提问来源于stack exchange,提问作者jessehouwing
相关产品推荐
相关产品推荐

