ARM - Add multiple VM to Recovery Services Vault (copyIndex) - azure

I'm trying to use the Recovery Services where I can automatically add a VM to Azure Backup via ARM template. I have successfully done this on a single machine deploy, but I'm trying to import it for when multiple VMs are deployed.
Here is where I had help from:
https://www.francoisdelport.com/2017/03/automating-azure-vm-backups-using-arm-templates/
and
Azure ARM JSON template - Add VM to Recovery Services Vault in different Resource Group
Here is a snippet from a single deploy I had working
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "Env1",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', variables('vmName'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "2016-06-01",
"name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', parameters('vmPrefix'), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', parameters('vmPrefix'))]",
"location": "[resourceGroup().location]",
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
"properties": {
"protectedItemType": "Microsoft.Compute/virtualMachines",
"policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
"sourceResourceId": "[resourceId(subscription().subscriptionId, parameters('vmRsg'), 'Microsoft.Compute/virtualMachines', parameters('vmPrefix'))]"
}
}
]
}
}
}
Now I'm trying to use that in a copyIndex form for VM deploy, and here is the code I've been testing with:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adminUsername": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "Username for the Virtual Machine."
}
},
"adminPassword": {
"type": "securestring",
"metadata": {
"description": "Password for the Virtual Machine."
}
},
"dnsNameForPublicIP": {
"type": "string",
"minLength": 1,
"metadata": {
"description": "Globally unique DNS Name for the Public IP used to access the Virtual Machine."
}
},
"windowsOSVersion": {
"type": "string",
"defaultValue": "2012-R2-Datacenter",
"allowedValues": [
"2008-R2-SP1",
"2012-Datacenter",
"2012-R2-Datacenter"
],
"metadata": {
"description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version. Allowed values: 2008-R2-SP1, 2012-Datacenter, 2012-R2-Datacenter."
}
},
"vmCount": {
"type": "int",
"defaultValue": 1
},
"virtualNetworkName": {
"type": "string"
},
"dataDiskCount": {
"type": "int",
"defaultValue": 1
},
"recoveryVault": {
"type": "string",
"metadata": {
"description": "Backup vault name"
}
},
"recoveryPolicy": {
"type": "string",
"metadata": {
"description": "Backcup policy name"
}
},
"vmPrefix": {
"type": "string",
"metadata": {
"description": "Prefix for VM names, used with vmCount to build the VM names"
}
},
"vmRsg": {
"type": "string",
"metadata": {
"description": "Resource group where VMs reside"
}
}
},
"variables": {
"imagePublisher": "MicrosoftWindowsServer",
"imageOffer": "WindowsServer",
"OSDiskName": "osdiskforwindowssimple",
"nicName": "myVMNic",
"subnetName": "Subnet",
"vhdStorageType": "Standard_LRS",
"publicIPAddressName": "myPublicIP",
"publicIPAddressType": "Dynamic",
"vhdStorageContainerName": "vhds",
"vmName": "MWindowsVM",
"vmSize": "Standard_A2",
"virtualNetworkName": "MyVNET",
"vnetId": "[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]",
"subnetRef": "[concat(variables('vnetId'), '/subnets/', variables('subnetName'))]"
},
"resources": [
{
"apiVersion": "2016-03-30",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[concat(variables('publicIPAddressName'), copyIndex(1))]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "PublicIPAddress"
},
"properties": {
"publicIPAllocationMethod": "[variables('publicIPAddressType')]",
"dnsSettings": {
"domainNameLabel": "[concat(parameters('dnsNameForPublicIP'), copyIndex(1))]"
}
},
"copy": {
"name": "publicIpCopy",
"count": "[parameters('vmCount')]"
}
},
{
"apiVersion": "2016-03-30",
"type": "Microsoft.Network/networkInterfaces",
"name": "[concat(variables('nicName'), copyIndex(1))]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "NetworkInterface"
},
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'), copyIndex(1)))]"
],
"properties": {
"ipConfigurations": [
{
"name": "[concat('ipconfig', copyIndex(1))]",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyIndex(1)))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
]
},
"copy": {
"name": "nicCopy",
"count": "[parameters('vmCount')]"
}
},
{
"apiVersion": "2017-03-30",
"copy": {
"name": "nodeCopy",
"count": "[parameters('vmCount')]"
},
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), copyIndex(1))]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "VirtualMachine"
},
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces/', concat(variables('nicName'), copyIndex(1)))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmSize')]"
},
"osProfile": {
"computerName": "[concat(variables('vmName'), copyIndex(1))]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('windowsOSVersion')]",
"version": "latest"
},
"osDisk": {
"createOption": "FromImage"
},
"copy": [
{
"name": "dataDisks",
"count": "[parameters('dataDiskCount')]",
"input": {
"diskSizeGB": 1023,
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty"
}
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyIndex(1)))]"
}
]
}
}
},
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "Env1",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', concat(variables('vmName'), copyIndex(1)))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"copy": {
"name": "protectedItemsCopy",
"count": "[parameters('vmCount')]"
},
"apiVersion": "2017-03-30",
"name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', parameters('vmPrefix'), copyIndex(1), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', parameters('vmPrefix'), copyIndex(1))]",
"location": "[resourceGroup().location]",
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
"properties": {
"protectedItemType": "Microsoft.Compute/virtualMachines",
"policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
"sourceResourceId": "[resourceId(subscription().subscriptionId ,parameters('vmRsg'),'Microsoft.Compute/virtualMachines', concat(parameters('vmPrefix'), copyIndex(1)) )]"
}
}
]
}
}
}
]
}
Sadly it reports an error when trying to deploy, which I can't figure out why because it seems to be correct.
Error: Code=InvalidTemplate; Message=Deployment template validation failed: 'The template resource 'nestedTemplate' at line '198' and column '10' is not valid: The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified. Please see https://aka.ms/arm-copy for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.
The deployment validation failed
FYI, line 198 is "name": "nestedTemplate",
Any ideas, please?

