'Convert JSON to a PowerShell Object, then, replace that Object with a new Object and convert back to JSON
Background
I have some JSON for a Packer build like so:
{
"builders": [
{
"type": "azure-arm"
}
],
"provisioners": [
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/docker-compose.sh",
"{{template_dir}}/scripts/installers/docker-moby.sh"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}",
"DOCKERHUB_LOGIN\u003d{{user `dockerhub_login`}}",
"DOCKERHUB_PASSWORD\u003d{{user `dockerhub_password`}}"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} {{ .Path }}\u0027"
},
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/azcopy.sh",
"{{template_dir}}/scripts/installers/azure-cli.sh",
"{{template_dir}}/scripts/installers/azure-devops-cli.sh",
"{{template_dir}}/scripts/installers/basic.sh",
"{{template_dir}}/scripts/installers/bicep.sh",
"{{template_dir}}/scripts/installers/aliyun-cli.sh",
"{{template_dir}}/scripts/installers/apache.sh",
"{{template_dir}}/scripts/installers/aws.sh",
"{{template_dir}}/scripts/installers/clang.sh",
"{{template_dir}}/scripts/installers/swift.sh",
"{{template_dir}}/scripts/installers/cmake.sh",
"{{template_dir}}/scripts/installers/codeql-bundle.sh",
"{{template_dir}}/scripts/installers/containers.sh",
"{{template_dir}}/scripts/installers/dotnetcore-sdk.sh",
"{{template_dir}}/scripts/installers/erlang.sh",
"{{template_dir}}/scripts/installers/firefox.sh",
"{{template_dir}}/scripts/installers/gcc.sh",
"{{template_dir}}/scripts/installers/gfortran.sh",
"{{template_dir}}/scripts/installers/git.sh",
"{{template_dir}}/scripts/installers/github-cli.sh",
"{{template_dir}}/scripts/installers/google-chrome.sh",
"{{template_dir}}/scripts/installers/google-cloud-sdk.sh",
"{{template_dir}}/scripts/installers/haskell.sh",
"{{template_dir}}/scripts/installers/heroku.sh",
"{{template_dir}}/scripts/installers/hhvm.sh",
"{{template_dir}}/scripts/installers/java-tools.sh",
"{{template_dir}}/scripts/installers/kubernetes-tools.sh",
"{{template_dir}}/scripts/installers/oc.sh",
"{{template_dir}}/scripts/installers/leiningen.sh",
"{{template_dir}}/scripts/installers/miniconda.sh",
"{{template_dir}}/scripts/installers/mono.sh",
"{{template_dir}}/scripts/installers/kotlin.sh",
"{{template_dir}}/scripts/installers/mysql.sh",
"{{template_dir}}/scripts/installers/mssql-cmd-tools.sh",
"{{template_dir}}/scripts/installers/sqlpackage.sh",
"{{template_dir}}/scripts/installers/nginx.sh",
"{{template_dir}}/scripts/installers/nvm.sh",
"{{template_dir}}/scripts/installers/nodejs.sh",
"{{template_dir}}/scripts/installers/bazel.sh",
"{{template_dir}}/scripts/installers/oras-cli.sh",
"{{template_dir}}/scripts/installers/phantomjs.sh",
"{{template_dir}}/scripts/installers/php.sh",
"{{template_dir}}/scripts/installers/postgresql.sh",
"{{template_dir}}/scripts/installers/pulumi.sh",
"{{template_dir}}/scripts/installers/ruby.sh",
"{{template_dir}}/scripts/installers/r.sh",
"{{template_dir}}/scripts/installers/rust.sh",
"{{template_dir}}/scripts/installers/julia.sh",
"{{template_dir}}/scripts/installers/sbt.sh",
"{{template_dir}}/scripts/installers/selenium.sh",
"{{template_dir}}/scripts/installers/smallstep-cli.sh",
"{{template_dir}}/scripts/installers/terraform.sh",
"{{template_dir}}/scripts/installers/packer.sh",
"{{template_dir}}/scripts/installers/vcpkg.sh",
"{{template_dir}}/scripts/installers/dpkg-config.sh",
"{{template_dir}}/scripts/installers/mongodb.sh",
"{{template_dir}}/scripts/installers/android.sh",
"{{template_dir}}/scripts/installers/yq.sh",
"{{template_dir}}/scripts/installers/pypy.sh",
"{{template_dir}}/scripts/installers/python.sh",
"{{template_dir}}/scripts/installers/graalvm.sh"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}",
"DEBIAN_FRONTEND\u003dnoninteractive"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} {{ .Path }}\u0027"
},
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/Install-Toolset.ps1",
"{{template_dir}}/scripts/installers/Configure-Toolset.ps1"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} pwsh -f {{ .Path }}\u0027"
}
]
}
I am trying to add some items inside the provisioners list, but only inside the second index list called scripts, so in this case the scripts object. Ideally doing this all in PowerShell (I am using PowerShell 7 latest).
What I have tried
Doing some Googling around, it was suggested that I convert the JSON to a PowerShell Object, and then attempt to add to that instead:
$JsonFile = "build.json"
$JsonObject = $(Get-Content $JsonFile -Raw)
$SystemObject=$($JsonObject | ConvertFrom-Json)
$OldScriptsJson = $SystemObject.provisioners[1].scripts | ConvertTo-Json
Which gives me the old JSON which I want to add to:
[
"{{template_dir}}/scripts/installers/azcopy.sh",
"{{template_dir}}/scripts/installers/azure-cli.sh",
"{{template_dir}}/scripts/installers/azure-devops-cli.sh",
"{{template_dir}}/scripts/installers/basic.sh",
"{{template_dir}}/scripts/installers/bicep.sh",
"{{template_dir}}/scripts/installers/aliyun-cli.sh",
"{{template_dir}}/scripts/installers/apache.sh",
"{{template_dir}}/scripts/installers/aws.sh",
"{{template_dir}}/scripts/installers/clang.sh",
"{{template_dir}}/scripts/installers/swift.sh",
"{{template_dir}}/scripts/installers/cmake.sh",
"{{template_dir}}/scripts/installers/codeql-bundle.sh",
"{{template_dir}}/scripts/installers/containers.sh",
"{{template_dir}}/scripts/installers/dotnetcore-sdk.sh",
"{{template_dir}}/scripts/installers/erlang.sh",
"{{template_dir}}/scripts/installers/firefox.sh",
"{{template_dir}}/scripts/installers/gcc.sh",
"{{template_dir}}/scripts/installers/gfortran.sh",
"{{template_dir}}/scripts/installers/git.sh",
"{{template_dir}}/scripts/installers/github-cli.sh",
"{{template_dir}}/scripts/installers/google-chrome.sh",
"{{template_dir}}/scripts/installers/google-cloud-sdk.sh",
"{{template_dir}}/scripts/installers/haskell.sh",
"{{template_dir}}/scripts/installers/heroku.sh",
"{{template_dir}}/scripts/installers/hhvm.sh",
"{{template_dir}}/scripts/installers/java-tools.sh",
"{{template_dir}}/scripts/installers/kubernetes-tools.sh",
"{{template_dir}}/scripts/installers/oc.sh",
"{{template_dir}}/scripts/installers/leiningen.sh",
"{{template_dir}}/scripts/installers/miniconda.sh",
"{{template_dir}}/scripts/installers/mono.sh",
"{{template_dir}}/scripts/installers/kotlin.sh",
"{{template_dir}}/scripts/installers/mysql.sh",
"{{template_dir}}/scripts/installers/mssql-cmd-tools.sh",
"{{template_dir}}/scripts/installers/sqlpackage.sh",
"{{template_dir}}/scripts/installers/nginx.sh",
"{{template_dir}}/scripts/installers/nvm.sh",
"{{template_dir}}/scripts/installers/nodejs.sh",
"{{template_dir}}/scripts/installers/bazel.sh",
"{{template_dir}}/scripts/installers/oras-cli.sh",
"{{template_dir}}/scripts/installers/phantomjs.sh",
"{{template_dir}}/scripts/installers/php.sh",
"{{template_dir}}/scripts/installers/postgresql.sh",
"{{template_dir}}/scripts/installers/pulumi.sh",
"{{template_dir}}/scripts/installers/ruby.sh",
"{{template_dir}}/scripts/installers/r.sh",
"{{template_dir}}/scripts/installers/rust.sh",
"{{template_dir}}/scripts/installers/julia.sh",
"{{template_dir}}/scripts/installers/sbt.sh",
"{{template_dir}}/scripts/installers/selenium.sh",
"{{template_dir}}/scripts/installers/smallstep-cli.sh",
"{{template_dir}}/scripts/installers/terraform.sh",
"{{template_dir}}/scripts/installers/packer.sh",
"{{template_dir}}/scripts/installers/vcpkg.sh",
"{{template_dir}}/scripts/installers/dpkg-config.sh",
"{{template_dir}}/scripts/installers/mongodb.sh",
"{{template_dir}}/scripts/installers/android.sh",
"{{template_dir}}/scripts/installers/yq.sh",
"{{template_dir}}/scripts/installers/pypy.sh",
"{{template_dir}}/scripts/installers/python.sh",
"{{template_dir}}/scripts/installers/graalvm.sh"
]
What I want to do
I basically want to add the following JSON to the old JSON
[
"{{template_dir}}/scripts/installers/colordiff.sh",
"{{template_dir}}/scripts/installers/kubelogin.sh",
"{{template_dir}}/scripts/installers/kubeval.sh",
"{{template_dir}}/scripts/installers/kubeaudit.sh",
"{{template_dir}}/scripts/installers/smallstep-cli.sh"
]
So the final product of all of this can be saved back to the original JSON:
{
"builders": [
{
"type": "azure-arm"
}
],
"provisioners": [
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/docker-compose.sh",
"{{template_dir}}/scripts/installers/docker-moby.sh"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}",
"DOCKERHUB_LOGIN\u003d{{user `dockerhub_login`}}",
"DOCKERHUB_PASSWORD\u003d{{user `dockerhub_password`}}"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} {{ .Path }}\u0027"
},
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/azcopy.sh",
"{{template_dir}}/scripts/installers/azure-cli.sh",
"{{template_dir}}/scripts/installers/azure-devops-cli.sh",
"{{template_dir}}/scripts/installers/basic.sh",
"{{template_dir}}/scripts/installers/bicep.sh",
"{{template_dir}}/scripts/installers/aliyun-cli.sh",
"{{template_dir}}/scripts/installers/apache.sh",
"{{template_dir}}/scripts/installers/aws.sh",
"{{template_dir}}/scripts/installers/clang.sh",
"{{template_dir}}/scripts/installers/swift.sh",
"{{template_dir}}/scripts/installers/cmake.sh",
"{{template_dir}}/scripts/installers/codeql-bundle.sh",
"{{template_dir}}/scripts/installers/containers.sh",
"{{template_dir}}/scripts/installers/dotnetcore-sdk.sh",
"{{template_dir}}/scripts/installers/erlang.sh",
"{{template_dir}}/scripts/installers/firefox.sh",
"{{template_dir}}/scripts/installers/gcc.sh",
"{{template_dir}}/scripts/installers/gfortran.sh",
"{{template_dir}}/scripts/installers/git.sh",
"{{template_dir}}/scripts/installers/github-cli.sh",
"{{template_dir}}/scripts/installers/google-chrome.sh",
"{{template_dir}}/scripts/installers/google-cloud-sdk.sh",
"{{template_dir}}/scripts/installers/haskell.sh",
"{{template_dir}}/scripts/installers/heroku.sh",
"{{template_dir}}/scripts/installers/hhvm.sh",
"{{template_dir}}/scripts/installers/java-tools.sh",
"{{template_dir}}/scripts/installers/kubernetes-tools.sh",
"{{template_dir}}/scripts/installers/oc.sh",
"{{template_dir}}/scripts/installers/leiningen.sh",
"{{template_dir}}/scripts/installers/miniconda.sh",
"{{template_dir}}/scripts/installers/mono.sh",
"{{template_dir}}/scripts/installers/kotlin.sh",
"{{template_dir}}/scripts/installers/mysql.sh",
"{{template_dir}}/scripts/installers/mssql-cmd-tools.sh",
"{{template_dir}}/scripts/installers/sqlpackage.sh",
"{{template_dir}}/scripts/installers/nginx.sh",
"{{template_dir}}/scripts/installers/nvm.sh",
"{{template_dir}}/scripts/installers/nodejs.sh",
"{{template_dir}}/scripts/installers/bazel.sh",
"{{template_dir}}/scripts/installers/oras-cli.sh",
"{{template_dir}}/scripts/installers/phantomjs.sh",
"{{template_dir}}/scripts/installers/php.sh",
"{{template_dir}}/scripts/installers/postgresql.sh",
"{{template_dir}}/scripts/installers/pulumi.sh",
"{{template_dir}}/scripts/installers/ruby.sh",
"{{template_dir}}/scripts/installers/r.sh",
"{{template_dir}}/scripts/installers/rust.sh",
"{{template_dir}}/scripts/installers/julia.sh",
"{{template_dir}}/scripts/installers/sbt.sh",
"{{template_dir}}/scripts/installers/selenium.sh",
"{{template_dir}}/scripts/installers/smallstep-cli.sh",
"{{template_dir}}/scripts/installers/terraform.sh",
"{{template_dir}}/scripts/installers/packer.sh",
"{{template_dir}}/scripts/installers/vcpkg.sh",
"{{template_dir}}/scripts/installers/dpkg-config.sh",
"{{template_dir}}/scripts/installers/mongodb.sh",
"{{template_dir}}/scripts/installers/android.sh",
"{{template_dir}}/scripts/installers/yq.sh",
"{{template_dir}}/scripts/installers/pypy.sh",
"{{template_dir}}/scripts/installers/python.sh",
"{{template_dir}}/scripts/installers/graalvm.sh",
"{{template_dir}}/scripts/installers/colordiff.sh",
"{{template_dir}}/scripts/installers/kubelogin.sh",
"{{template_dir}}/scripts/installers/kubeval.sh",
"{{template_dir}}/scripts/installers/kubeaudit.sh",
"{{template_dir}}/scripts/installers/smallstep-cli.sh"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}",
"DEBIAN_FRONTEND\u003dnoninteractive"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} {{ .Path }}\u0027"
},
{
"type": "shell",
"scripts": [
"{{template_dir}}/scripts/installers/Install-Toolset.ps1",
"{{template_dir}}/scripts/installers/Configure-Toolset.ps1"
],
"environment_vars": [
"HELPER_SCRIPTS\u003d{{user `helper_script_folder`}}",
"INSTALLER_SCRIPT_FOLDER\u003d{{user `installer_script_folder`}}"
],
"execute_command": "sudo sh -c \u0027{{ .Vars }} pwsh -f {{ .Path }}\u0027"
}
]
}
How can I go about that using PowerShell?
Solution 1:[1]
This should do it:
$json = Get-Content 'Build.json' -Raw | ConvertFrom-Json
# Define an array of strings to add.
$scriptsToAdd = @(
'{{template_dir}}/scripts/installers/colordiff.sh'
'{{template_dir}}/scripts/installers/kubelogin.sh'
'{{template_dir}}/scripts/installers/kubeval.sh'
'{{template_dir}}/scripts/installers/kubeaudit.sh'
'{{template_dir}}/scripts/installers/smallstep-cli.sh'
)
# Alternatively read these from a JSON file as well:
# $scriptsToAdd = Get-Content 'ScriptsToAdd.json' -Raw | ConvertFrom-Json
# Append the $scriptsToAdd array to the scripts array of the JSON
$json.provisioners[1].scripts += $scriptsToAdd
# Make sure to specify a large enough argument for -Depth, which defaults to 2.
# Otherwise objects that are nested deeper will be truncated.
$json | ConvertTo-Json -Depth 100 | Set-Content 'BuildNew.json'
As for what you have tried:
$OldScriptsJson = $SystemObject.provisioners[1].scripts | ConvertTo-Json
You just converted part of the original JSON object back to a JSON string. When working with JSON, you should always operate on the object and only as a final step, convert back to the serialized JSON, which can be a string or a file.
Solution 2:[2]
$SystemObject = get-content build.json | convertfrom-json
# load changes into another object
$addobject = get-content add.json | convertfrom-json
# add 2 arrays together (+= kills puppies in bulk)
$SystemObject.provisioners[1].scripts += $addobject
# save, watch out for default depth of 2, the latest ps 7 gives a warning
# "WARNING: Resulting JSON is truncated as serialization has exceeded the set depth
# of 2."
$SystemObject | ConvertTo-Json -Depth 3 | set-content build2.json
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
