Archive for August, 2020

ARM Templates: Pass all parameters to a script

I had an interesting inquiry the other day. I was talking to a developer. She had a script which consumed most of the parameters in her ARM template. Every time she added a new parameter, she also had to remember to update the script call to pass the new parameter. She needed a mechanism to just pass all parameters to a bash script.

As a proof of concept, I just wanted to find a way to get the parameters to be saved on a Linux VM. For this, I did some looking at the various ARM template functions and noticed this one: deployment(). deployment() allows access to the ARM template and the parameters which differ in value from the parameter’s defaultValue.

To use the value, I first captured the values of interest in the ARM template variables:

"variables": {
  "uniqueParams": "[deployment().properties.parameters]",
  "defaultParams": "[deployment().properties.template.parameters]",
  "userParams": "[replace(string(variables('uniqueParams')), '\"', '\\\"')]",
  "originalParams": "[replace(string(variables('defaultParams')), '\"', '\\\"')]"
},

Please note that the above variables section was trimmed to just show the capture of the parameters. The string() function turns the object into JSON, replace() does simple string substitution. Once captured, my proof of concept then just wanted to show that the values could be passed along. To do this, I added a custom extension which would emit the data to a well known location.

{
    "type": "Microsoft.Compute/virtualMachines/extensions",
    "apiVersion": "2020-06-01",
    "name": "[concat(variables('vmName'),'/', 'RunScripts')]",
    "location": "[parameters('location')]",
    "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/',variables('vmName'))]"
    ],
    "properties": {
        "publisher": "Microsoft.Azure.Extensions",
        "type": "CustomScript",
        "typeHandlerVersion": "2.1",
        "autoUpgradeMinorVersion":true,
        "settings": {
            "commandToExecute": "[concat('echo \"', variables('userParams'), '\" > /var/userParams.txt')]"
        }
    }
}

Once done, the following was emitted to userParams.txt:

{
  "vmNamePrefix": {
    "value": "scseely"
  },
  "vmSize": {
    "value": "Standard_DS2_v2"
  },
  "pwd": {
    "value": "p@ssw0rd"
  },
  "dnsName": {
    "value": "scseely"
  },
  "publicIPAddressName": {
    "value": "sycompscs"
  }
}

Likewise, if you need the default params as well, the file looks like this:

{
  "vmNamePrefix": {
    "type": "String",
    "metadata": {
      "description": "Assign a prefix for the VM name"
    }
  },
  "location": {
    "defaultValue": "[resourceGroup().location]",
    "type": "String",
    "metadata": {
      "description": "Select the Azure region for the resources"
    }
  },
  "vmSize": {
    "type": "String",
    "metadata": {
      "description": "Select the vm size"
    }
  },
  "userName": {
    "defaultValue": "azureadmin",
    "type": "String",
    "metadata": {
      "description": "Specify the OS username"
    }
  },
  "pwd": {
    "type": "SecureString",
    "metadata": {
      "description": "If Windows, specify the password for the OS username"
    }
  },
  "dnsName": {
    "type": "String",
    "metadata": {
      "description": "Specify the DNS name for the managed web app"
    }
  },
  "publicIPAddressName": {
    "type": "String",
    "metadata": {
      "description": "Assign a name for the public IP address"
    }
  }
}

Now, to read the file back, I can use a tool like jq to load and manipulate the JSON file in my scripts. Because the commandToExecute is just a bash command, I can stitch the emission of the JSON with scripts using ‘&&’.

Leave a comment