To expand upon #4c74356b41 answer I was missing the all important "index":{ "value": "[copyIndex()]" within "Microsoft.Resources/deployments" on the parent template.
For those wanting to know more, have a look at: https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple
Ensure you have the ('index') parameter next to those items which need to be duplicated, such as "[concat(parameters('WHATEVER'), parameters('index'))]"
I also ended up having a nested source within my linked template for the overall design I was looking for.
So my parent template had a linked (child) template (to another file) with:
name": "[concat('nestings', copyIndex(1))]",
"type": "Microsoft.Resources/deployments", ...
My child template had all the usual buildings of a VM with the parameters ('index') to ensure the items which are duplicated are named correctly.
And finally at the bottom of the child template I had a nested template source so I could back the VM up to another resource group (had to be nested, otherwise you can't do multiple resource groups), which looked like this:
{
"apiVersion": "2017-05-10",
"name": "[concat('nestedTemplate', parameters('index'))]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "Env1",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', concat(variables('vmName'), parameters('index')))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"apiVersion": "2016-06-01",
"name": "[concat( parameters('recoveryVault'), '/Azure/', 'iaasvmcontainer;iaasvmcontainerv2;', parameters('vmRsg') , ';', concat(parameters('vmPrefix'), parameters('index')), '/vm;iaasvmcontainerv2;', parameters('vmRsg'),';', concat(parameters('vmPrefix'), parameters('index')))]",
"location": "[resourceGroup().location]",
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems",
"properties": {
"protectedItemType": "Microsoft.Compute/virtualMachines",
"policyId": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryVault'), parameters('recoveryPolicy'))]",
"sourceResourceId": "[resourceId(subscription().subscriptionId, parameters('vmRsg'), 'Microsoft.Compute/virtualMachines', concat(parameters('vmPrefix'), parameters('index')))]"
}
}
]
}
}
}

So what its telling you that you are not supposed to use copyIndex() function in that place. Now why exactly this is happening I don't know, but I do know that inline templates are a mess (for instance they use parent template paremeters, not nested template), I'm pretty sure if you convert that template to a real nested template (so a linked template, completely separate file) the above syntax will work.
Also, I'm handling this in a separate manner. I'm using 1 single nested deployment for each VM I have, so I'm using copy on the deployment resource, not backup resource.

Related

Deploy functions from ARM, before create event subscription

