如何在PowerShell中合并两个JSON的Jobs对象并保留原父结构?
问题描述
我有两个结构相似的JSON文件,需要从第一个JSON的Jobs数组中提取所有元素,并追加到第二个JSON的同名Jobs数组下。目前已成功提取并合并两个JSON的Jobs内容,但无法在不丢失Jobs以外原有父对象的前提下直接更新第二个JSON。注意:JSON根节点的属性名并非始终以DBM开头。
第一个JSON(源JSON)
{ "DBM0003": { "Type": "Folder", "ControlmServer": "vl-aus-dbaqa001", "ActiveRetentionPolicy": "CleanEndedOK", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Application": "VSAUAPP", "Jobs": [ { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "hostname", "Name": "DBMAU001", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU001-273" } ] }, "eventsToAdd": { "Type": "AddEvents", "Events": [ { "Event": "DBMAU001-TO-DBMAU002-341" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU001-273" } ] } }, { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "cat $HOME/installed-versions.txt", "Name": "DBMAU002", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "DBMAU001-TO-DBMAU002-341" } ] }, "eventsToAdd": { "Type": "AddEvents", "Events": [ { "Event": "DBMAU002-TO-DBMAU003-341" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "DBMAU001-TO-DBMAU002-341" } ] } }, { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "cat $HOME/installed-versions.txt", "Name": "DBMAU003", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "DBMAU002-TO-DBMAU003-341" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "DBMAU002-TO-DBMAU003-341" } ] } } ], "When": { "RuleBasedCalendars": { "Included": [ "CAP_0001" ], "CAP_0001": { "Type": "Calendar:RuleBased", "When": { "DaysRelation": "OR", "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ] } } } } } }
第二个JSON(目标JSON)
{ "DBM0002": { "Type": "Folder", "ControlmServer": "vl-aus-dbaqa001", "ActiveRetentionPolicy": "CleanEndedOK", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Application": "VSAUAPP", "Jobs": [ { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "hostname", "Name": "DBMAU004", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU004" } ] }, "eventsToAdd": { "Type": "AddEvents", "Events": [ { "Event": "DBMAU004-TO-DBMAU005" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU004" } ] } }, { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "hostname", "Name": "DBMAU004", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU004" } ] }, "eventsToAdd": { "Type": "AddEvents", "Events": [ { "Event": "DBMAU004-TO-DBMAU005" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "CAPU003-TO-DBMAU004" } ] } }, { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "cat $HOME/installed-versions.txt", "Name": "DBMAU005", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "DBMAU004-TO-DBMAU005" } ] }, "eventsToAdd": { "Type": "AddEvents", "Events": [ { "Event": "DBMAU005-TO-DBMAU006" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "DBMAU004-TO-DBMAU005" } ] } }, { "Type": "Job:Command", "SubApplication": "VSAUSUBAPP", "CreatedBy": "emuser", "Description": "Test Job", "RunAs": "ctmagent", "Application": "VSAUAPP", "Command": "cat $HOME/installed-versions.txt", "Name": "DBMAU006", "When": { "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ], "DaysRelation": "OR", "RuleBasedCalendars": { "Relationship": "AND", "Included": [ "CAP_0001" ] } }, "eventsToWaitFor": { "Type": "WaitForEvents", "Events": [ { "Event": "DBMAU005-TO-DBMAU006" } ] }, "eventsToDelete": { "Type": "DeleteEvents", "Events": [ { "Event": "DBMAU005-TO-DBMAU006" } ] } } ], "When": { "RuleBasedCalendars": { "Included": [ "CAP_0001" ], "CAP_0001": { "Type": "Calendar:RuleBased", "When": { "DaysRelation": "OR", "WeekDays": [ "NONE" ], "MonthDays": [ "ALL" ] } } } } } }
当前PowerShell脚本
$sourcejson = Get-Content 'DBM0002.json' | ConvertFrom-Json $destjson = Get-Content 'DBM0003.json' | ConvertFrom-Json $sourcefolder = $sourcejson.PsObject.Properties.Name $sourcejobs = $sourcejson.$($sourcefolder).Jobs $sourcejobsjson = $sourcejobs | ConvertTo-Json -Depth 99 $sourcejobsnames = $sourcejson.$($sourcefolder).Jobs.Name $sourcejobscount = $sourcejson.$($sourcefolder).Jobs.Name.Count $destfolder = $destjson.PsObject.Properties.Name $destjobs = $destjson.$($destfolder).Jobs $destjobsjson = $destjobs | ConvertTo-Json -Depth 99 $destjobsnames = $destjson.$($destfolder).Jobs.Name $destjobscount = $destjson.$($destfolder).Jobs.Name.Count $destjobs += $sourcejobs $destjobs | ConvertTo-Json -Depth 99 | Add-Content -Path Combined.json $sourcejson = Get-Content 'DBM0002.json' | ConvertFrom-Json $destjson = Get-Content 'DBM0003.json' | ConvertFrom-Json $sourcefolder = @($sourcejson.PsObject.Properties)[0].Name $sourcejobs = @($sourcejson.PSObject.Properties)[0].Value.Jobs $sourcejobsnames = @($sourcejson.PSObject.Properties)[0].Value.Jobs.Name $sourcejobscount = @($sourcejson.PSObject.Properties)[0].Value.Jobs.Name.Count $destfolder = @($destjson.PsObject.Properties)[0].Name $destjobs = @($destjson.PSObject.Properties)[0].Value.Jobs $destjobsnames = @($destjson.PSObject.Properties)[0].Value.Jobs.Name $destjobscount = @($destjson.PSObject.Properties)[0].Value.Jobs.Name.Count # Option 1 $destjobs += $sourcejobs # Option 2 @($destjson.PSObject.Properties)[0].Value.Jobs += @(@($sourcejson.PSObject.Properties)[0].Value.Jobs) # Option 3 @($destjson.PSObject.Properties)[0].Value.Jobs += @($sourcejson.PSObject.Properties)[0].Value.Jobs $destjson | ConvertTo-Json -Depth 99 | Add-Content -Path Combined.json Write-Host $sourcefolder","$sourcejobscount"," -NoNewline && Write-Host $sourcejobsnames -Separator ":" Write-Host $destfolder","$destjobscount"," -NoNewline && Write-Host $destjobsnames -Separator ":"
解决方案
核心问题在于直接对$destjobs赋值不会修改原$destjson对象的引用,需要直接操作$destjson内部的Jobs数组。以下是修正后的脚本:
# 读取并解析两个JSON文件 $sourceJson = Get-Content 'DBM0003.json' | ConvertFrom-Json $destJson = Get-Content 'DBM0002.json' | ConvertFrom-Json # 获取源JSON的根节点属性名(兼容非DBM开头的情况) $sourceRootKey = @($sourceJson.PSObject.Properties)[0].Name # 提取源JSON的Jobs数组 $sourceJobs = $sourceJson.$sourceRootKey.Jobs # 获取目标JSON的根节点属性名 $destRootKey = @($destJson.PSObject.Properties)[0].Name # 将源Jobs数组追加到目标Jobs数组中 $destJson.$destRootKey.Jobs += $sourceJobs # 将合并后的目标JSON写入文件,保留所有原有属性 $destJson | ConvertTo-Json -Depth 99 | Set-Content -Path 'Combined.json' # 输出验证信息 Write-Host "源根节点: $sourceRootKey,Jobs数量: $($sourceJobs.Count)" Write-Host "目标根节点: $destRootKey,合并后Jobs数量: $($destJson.$destRootKey.Jobs.Count)"
关键说明
- 直接操作
$destJson.$destRootKey.Jobs,确保修改的是原$destJson对象的内部数组,而非副本。 - 使用
@($sourceJson.PSObject.Properties)[0].Name动态获取根节点属性名,兼容任意命名的根节点。 - 使用
Set-Content而非Add-Content避免重复写入内容。 -Depth 99确保嵌套的JSON结构被正确序列化,不会丢失层级。
内容的提问来源于stack exchange,提问作者venky_au
相关产品推荐
相关产品推荐

