使用Powershell查找和替换嵌套的JSON值

时间:2018-10-13 20:45:28

标签: json powershell .net-core azure-devops

我有一个appsettings.json文件,我想在VSTS发布管道PowerShell任务中使用PowerShell脚本进行转换。 (顺便说一句,我正在将netstandard 2 Api部署到IIS)。 JSON的结构如下:

{
    "Foo": {
        "BaseUrl": "http://foo.url.com",
        "UrlKey": "12345"
    },
    "Bar": {
        "BaseUrl": "http://bar.url.com"
    },
    "Blee": {
        "BaseUrl": "http://blee.url.com"
    }
}

我想替换BaseUrl,如果存在,则替换每个部分中的UrlKey值,它们分别是Foo,Bar和Blee。 (Foo:BaseUrl,Foo:UrlKey,Bar:BaseUrl等)

我正在使用以下JSON结构来保存新值:

{ 
    "##{FooUrl}":"$(FooUrl)", 
    "##{FooUrlKey}":"$(FooUrlKey)",
    "##{BarUrl}":"$(BarUrl)",
    "##{BleeUrl}":"$(BleeUrl)"
}

到目前为止,我有以下脚本:

# Get file path
$filePath = "C:\mywebsite\appsettings.json"

# Parse JSON object from string
$jsonString = "$(MyReplacementVariablesJson)"
$jsonObject = ConvertFrom-Json $jsonString

# Convert JSON replacement variables object to HashTable
$hashTable = @{}
foreach ($property in $jsonObject.PSObject.Properties) {
    $hashTable[$property.Name] = $property.Value
}

# Here's where I need some help

# Perform variable replacements
foreach ($key in $hashTable.Keys) {
    $sourceFile = Get-Content $filePath
    $sourceFile -replace $key, $hashTable[$key] | Set-Content $filePath
    Write-Host 'Replaced key' $key 'with value' $hashTable[$key] 'in' $filePath
}

2 个答案:

答案 0 :(得分:3)

为什么要将替换值定义为JSON字符串?那只会使你的生活更加痛苦。无论如何,如果您要在脚本中定义值,请立即将它们定义为哈希表:

$newUrls = @{
    'Foo'  = 'http://newfoo.example.com'
    'Bar'  = 'http://newbaz.example.com'
    'Blee' = 'http://newblee.example.com'
}

$newKeys = @{
    'Foo' = '67890'
}

即使您想从文件中读取它们,也可以使该文件成为包含这些哈希表的PowerShell脚本并对其进行点源化。或者至少将这些值定义为文本文件中key=value行的列表,可以轻松地将其转换为哈希表:

$newUrls = Get-Content 'new_urls.txt' | Out-String | ConvertFrom-StringData
$newKeys = Get-Content 'new_keys.txt' | Out-String | ConvertFrom-StringData

然后遍历输入JSON数据的顶级属性,并将嵌套属性替换为新值:

$json = Get-Content $filePath | Out-String | ConvertFrom-Json
foreach ($name in $json.PSObject.Properties) {
    $json.$name.BaseUrl = $newUrls[$name]
    if ($newKeys.ContainsKey($name)) {
        $json.$name.UrlKey = $newKeys[$name]
    }
}
$json | ConvertTo-Json | Set-Content $filePath

请注意,如果您的实际JSON数据具有两个以上的层次结构,则需要通过参数ConvertTo-Json告诉-Depth它应该转换多少个层次。


旁注:由于Get-Content期望JSON输入作为单个字符串,因此需要通过Out-String用管道传输ConvertFrom-Json输出,并且使用Out-String可使代码与所有PowerShell一起使用版本。如果您使用的是PowerShell v3或更高版本,则可以通过将Get-Content | Out-String替换为Get-Content -Raw来稍微简化代码。

答案 1 :(得分:0)

谢谢Ansgar的详细回答,这对我有很大帮助。最终,在没有运气遍历输入JSON数据的顶级属性之后,我决定使用以下代码:

$json = (Get-Content -Path $filePath) | ConvertFrom-Json

    $json.Foo.BaseUrl = $newUrls["Foo"]
    $json.Bar.BaseUrl = $newUrls["Bar"]
    $json.Blee.BaseUrl = $newUrls["Blee"]

    $json.Foo.Key = $newKeys["Foo"]

$json | ConvertTo-Json | Set-Content $filePath

我希望这可以帮助其他人。