Using ARM I created a function APP and an event grid topic.
Now, from the same ARM, I want to create a subscription to the topic, but to do it, I need to deploy functions into the function App before.
Is it possible to deploy my functions from the same ARM? Or Do I must to have two different ARMs, one to create all stuff (storage and topics) except functions related and another one the create all resources that need the functions deployed (event subscriptions)? In the second case, I will need to deploy functions in the middle.
I'm looking for one ARM to deploy the full infrastructure from zero (including functions in the function app). Is this possible? How?
According to my test, we can create these resources in one template. For example
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json",
"contentVersion": "1.0.0.0",
"parameters": {
"eventGridTopicName": {
"type": "string",
"defaultValue": "EventGridTopic",
"metadata": {
"description": "The name of the Event Grid custom topic."
}
},
"eventGridSubscriptionName": {
"type": "string",
"defaultValue": "EventGridSub",
"metadata": {
"description": "The name of the Event Grid custom topic's subscription."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location in which the Event Grid resources should be deployed."
}
},
"appName": {
"type": "string",
"defaultValue": "Func",
"metadata": {
"description": "The name of the function app that you wish to create."
}
},
"functionName": {
"type": "string",
"defaultValue": "EventGridFunction",
"metadata": {
"description": "Function App Name"
}
},
"storageAccountType": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"runtime": {
"type": "string",
"defaultValue": "dotnet",
"allowedValues": [
"node",
"dotnet",
"java"
],
"metadata": {
"description": "The language worker runtime to load in the function app."
}
}
},
"variables": {
"eventGridTopic": "[concat(uniquestring(resourceGroup().id),parameters('EventGridTopicName'))]",
"eventGridSub": "[concat(uniquestring(resourceGroup().id),parameters('eventGridSubscriptionName'))]",
"functionUrl": "[concat('https://', variables('FunctionAppName'),'.azurewebsites.net/runtime/webhooks/eventgrid?functionName=', parameters('FunctionName'),'&code=')]",
"functionAppName": "[concat(uniquestring(resourceGroup().id),parameters('appName'))]",
"hostingPlanName": "[parameters('appName')]",
"applicationInsightsName": "[parameters('appName')]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunction')]",
"functionWorkerRuntime": "[parameters('runtime')]"
},
"resources": [
// create event topic
{
"name": "[variables('eventGridTopic')]",
"type": "Microsoft.EventGrid/topics",
"location": "[parameters('location')]",
"apiVersion": "2020-04-01-preview",
},
// create event topic subscrition
{
"name": "[concat(variables('eventGridTopic'), '/Microsoft.EventGrid/', variables('eventGridSub'))]",
"type": "Microsoft.EventGrid/topics/providers/eventSubscriptions",
"location": "[parameters('location')]",
"apiVersion": "2020-04-01-preview",
"dependsOn": [
"[variables('eventGridTopic')]",
"[resourceId('Microsoft.Web/sites/functions/', variables('functionAppName'), parameters('functionName'))]"
],
"properties": {
"destination": {
"endpointType": "AzureFunction",
"properties": {
"resourceId": "[resourceId('Microsoft.Web/sites/functions/', variables('functionAppName'), parameters('functionName'))]"
}
},
"filter": {
}
}
},
// create storage account
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountName')]",
"apiVersion": "2016-12-01",
"location": "[parameters('location')]",
"kind": "Storage",
"sku": {
"name": "[parameters('storageAccountType')]"
}
},
// create host plan
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2018-02-01",
"name": "[variables('hostingPlanName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Y1",
"tier": "Dynamic"
},
"properties": {
"name": "[variables('hostingPlanName')]",
"computeMode": "Dynamic"
}
},
// create function app
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('functionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"[concat('microsoft.insights/components/', variables('applicationInsightsName'))]"
],
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')),'2015-05-01-preview').key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[toLower(variables('functionAppName'))]"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~3"
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(resourceId('microsoft.insights/components/', variables('applicationInsightsName')), '2015-05-01').InstrumentationKey]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "[variables('functionWorkerRuntime')]"
}
]
}
}
},
// create event gride trigger function
{
"apiVersion": "2019-08-01",
"name": "[concat(variables('functionAppName'),'/', parameters('functionName'))]",
"type": "Microsoft.Web/sites/functions",
"dependsOn":[ "[variables('functionAppName')]"],
"properties": {
"config": {
"bindings": [
{
"name": "eventGridEvent",
"direction": "in",
"type": "eventGridTrigger"
}
]
},
"files":{
// the code
"run.csx":"#r \"Microsoft.Azure.EventGrid\"\r\nusing Microsoft.Azure.EventGrid.Models;\r\n\r\npublic static void Run(EventGridEvent eventGridEvent, ILogger log)\r\n{\r\n log.LogInformation(eventGridEvent.Data.ToString());\r\n}"
}
}
},
// create application insight
{
"apiVersion": "2018-05-01-preview",
"name": "[variables('applicationInsightsName')]",
"type": "microsoft.insights/components",
"location": "East US",
"tags": {
"[concat('hidden-link:', resourceGroup().id, '/providers/Microsoft.Web/sites/', variables('applicationInsightsName'))]": "Resource"
},
"properties": {
"ApplicationId": "[variables('applicationInsightsName')]",
"Request_Source": "IbizaWebAppExtensionCreate"
}
}
],
"outputs": {
}
}
For more details, please refer to the blog.

ARM template: issue with output in nested templates

