The new ARM resource type Microsoft.Resources/deploymentScripts allows you to execute scripts within template deployments, capture the script outputs and re-use them later within the rest of the template.

Whilst the documentation goes some way to help you monitor and troubleshoot when the script doesn’t work as planned using the provided script service storage accounts, out of the box,I didn’t find these particularly helpful to identify why I wasn’t getting the required outputs from my inline bash script.

In order to help yourself debug, you’ll need to change the cleanUpPreference property, the default onSuccess will clear down the debug contents, meaning you don’t have anywhere to grab the output logs from. Careful here, as onSuccess could just mean that your script executed ok, not necessarily that it provided the result you expected. Here I’m setting it to onExpiration to the provided retentionInterval period.

"properties": 
{
  "forceUpdateTag": "[parameters('utcValue')]",
  "AzCliVersion": "2.15.0",
  "timeout": "PT30M",
  "arguments": "",
  "scriptContent": "",
  "cleanupPreference": "OnExpiration",
  "retentionInterval": "P1D"
}

Using inline scripts

I’m not usually a fan of condensing multiple lines of any script (bash/powershell) into one line, which you’ll then need to escape, so that you can smash it into a json property within the ARM template - making it totally unreadable for your future self (or unfortunate others). However, sometimes it makes the dev-loop quicker when you’re still working things out with the rest of your automated deployment.

So, when your scriptContent doesn’t work as planned, you’ve triple-checked it works locally, what are you now supposed to do? It’s a black-hole debug experience, or so I initially thought…

DeploymentScript artifacts

As mentioned earlier, all of the script files are stored within the provided script storage account.

  • azscriptinput
    • DeploymentScript.sh - Azure Cli deployment script execution engine uses this script to initialize context and collect outputs of user script execution
    • userscript.sh - The contents of the scriptContent property (not very useful)
  • azscriptoutput
    • executionresult.json - Execution summary of script start/end time and the overall result (half-useful)
    • scriptoutputs.json - The json output of your bash script (only useful if the script works as intended)

DeploymentScript json outputs

As per the documentation your bash script MUST output json conforming to the following schema:

{
  "result": {
    "property1": "value",
    "property2": "value"
  }
}

And within your ARM template outputs you need to reference this output values like this:

"outputs": {
    "Property1OutputVar": {
        "value": "[reference('runBashWithOutputs').outputs.result.property1]",
        "type": "string"
    },
    "Property2OutputVar": {
        "value": "[reference('runBashWithOutputs').outputs.result.property2]",
        "type": "string"
    }        
}

In my case, my inline script was executing successfully, but my actual values were empty:

{
  "result": {
    "appId": "",
    "appSecret": ""
  }
}

AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY

Time to add some debugging into our script, but how can we do that? Looking in the DeploymentScript.sh mentioned above, you’ll find a bunch of other variables, one of which is AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY, so we can use this location to dump any of our custom script outputs to 😀

So by doing the following in the inline script, we can now add some tracing inside the script, and the output will be moved into the storage account with the rest of the outputs.

"properties": 
{
  "AzCliVersion": "2.15.0",
  "forceUpdateTag": "[parameters('utcValue')]",
  "timeout": "PT30M",
  "arguments": "[parameters('appName')]",
  "scriptContent": "appName=$1; echo $appName > $AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY/app; echo $(az account list) > $AZ_SCRIPTS_PATH_OUTPUT_DIRECTORY/account; ...<rest of script has been removed>",
  "cleanupPreference": "OnExpiration",
  "retentionInterval": "P1D"
}

Here you can see I’m dumping both the input appName parameter value and the output from the az account list command to different files in the script storage output:

Hope this helps others.