Edit

Share via


ARM template functions in deployment scopes

With Azure Resource Manager templates (ARM templates), you can deploy to resource groups, subscriptions, management groups, or tenants. Generally, ARM template functions work the same for all scopes. This article describes the differences that exist for some functions and how these differences depend on the scope.

Supported functions

Consider the following when deploying to different scopes:

  • The resourceGroup() function is supported for resource group deployments.

  • The subscription() function is supported for resource-group and subscription deployments.

  • The reference() and list() functions are supported for all scopes.

  • Use resourceId() to get the ID for a resource deployed at the resources group.

    "subnet": {
      "id": "[resourceId(parameters('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnet1Name'))]"
    }
    
  • Use the subscriptionResourceId() function to get the ID for a resource deployed at the subscription.

    For example, to get the resource ID for a policy definition that's deployed to a subscription, use:

    "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]"
    
  • Use the extensionResourceId() function for resources that implement as extensions of the management group. Custom policy definitions that are deployed to the management group are extensions of the management group.

    To get the resource ID for a custom policy definition at the management-group level, use:

    "policyDefinitionId": "[extensionResourceId(variables('mgScope'), 'Microsoft.Authorization/policyDefinitions', parameters('policyDefinitionID'))]"
    
  • Use the tenantResourceId() function to get the ID for a resource deployed at the tenant. Built-in policy definitions are tenant-level resources. When assigning a built-in policy at the management-group level, use the tenantResourceId function.

    To get the resource ID for a built-in policy definition, use:

    "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policyDefinitions', parameters('policyDefinitionID'))]"
    

Function resolution in scopes

When you deploy to more than one scope, the resourceGroup() and subscription() functions resolve differently based on how you specify the template. When you link to an external template, the functions always resolve to the scope for that template. When you nest a template within a parent template, use the expressionEvaluationOptions property to specify if the functions resolve to the resource group and subscription for the parent template or the nested template. Set the property to inner to resolve to the scope for the nested template. Set the property to outer to resolve to the scope of the parent template.

The following table shows if the functions resolve to the parent or embedded resource group and subscription.

Template type Scope Resolution
nested outer (default) Parent resource group
nested inner Sub resource group
linked N/A Sub resource group

The following example template shows a:

  • Nested template with a default (outer) scope.
  • Nested template with an inner scope.
  • Linked template.
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "defaultScopeTemplate",
      "resourceGroup": "inlineGroup",
      "properties": {
        "mode": "Incremental",
        "parameters": {},
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [],
          "outputs": {
            "resourceGroupOutput": {
              "type": "string",
              "value": "[resourceGroup().name]"
            }
          }
        }
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "innerScopeTemplate",
      "resourceGroup": "inlineGroup",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {},
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [],
          "outputs": {
            "resourceGroupOutput": {
              "type": "string",
              "value": "[resourceGroup().name]"
            }
          }
        }
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "linkedTemplate",
      "resourceGroup": "linkedGroup",
      "properties": {
        "mode": "Incremental",
        "parameters": {},
        "templateLink": {
          "contentVersion": "1.0.0.0",
          "uri": "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/resourcegroupname.json"
        }
      }
    }
  ],
  "outputs": {
    "parentRG": {
      "type": "string",
      "value": "[format('Parent resource group is {0}', resourceGroup().name)]"
    },
    "defaultScopeRG": {
      "type": "string",
      "value": "[format('Default scope resource group is {0}', reference('defaultScopeTemplate').outputs.resourceGroupOutput.value)]"
    },
    "innerScopeRG": {
      "type": "string",
      "value": "[format('Inner scope resource group is {0}', reference('innerScopeTemplate').outputs.resourceGroupOutput.value)]"
    },
    "linkedRG": {
      "type": "string",
      "value": "[format('Linked resource group is {0}', reference('linkedTemplate').outputs.resourceGroupOutput.value)]"
    }
  }
}

To test the preceding template and see the results, use PowerShell or the Azure CLI.

New-AzResourceGroup -Name parentGroup -Location southcentralus
New-AzResourceGroup -Name inlineGroup -Location southcentralus
New-AzResourceGroup -Name linkedGroup -Location southcentralus

New-AzResourceGroupDeployment `
  -ResourceGroupName parentGroup `
  -TemplateUri https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/azure-resource-manager/crossresourcegroupproperties.json

The output from the preceding example is:

 Name             Type                       Value
 ===============  =========================  ==========
 parentRG         String                     Parent resource group is parentGroup
 defaultScopeRG   String                     Default scope resource group is parentGroup
 innerScopeRG     String                     Inner scope resource group is inlineGroup
 linkedRG         String                     Linked resource group is linkedgroup

Next steps