I'm currently facing an issue with nested template.
When I'm applying my template (detail below), I get this answer from Azure:
Azure Error: InvalidTemplate
Message: Deployment template validation failed: 'The template reference 'sandbox.test.portal' is not valid: could not find template resource or resource copy with this name. Please see https://aka.ms/arm-template-expressions/#reference for usage details.'.
However, I don't really understand why I get this issue, because for the content inside the nested template, I used what they provide in the documentation here: https://github.com/Azure/azure-quickstart-templates/blob/master/101-azure-dns-new-zone/azuredeploy.json
My ARM template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"newZoneName": {
"type": "string",
"defaultValue": "sandbox.test.portal",
"metadata": {
"description": "The name of the DNS zone to be created. Must have at least 2 segements, e.g. hostname.org"
}
},
"newRecordName": {
"type": "string",
"defaultValue": "www",
"metadata": {
"description": "The name of the DNS record to be created. The name is relative to the zone, not the FQDN."
}
}
},
"variables": {
"publicIPAddressName": "[concat(resourceGroup().name, '-pip')]",
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "my-rg",
"subscriptionId": "[subscription().subscriptionId]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Network/dnszones",
"name": "[parameters('newZoneName')]",
"apiVersion": "2016-04-01",
"location": "global",
"properties": {
}
},
{
"type": "Microsoft.Network/dnszones/a",
"name": "[concat(parameters('newZoneName'), '/', parameters('newRecordName'))]",
"apiVersion": "2016-04-01",
"location": "global",
"dependsOn": [
"[parameters('newZoneName')]"
],
"properties": {
"TTL": 3600,
"ARecords": [
{
"ipv4Address": "1.2.3.4"
},
{
"ipv4Address": "1.2.3.5"
}
]
}
}
],
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(parameters('newZoneName')).nameServers]"
}
}
}
}
}
]
}
basically, you need to remove the outputs from the nested inline template, so remove this bit:
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(parameters('newZoneName')).nameServers]"
}
}
long story short, nested inline deployments are bad. dont use them.
alternatively move those to the parent template and do a real lookup:
reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')))
You have several minor mistakes in your template:
Comma in variables '-pip')]",
Undefined parameter dnsLabelPrefix
The general mistake in nested outputs. When you use nested templates azure don't find it in your main template. Therefore you must use a reference function with identifier and API: "[reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')), '2016-04-01').nameServers]".
I modified your template and validate in my subscription.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"newZoneName": {
"type": "string",
"defaultValue": "sandbox.test.portal",
"metadata": {
"description": "The name of the DNS zone to be created. Must have at least 2 segements, e.g. hostname.org"
}
},
"newRecordName": {
"type": "string",
"defaultValue": "www",
"metadata": {
"description": "The name of the DNS record to be created. The name is relative to the zone, not the FQDN."
}
},
"dnsLabelPrefix": {
"type": "string",
"defaultValue": "[concat('dns',uniqueString(resourceGroup().name))]"
},
"nestedResourceGroup": {
"type": "string",
"defaultValue": "my-rg",
"metadata": {
"description": "my-rg"
}
}
},
"variables": {
"publicIPAddressName": "[concat(resourceGroup().name, '-pip')]"
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
{
"apiVersion": "2017-05-10",
"name": "nestedTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('nestedResourceGroup')]",
"subscriptionId": "[subscription().subscriptionId]",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Network/dnszones",
"name": "[parameters('newZoneName')]",
"apiVersion": "2016-04-01",
"location": "global",
"properties": {
}
},
{
"type": "Microsoft.Network/dnszones/a",
"name": "[concat(parameters('newZoneName'), '/', parameters('newRecordName'))]",
"apiVersion": "2016-04-01",
"location": "global",
"dependsOn": [
"[resourceId('Microsoft.Network/dnszones', parameters('newZoneName'))]"
],
"properties": {
"TTL": 3600,
"ARecords": [
{
"ipv4Address": "1.2.3.4"
},
{
"ipv4Address": "1.2.3.5"
}
]
}
}
],
"outputs": {
"nameServers": {
"type": "array",
"value": "[reference(resourceId('Microsoft.Network/dnszones', parameters('newZoneName')), '2016-04-01').nameServers]"
}
}
}
}
}
]
}
Have a nice day!

Azure ARM deployment - copyIndex error with multiple NICs

