'How to convert an array into properties of one object in an ARM template?

I am looking for a way to convert an array (e.g. of strings) into one object, where the properties are generated from the array values.

Use case: I want to generate a tags object with links to resources, based on a list of resource names. I need to do this, to link App Service resources to an Application Insights resource.

The list of resources could be supplied using a parameter:

"parameters": {
  "appServices": {
    "type": "array",
    "metadata": {
      "description": "Names of app services to link this application insights resource to via hidden tags"
    }
  }
}

Sample input:

['appName1', 'appName2', 'appName3']

Sample output:

"tags":
{
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName1'))]": "Resource",
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName2'))]": "Resource",
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName3'))]": "Resource"
}

I know you can use copy to loop over arrays but that will create an array of objects and not a single object (which is required for tags), for example:

[
{
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName1'))]": "Resource"
},
{
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName2'))]": "Resource"
},
{
  "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', 'appName3'))]": "Resource"
}
]

It would be possible to use union to merge those objects again, but that function requires you to hardcode the objects you want to merge, so it does not work when you have an input with variable length.

What I am looking for is a way to do this in a dynamic way.



Solution 1:[1]

There is no direct option to convert array to object. But here's a hack to achieve what you need. This will work for array of any length.

Steps:

  1. append hidden-link text to service names
  2. convert array to string
  3. replace necessary symbols and make it a valid json string.
  4. use json() to convert string to object
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appServices": {
      "type": "array",
      "metadata": {
        "description": "Names of app services to link this application insights resource to via hidden tags"
      },
      "defaultValue": [ "appName1", "appName2", "appName3" ]
    }
  },
  "functions": [],
  "variables": {
    "copy": [
      {
        "name": "as",
        "count": "[length(parameters('appServices'))]",
        "input": "[concat('hidden-link:', resourceId('Microsoft.Web/sites/', parameters('appServices')[copyIndex('as')]))]"
      }
    ],
    "0": "[string(variables('as'))]",
    "1": "[replace(variables('0'), '[', '{')]",
    "2": "[replace(variables('1'), '\",', '\":\"Resource\",')]",
    "3": "[replace(variables('2'), '\"]', '\":\"Resource\"}')]"
  },
  "resources": [],
  "outputs": {
    "op1": {
      "type": "object",
      "value": "[json(variables('3'))]"
    }
  }
}

enter image description here

Solution 2:[2]

I'm not sure if this is the best approach to this problem.

Tags are supposed to be metadata about a specific object/service. Wouldn't it make more sense to apply a tag (say your system name, environment, etc..) and then run a query against azure on that tag?

This should achieve the same result pulling back all related resources.

Solution 3:[3]

I don't know if it is still relevant, but since 2021 it is possible to do with items() function

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 DreadedFrost
Solution 3 Snoopy