Home > Net >  I want to create json file by substituting values from environment variables in a json template file
I want to create json file by substituting values from environment variables in a json template file

Time:11-05

One requirement of mine is - Using windows, not use any tools not already available as part of aws cli or windows For example, I have this json file test.json with below content:

"My number is $myvar"

I read this into a powershell variable like so:

$myobj=(get-content .\test.json | convertfrom-json)

$myvar=1

From here, I would like to do something with this $myobj which will enable me to get this output:

$myobj | tee json_with_values_from_environment.json
My number is 1

I got some limited success with iex, but not sure if it can be made to work for this example

CodePudding user response:

If you want to do this safely you should use the PSParser to find all VariableExpressionAst and replace them with the values in your session. This is clearly more tedious but in my opinion, the way it should be done.

Given the following test.json:

{
  "test1": "My number is $myvar",
  "test2": {
    "somevalue": "$env:myothervar",
    "someothervalue": "$anothervar !!"
  }
}

We want to find and replace $myvar, $myothervar and $anothervar with their corresponding values defined in the current session, so the code looks like this (note that we do the replacement before converting the Json string into an object, this way is much easier):

using namespace System.Management.Automation.Language

$isCore7 = $PSVersionTable.PSVersion -ge '7.2'

# Define the variables here
$myvar = 10
$env:myothervar = 'hello'
$anothervar = 'world'

# Read the Json
$json = Get-Content .\test.json -Raw

# Now parse it
$ast = [Parser]::ParseInput($json, [ref] $null, [ref] $null)
# Find all variables in it,  and enumerate them
$ast.FindAll({ $args[0] -is [VariableExpressionAst] }, $true) |
    Sort-Object { $_.Extent.Text } -Unique | ForEach-Object {
        # now replace the text with the actual value
        if($isCore7) {
            # in PowerShell Core is very easy
            $json = $json.Replace($_.Extent.Text, $_.SafeGetValue($true))
            return
        }
        # in Windows PowerShell not so much
        $varText = $_.Extent.Text
        $varPath = $_.VariablePath

        # find the value of the var (here we use the path)
        $value = $ExecutionContext.SessionState.PSVariable.GetValue($varPath.UserPath)
        if($varPath.DriveName -eq 'env') {
            $value = $ExecutionContext.SessionState.InvokeProvider.Item.Get($varPath.UserPath).Value
        }
        # now replace the text with the actual value
        $json = $json.Replace($varText, $value)
    }

# now we can safely convert the string to an object
$json | ConvertFrom-Json

If we were to convert it back to Json to see the result:

{
  "test1": "My number is 10",
  "test2": {
    "somevalue": "hello",
    "someothervalue": "world !!"
  }
}

CodePudding user response:

You can use $ExecutionContext.InvokeCommand.ExpandString()

$myobj = '{test: "My number is $myvar"}' | ConvertFrom-Json
$myvar = 1
$ExecutionContext.InvokeCommand.ExpandString($myobj.test)

Output

My number is 1
  • Related