I am trying to deploy the below Palo Alto deployment to an Azure environment. We are using it as an internal firewall for the various features it provides that NSGs don't, so we don't want a public IP. We're using a virtual gateway and sticking the firewall behind it in an active-active pair (the load balancer, NSGs, etc. are being done in a separate template).
I've been trying to get this template to work for a while now, but I'm stuck on deploying the two VMs with multiple NICs. I keep getting this error:
ERROR: Azure Error: InvalidTemplate
Message: Deployment template validation failed: 'The template variable 'nicName' is not valid: The template function 'copyIndex' is not expected at this location. The function can only be used in a resource with copy specified. Please see https://aka.ms/arm-copy for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.
I've tried a bunch of fixes - changing the variable syntax, changing the syntax of the resource, but none of them are working. I've checked the Azure documentation on using the copyIndex feature, but I can't see where I'm going wrong. I was hoping someone with a bit more experience could point out where my syntax is wrong and provide suggestions on how to correct it?
Many thanks, template is below:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"LoadBalancerSku": {
"type": "string",
"allowedValues": [
"Standard",
"Basic"
],
"metadata": {
"description": "Std LB load balances across all the ports where as Basic LB load balances on a port-to-port basis"
},
"defaultValue": "Standard"
},
"storageName": {
"type": "string",
"metadata": {
"description": "Name of the storage account created to store the VM's disks. Storage account name must be globally unique."
},
"defaultValue": "Enter a globally unique name"
},
"mgmtPublicIPDns": {
"type": "string",
"metadata": {
"description": "DNS Name prefix of public IP resource for Management interface of VM-Series firewall. Name must be globally unique."
},
"defaultValue": "Enter a globally unique name"
},
"networkSecurityGroupName": {
"type": "string",
"defaultValue": "nsg",
"metadata": {
"description": "Network Security Group Name"
}
},
"networkSecurityGroupInboundIP": {
"type": "string",
"metadata": {
"description": "Your source public IP address. Added to the inbound NSG on eth0 (MGMT), to restrict access to the deployment."
},
"defaultValue": "1.1.1.1/32"
},
"avSetName": {
"type": "string",
"metadata": {
"description": "Name of the availability set for outbound firewall"
},
"defaultValue": "outbound-avset"
},
"storageType": {
"type": "string",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Premium_LRS",
"Standard_RAGRS"
],
"metadata": {
"description": "Type of the storage account created"
},
"defaultValue": "Standard_LRS"
},
"virtualNetworkName": {
"type": "string",
"defaultValue": "firewall-test",
"metadata": {
"description": "Virtual Network Name"
}
},
"virtualNetworkAddressPrefix": {
"type": "string",
"defaultValue": "10.0.0.0/16",
"metadata": {
"description": "CIDR for Virtual Network"
}
},
"mgmtSubnetName": {
"type": "string",
"defaultValue": "Mgmt",
"metadata": {
"description": "Subnet for Management Network"
}
},
"mgmtSubnetPrefix": {
"type": "string",
"defaultValue": "10.0.0.0/24",
"metadata": {
"description": "CIDR for Management Network"
}
},
"untrustSubnetName": {
"type": "string",
"defaultValue": "Untrust",
"metadata": {
"description": "Subnet for Untrusted Network"
}
},
"untrustSubnetPrefix": {
"type": "string",
"defaultValue": "10.0.1.0/24",
"metadata": {
"description": "CIDR for Untrusted Network"
}
},
"trustSubnetName": {
"type": "string",
"defaultValue": "Trust",
"metadata": {
"description": "Subnet for Trusted Network"
}
},
"trustSubnetPrefix": {
"type": "string",
"defaultValue": "10.0.2.0/24",
"metadata": {
"description": "CIDR for Trusted Network"
}
},
"mgmtPublicIPName": {
"type": "string",
"metadata": {
"description": "Name prefix of public IP resource for Management interface of VM-Series firewall."
},
"defaultValue": "mgmt-pip"
},
"loadBalancerName": {
"type": "string",
"metadata": {
"description": "Name for the outbound load balancer resource."
},
"defaultValue": "outbound-lb"
},
"loadBalancerIP": {
"type": "string",
"metadata": {
"description": "IP Address for the outbound load balancer resource in the Trust network."
},
"defaultValue": "10.0.2.4"
},
"imageSku": {
"type": "string",
"defaultValue": "bundle1",
"allowedValues": [
"byol",
"bundle1",
"bundle2"
],
"metadata": {
"description": "byol = Bring Your Own License; bundle1 = Bundle 1 PAYG (Hourly); bundle2 = Bundle 2 PAYG (Hourly)"
}
},
"virtualMachineName": {
"type": "string",
"metadata": {
"description": "Name prefix of VM-Series VM in the Azure portal"
},
"defaultValue": "outbound-vm-series"
},
"vmSize": {
"type": "string",
"allowedValues": [
"Standard_D3",
"Standard_D4",
"Standard_D3_v2",
"Standard_D4_v2",
"Standard_D5_v2",
"Standard_D14_v2",
"Standard_A4"
],
"metadata": {
"description": "Azure VM size for VM-Series"
},
"defaultValue": "Standard_D3_v2"
},
"authenticationType": {
"type": "string",
"metadata": {
"description": "Type of administrator user authentication "
},
"allowedValues": [
"sshPublicKey",
"password"
],
"defaultValue": "password"
},
"adminUsername": {
"type": "string",
"defaultValue": "pandemo",
"metadata": {
"description": "Username of the administrator account of VM instances"
}
},
"adminPassword": {
"type": "securestring",
"defaultValue": "Dem0pa$$w0rd",
"metadata": {
"description": "Password for the administrator account of all VM instances. This must be specified if Authentication Type is 'password'."
}
},
"sshKey": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "SSH RSA public key file as a string. Must be specified if Authentication Type is 'sshPublicKey'."
}
},
"vmCount": {
"type": "int",
"defaultValue": 2,
"metadata": {
"description": "Number of VM-Series firewall"
}
}
},
"variables": {
"baseUrl": "http://git.lr.net/Azure/management/firewall/tree/master/azure-pan-hub",
"deployStorageURL": "[concat(variables('baseUrl'),'/deployStorage.json')]",
"deployVnetURL": "[concat(variables('baseUrl'),'/deployVnet.json')]",
"deployFirewallURL": "[concat(variables('baseUrl'),'/deployFirewall.json')]",
"location": "[resourceGroup().location]",
"rgname": "[resourceGroup().name]",
"nicName": "[concat(parameters('virtualMachineName'), copyindex())]",
"imagePublisher": "paloaltonetworks",
"imageOffer": "vmseries1",
"version": "latest",
"vnetname": "[parameters('virtualNetworkName')]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('vnetname'))]",
"mgmtSubnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('mgmtSubnetName'))]",
"untrustSubnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('untrustSubnetName'))]",
"trustSubnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('trustSubnetName'))]",
"subnets": [
{
"name": "[parameters('mgmtSubnetName')]",
"properties": {
"addressPrefix": "[parameters('mgmtSubnetPrefix')]"
}
},
{
"name": "[parameters('untrustSubnetName')]",
"properties": {
"addressPrefix": "[parameters('untrustSubnetPrefix')]"
}
},
{
"name": "[parameters('trustSubnetName')]",
"properties": {
"addressPrefix": "[parameters('trustSubnetPrefix')]"
}
}
]
},
"resources": [
{
"name": "deployStorage",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageName')]",
"apiVersion": "2015-06-15",
"location": "[variables('location')]",
"properties": {
"accountType": "[parameters('storageType')]"
}
}
]
}
}
},
{
"name": "deployVnet",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-05-10",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2015-06-15",
"location": "[variables('location')]",
"name": "[variables('vnetname')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('virtualNetworkAddressPrefix')]"
]
},
"subnets": "[variables('subnets')]"
}
}
]
}
}
},
{
"name": "deployAvailabilitySet",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"dependsOn": [
"Microsoft.Resources/deployments/deployStorage",
"Microsoft.Resources/deployments/deployVNet"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Compute/availabilitySets",
"name": "[parameters('avSetName')]",
"location": "[variables('location')]"
}
]
}
}
},
{
"name": "deployMgmtNetworkInterface",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-08-01",
"dependsOn": [
"Microsoft.Resources/deployments/deployStorage",
"Microsoft.Resources/deployments/deployVNet"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "[concat(parameters('virtualMachineName'), copyindex(), '-nic0')]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[variables('location')]",
"apiVersion": "2015-06-15",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', parameters('mgmtPublicIPName'), copyindex())]"
],
"copy": {
"name": "nicLoop",
"count": "[parameters('vmCount')]"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig-mgmt",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[concat(variables('vnetId'),'/subnets/', parameters ('mgmtSubnetName'))]"
}
}
}
]
}
}
]
}
}
},
{
"name": "deployUntrustNetworkInterface",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-08-01",
"dependsOn": [
"Microsoft.Resources/deployments/deployStorage",
"Microsoft.Resources/deployments/deployVNet"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "[concat(parameters('virtualMachineName'), copyindex(), '-nic1-std')]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[variables('location')]",
"apiVersion": "2015-06-15",
"copy": {
"name": "nicLoop",
"count": "[parameters('vmCount')]"
},
"properties": {
"enableIPForwarding": true,
"ipConfigurations": [
{
"name": "ipconfig-untrust",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[concat(variables('vnetId'),'/subnets/', parameters ('untrustSubnetName'))]"
}
}
}
]
}
}
]
}
}
},
{
"name": "deploytrustNetworkInterface",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-08-01",
"dependsOn": [
"Microsoft.Resources/deployments/deployStorage",
"Microsoft.Resources/deployments/deployVNet"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "[concat(parameters('virtualMachineName'), copyindex(), '-nic2')]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[variables('location')]",
"apiVersion": "2015-06-15",
"copy": {
"name": "nicLoop",
"count": "[parameters('vmCount')]"
},
"properties": {
"enableIPForwarding": true,
"ipConfigurations": [
{
"name": "ipconfig-trust",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[concat(variables('vnetId'),'/subnets/', parameters ('trustSubnetName'))]"
}
}
}
]
}
}
]
}
}
},
{
"name": "[concat(parameters('virtualMachineName'), '-std-', copyindex())]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-08-01",
"dependsOn": [
"[concat('Microsoft.Network/networkInterfaces/', parameters('virtualMachineName'), copyindex(), '-nic0')]",
"[concat('Microsoft.Network/networkInterfaces/', parameters('virtualMachineName'), copyindex(), '-nic1-std')]",
"[concat('Microsoft.Network/networkInterfaces/', parameters('virtualMachineName'), copyindex(), '-nic2')]"
],
"copy": {
"name": "vmLoop",
"count": "[parameters('vmCount')]"
},
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(parameters('virtualMachineName'), '-std')]",
"location": "[variables('location')]",
"apiVersion": "2015-05-01-preview",
"plan": {
"name": "[parameters('imageSku')]",
"product": "[variables('imageOffer')]",
"publisher": "[variables('imagePublisher')]"
},
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": {
"computerName": "[parameters('virtualMachineName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('imageSku')]",
"version": "latest"
},
"osDisk": {
"name": "osdisk",
"vhd": {
"uri": "[concat('http://', parameters('storageName'), '.blob.core.windows.net/vhds/', parameters('virtualMachineName'), '-', variables('imageOffer'), '-', parameters('imageSku'), '.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'),'-nic0'))]",
"properties": {
"primary": true
}
},
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'),'-nic1-std'))]",
"properties": {
"primary": false
}
},
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'),'-nic2'))]",
"properties": {
"primary": false
}
}
]
}
}
}
]
}
}
}
]
}
so in general with loops, you can only use copyIndex() function inside loops (and you are trying to use it outside of loop). with variables you can use this (same method applies to property loops):
"variables": {
"copy": [
{
"name": "real_var_name_goes_here",
"count": "how_many_items_with_var",
"input": {
"key": "value" << have to use copyIndex('real_var_name_goes_here')
}
}
]
}
and you'd use normal way for regular loops
Reading:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple

