Search code examples
jsonpowershellhashtableazure-rm-templateazure-cli

How do you pass an object parameter into a json arm template as a hashtable?


My variable is the following in powershell:

$lcr=@{"tierToCool"=@{"daysAfterModificationGreaterThan"=1};"tierToArchive"=@{"daysAfterModificationGreaterThan"=2}}

Then when I run the template using an az cli command to pass the variable as an object into my arm template:

az deployment group create --subscription <hidden> --resource-group <hidden> --template-file <hidden> --parameters lcr=$lcr

I get the following error:

Failed to parse JSON: System.Collections.Hashtable

Error Detail: Expecting value: line 1 column 1 (char 0)

Is there something wrong with the way I'm passing the parameter into the template or the way I'm formatting it? Any help is greatly appreciated.


Solution

  • Building on the helpful comments:

    • az, the Azure CLI, requires JSON as the --parameters arguments, i.e., a JSON string, not a hashtable.

      • It generally makes no sense to pass a hashtable as an argument to an external program, because doing so sends its string representation, which is - unhelpfully - the type name, 'System.Collections.Hashtable'
    • While --parameters (@{ lcr = $lcr } | ConvertTo-Json -Compress) should be enough to send the JSON representation of your hashtable, the sad reality is that, as of PowerShell 7.1, you additionally need to \-escape the embedded " characters, due to a long-standing bug in argument-passing to external programs.

      • The most robust way to do this is (if there are no escaped " in the string, -replace '"', '\"' is enough):

        --parameters ((@{ lcr = $lcr } | ConvertTo-Json -Compress) -replace '([\\]*)"', '$1$1\"')
        
      • If you have a JSON string literal or JSON string stored in variable, use the following to pass it to an external program (if the string is stored in a variable $var, replace '{ "foo": "bar" }' with $var):

        someProgram ... ('{ "foo": "bar" }' -replace '([\\]*)"', '$1$1\"')
        
      • See this answer for more information.

    Therefore:

    az deployment group create --subscription <hidden> --resource-group <hidden> --template-file <hidden> --parameters ((@{ lcr = $lcr } | ConvertTo-Json -Compress) -replace '([\\]*)"', '$1$1\"')
    

    A general ConvertTo-Json pitfall: You may need to use the -Depth parameter for full to-JSON serialization, depending on how deeply nested your object graph is (not needed with your sample input) - see this post.