How to use a DocumentDB(MongoDB) connection string as an Environment variable in an Azure Resource Management Template

I want to use a DocumentDB(MongoDB) connection string as an environment variable in an Azure Resource Management Template. Forexample i have a resource group which has a wep app and a DocumentDB(MongoDB) database.
"siteConfig": {
"appSettings": [
{
"name": "db",
"value": "connection string"
}
]
}
How can i assign an environment variable to a connection string in template?
ARM template supports listKeys and list{Value} function, more details we can refer to ARM template function.
We can find DocumentDB list connection strings API, so we can use listconnectionstrings function to get documentdb connection string in the ARM template.
"appSettings": [
{
"name": "db",
"value": " [listConnectionStrings(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('documentdb')), '2015-04-08').connectionStrings[0].connectionString]"
}
It works correct on my side. If we want to add appsetting for WebApp, we also can do with following code
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webSiteName'))]"
],
"tags": {
"displayName": "appsetting"
},
"properties": {
"db": "[listConnectionStrings(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('documentdb')), '2015-04-08').connectionStrings[0].connectionString]"
}
}
]
Check the result from the Azure portal.
Update:
ARM template demo code
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"type": "string",
"minLength": 1
},
"documentdb": {
"type": "string",
"minLength": 1
},
"skuName": {
"type": "string",
"defaultValue": "S1",
"allowedValues": [
"F1",
"D1",
"B1",
"B2",
"B3",
"S1",
"S2",
"S3",
"P1",
"P2",
"P3",
"P4"
],
"metadata": {
"description": "Describes plan's pricing tier and instance size. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
}
},
"skuCapacity": {
"type": "int",
"defaultValue": 1,
"minValue": 1,
"metadata": {
"description": "Describes plan's instance count"
}
}
},
"variables": {
"webSiteName": "[concat('webSite', uniqueString(resourceGroup().id))]",
"docDbName": "tomdocumentdb",
"storageAccountId": "[concat(resourceGroup().id,'/providers/Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"name": "[parameters('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"displayName": "Website"
},
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"properties": {
"name": "[variables('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
},
"resources": [
{
"name": "appsettings",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webSiteName'))]"
],
"tags": {
"displayName": "appsetting"
},
"properties": {
"db": "[listConnectionStrings(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('documentdb')), '2015-04-08').connectionStrings[0].connectionString]"
}
}
]
}
]
}
Paramter file
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"value": "tomtest" //your hostingplan name
},
"skuName": {
"value": "B1"
},
"documentdb": {
"value": "tomdocument" // your documentdb name
}
}
}
After a bit of a struggle:
"appSettings": [{
"Name": "DOCUMENTDB_ENDPOINT",
"Value": "[reference(concat('Microsoft.DocumentDb/databaseAccounts/', parameters('databaseAccountName'))).documentEndpoint]"
}, {
"Name": "DOCUMENTDB_PRIMARY_KEY",
"Value": "[listKeys(resourceId('Microsoft.DocumentDb/databaseAccounts', parameters('databaseAccountName')), '2015-04-08').primaryMasterKey]"
}]

Azure RM Template. Deploy copy VM with unique secret from Key Vault

I would like to be able to create VMs amount of which I specify via parameters (achieved by copy) with different secret for each VM (ex. secret1 for VM1, secret2 for VM2, etc.) Here is a basic example of copy VM template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"numberOfVMs": {
"type": "int",
"defaultValue": 1,
"minvalue": 1
},
"vmAdminUserName": {
"type": "string",
"minLength": 1
},
"vmAdminPassword": {
"type": "securestring"
}
},
"variables": {
"storageAccountName": "[concat('stor567', uniqueString(resourceGroup().id))]",
"storageAccountType": "Standard_LRS",
"vmWindowsOSVersion": "2016-Datacenter",
"vnetPrefix": "10.0.0.0/16",
"vnetSubnet1Name": "Subnet-1",
"vnetSubnet1Prefix": "10.0.0.0/24",
"nicVnetID": "[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]",
"nicSubnetRef": "[concat(variables('nicVnetID'), '/subnets/', variables('vnetSubnet1Name'))]",
"vmImagePublisher": "MicrosoftWindowsServer",
"vmImageOffer": "WindowsServer",
"vmVmSize": "Standard_DS1_v2",
"vmVnetID": "[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]",
"vmSubnetRef": "[concat(variables('vmVnetID'), '/subnets/', variables('vnetSubnet1Name'))]",
"vmStorageAccountContainerName": "vhds"
},
"resources": [
{
"name": "[variables('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"apiVersion": "2015-06-15",
"dependsOn": [ ],
"properties": {
"accountType": "[variables('storageAccountType')]"
}
},
{
"name": "vnet",
"type": "Microsoft.Network/virtualNetworks",
"location": "[resourceGroup().location]",
"apiVersion": "2016-03-30",
"dependsOn": [ ],
"tags": {
"displayName": "vnet"
},
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('vnetPrefix')]"
]
},
"subnets": [
{
"name": "[variables('vnetSubnet1Name')]",
"properties": {
"addressPrefix": "[variables('vnetSubnet1Prefix')]"
}
}
]
}
},
{
"name": "[concat('NIC',copyindex())]",
"type": "Microsoft.Network/networkInterfaces",
"location": "[resourceGroup().location]",
"copy": {
"name": "nicLoop",
"count": "[parameters('numberOfVMs')]"
},
"apiVersion": "2016-03-30",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', 'vnet')]"
],
"tags": {
"displayName": "nic"
},
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('nicSubnetRef')]"
}
}
}
]
}
},
{
"name": "[concat('VM',copyindex())]",
"type": "Microsoft.Compute/virtualMachines",
"location": "[resourceGroup().location]",
"copy": {
"name": "virtualMachineLoop",
"count": "[parameters('numberOfVMs')]"
},
"apiVersion": "2015-06-15",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"nicLoop"
],
"tags": {
"displayName": "vm"
},
"properties": {
"hardwareProfile": {
"vmSize": "[variables('vmVmSize')]"
},
"osProfile": {
"computerName": "[concat('VM',copyindex())]",
"adminUsername": "[parameters('vmAdminUsername')]",
"adminPassword": "[parameters('vmAdminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('vmImagePublisher')]",
"offer": "[variables('vmImageOffer')]",
"sku": "[variables('vmWindowsOSVersion')]",
"version": "latest"
},
"osDisk": {
"name": "vmOSDisk",
"vhd": {
"uri": "[concat(reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2016-01-01').primaryEndpoints.blob, variables('vmStorageAccountContainerName'), '/', 'VM',copyIndex(),'-','OSdisk.vhd')]"
},
"caching": "ReadWrite",
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', concat('NIC',copyindex()))]"
}
]
}
}
}],
"outputs": {}
}
However, I'm struggling to integrate using of password as unique secrets from Key Vault in that template. If I use example from official documentation Reference a secret with static id VMs with secret1 for each VM will be created. And I can’t wrap Reference a secret with dynamic id into nested template because that would deploy my copied VMs again and again for the each number of VMs I would like to deploy. Please help me understand, how this challenge can be solved?
Links: Parent and Nested.
I'm not sure if that's what you meant (because i still think that i struggle to understand your problem).
These templates allow to deploy variable amount of vm's and use different keyvault keys as passwords for those. Example:
2 Windows VM's with one secret and 3 Ubuntu VM's with another
1 Windows VM with one secret and 4 Ubuntu VM's with another
You can easily extend that to other images, like centos.
As you can probably see after looking at the templates I'm using arrays and copyindex() to feed proper values where they belong.
Tell me if that's not what you are after. Be careful when using those, github raw links use some form of caching, so deploying from github might not work for you with errors, in that case just use the links I've provided (NOT RAW) to copy to local machine and upload to some service like pastebin, and deploy from there.

Resources