Here is my parameter file:
"VNetSettings": {
"value": {
"name": "VNet1",
"addressPrefixes": "10.0.0.0/16",
"subnets": [
{
"name": "sub1",
"addressPrefix": "10.0.1.0/24"
},
{
"name": "sub2",
"addressPrefix": "10.0.2.0/24"
}
]
}
}
Here is my deployment file(deploy.json)
{
"contentversion": "1.0.0.0",
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"parameters": {
"VNetSettings": {
"type": "object"
},
"noofsubnets": {
"type": "int"
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/virtualNetworks",
"name": "[parameters('VNetSettings').name]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('VNetSettings').addressPrefixes]"
]
},
"copy": {
"name": "subnets",
"count": "[parameters('noofsubnets')]",
"input": {
"name": "[parameters('VNetSettings').subnets[copyIndex('subnets',1)].name]",
"properties": {
"addressPrefix": "[parameters('VNetSettings').subnets[copyIndex('subnets',1)].addressPrefix]"
}
}
}
}
}
]
}
What the deployment arm template should be doing is launch the subnets with their respective address prefixes (eg: sub1 -> 10.0.1.0/24,sub2 -> 10.0.2.0/24) but when I execute the template from the powershell using the following command:
New-AzureRmResourceGroupDeployment -Name testing -ResourceGroupName rgname -TemplateFile C:\Test\deploy.json -TemplateParameterFile C:\Test\parameterfile.json
I get displayed with the following error:
The template function 'copyIndex' is not expected at this location.
The function can only be used in a resource with copy specified. Error
says there is something wrong with the copyindex() but I'm unable to
find out what exactly is wrong with it.
Copy has to look like this:
"copy": [
{
"name": "xxx",
"count": "xxx",
"input": { ... }
}
]
You are missing []
copy shouldn't be inside the properties field. It has to be at the same level as properties.
Related
I have a JSON ARM template which creates multiple vms through a loop, I thought I could add encryptvm at the end of the loop and it would encrypt all the disks.
However it keeps failing with a strange error
The full json is here:
https://pastebin.com/embed_iframe/Lxmb7Y42
I've used both these parameters.
, parameters('VMNames'), copyIndex(1))]",
and
, parameters('VMNames'))]"
but neither seems to work.
All I'm doing essentially is adding the following resource section in:
"resources": [
{
"name": "[concat(parameters('VMNames'),'UpdateEncryptionSettings)']",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNames'))]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/encryptVm.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"vmName": {
"value": "[parameters('VMNames')]"
},
"aadClientID": {
"value": "[parameters('aadClientID')]"
},
"aadClientSecret": {
"value": "[parameters('aadClientSecret')]"
},
"keyVaultName": {
"value": "[parameters('keyVaultName')]"
},
"keyVaultResourceGroup": {
"value": "[parameters('keyVaultResourceGroup')]"
},
"useExistingKek": {
"value": "[parameters('useExistingKek')]"
},
"keyEncryptionKeyURL": {
"value": "[parameters('keyEncryptionKeyURL')]"
},
"_artifactsLocation": {
"value": "[parameters('_artifactsLocation')]"
},
"_artifactsLocationSasToken": {
"value": "[parameters('_artifactsLocationSasToken')]"
}
}
}
},
{
"apiVersion": "2017-05-10",
"name": "[concat(parameters('VMNames'),'recoveryServicesVault')]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('recoveryServicesVaultResourceGroup')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNames'))]"
// "[resourceId('Microsoft.Resources/deployments/', concat(parameters('VMNames'), copyIndex(1),'UpdateEncryptionSettings'))]"
],
"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('recoveryServicesVaultName'), '/', 'Azure', '/', variables('rsvV2vm'), resourceGroup().name, ';', parameters('VMNames'))]",
"apiVersion": "2017-07-01",
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/backupProtectionIntent",
"properties": {
"friendlyName": "[concat(parameters('VMNames'), copyIndex(1), 'BackupIntent')]",
"protectionIntentItemType": "AzureResourceItem",
"policyId": "[resourceId(parameters('recoveryServicesVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryServicesVaultName'), parameters('recoveryServicesVaultBackupPolicyName'))]",
"sourceResourceId": "[resourceId(resourceGroup().name, 'Microsoft.Compute/virtualMachines', parameters('VMNames'))]"
}
}
]
}
}
}
]
Can't see where I'm going wrong. Maybe I've added it in the wrong place, but checking on JSON validator tools online and everything seems fine.
this template is due to the fact you are defining your deployment once for each vm, but you are giving each deployment the same name:
"name": "[concat(parameters('VMNames'),'UpdateEncryptionSettings')]",
"type": "Microsoft.Resources/deployments",
you need to add copyIndex() function to this name
I am trying to deploy multiple Azure VNETs using the code below,it
it gives error below
{
"error": {
"code": "InvalidTemplate",
"details": null,
"message": "Deployment template validation failed: 'The template resource '[concat(variables('namePrefix'), parameters('VNetSettings').vnets.name, [copyIndex(1)])]' at line '1' and column '923' is not valid: The language expression property 'name' has an invalid array index.. Please see https://aka.ms/arm-template-expressions for usage details.'.",
"target": null
},
"properties": null
}
This is my Code below. I want to use coyIndex to loop through multiple instances of azure virtual networks. Based on number of vnet names provided i want it get number of instances to be created.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"VNetSettings": {
"type": "object"
},
"namingSettings": {
"type": "object"
}
},
"variables": {
"namePrefix": "[concat(parameters('namingSettings').name.org,'-',parameters('namingSettings').name.accountEnv,'-',parameters('namingSettings').name.sdlcEnv,'-',parameters('namingSettings').name.region,'-',parameters('namingSettings').name.appname,'-')]"
},
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[concat(variables('namePrefix'), parameters('VNetSettings').vnets.name, [copyIndex(1)])]",
"location": "[resourceGroup().location]",
"copy": {
"name": "vnetcopy",
"count": "[length(parameters('VNetSettings').vnets.name)]"
},
"scale": null,
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('VNetSettings').vnets.cidr]"
]
}
}
}
]
}
Update
Parameter fileenter code here
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters":{
"namingSettings": {
"value": {
"name": {
"org": "it",
"accountEnv": "nonprod",
"sdlcEnv": "it-test",
"region": "eastus2",
"tier": "",
"object": "",
"networkbuild": "network",
"auditbuild": "audit",
"automationbuild": "automation",
"dnsbuild": "dns",
"appname": "network"
}
}
},
"VNetSettings": {
"value": {
"vnets": [
{
"name": "vnet0",
"cidr": "10.10.10.0/24",
}
],
}
}
}
}
Your concat() input is wrong. copyIndex() should not be inside []. Try this:
"[concat(variables('namePrefix'), parameters('VNetSettings').vnets.name, copyIndex(1))]"
copyIndex() is just another function, you only wrap the string with [] once no matter how many functions are inside
you need to adjust your template to reflect the fact you are iterating over an array (right now you iterate over the name, and vnets.name is not a valid construct in the ARM Templates).
you need to do something like this:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"VNetSettings": {
"type": "object"
},
"namingSettings": {
"type": "object"
}
},
"variables": {
"namePrefix": "[concat(parameters('namingSettings').name.org,'-',parameters('namingSettings').name.accountEnv,'-',parameters('namingSettings').name.sdlcEnv,'-',parameters('namingSettings').name.region,'-',parameters('namingSettings').name.appname,'-')]"
},
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[concat(variables('namePrefix'), parameters('VNetSettings').vnets[copyIndex()].name)]",
"location": "[resourceGroup().location]",
"copy": {
"name": "vnetcopy",
"count": "[length(parameters('VNetSettings').vnets)]"
},
"scale": null,
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('VNetSettings').vnets[copyIndex()].cidr]"
]
}
}
}
]
}
notice you need to use copyIndex() to get to the current vnet in your array and you need to use the .vnet to determine length
The aim of the template is to add subnets to an existing Vnet but when executing it using the powershell command
New-AzureRmResourceGroupDeployment -Name testing -ResourceGroupName rgname -TemplateFile C:\Test\deploy.json -TemplateParameterFile C:\Test\parameterfile.json
The following error is displayed and I really cant understand what it means.Here is the error *
"Error: Code=InvalidRequestContent; Message=The request content was invalid and could not be deserialized: 'Cannot populate JSON
array ontotype'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Templates.Schema.TemplateResourceCopy'. Path 'properties.template.resources[0].copy' "*
Following is my input file(parameter.json)
{
"VNetSettings":{
"value":{
"name":"VNet2",
"addressPrefixes":"10.0.0.0/16",
"subnets":[
{
"name": "sub5",
"addressPrefix": "10.0.5.0/24"
},
{
"name":"sub6",
"addressPrefix":"10.0.6.0/24"
}
]
}
}
}
The following is my template(deploy.json)
{
"contentversion":"1.0.0.0",
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"parameters":{
"VNetSettings":
{"type":"object"},
"noofsubnets":
{
"type":"int"
}
},
"resources":
[
{
"type":"Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2015-06-15",
"location":"[resourceGroup().location]",
"copy": [
{
"name":"subnets",
"count":"[parameters('noofsubnets')]",
"input": {
"name": "[concat(parameters('VNetSettings').name, '/',parameters('VNetSettings').subnets[copyIndex('subnets')].name)]",
"properties":{
"addressPrefix": "[parameters('VNetSettings').subnets[copyIndex('subnets')].addressPrefix]"
}
}
}
]
}
]
}
I guess the error should be in and around the copy statement.
if you create a subnet resource, you need to structure json like a full blown resource:
"name": "[concat('bla/bla-', copyIndex())]",
"type": xxx,
"apiVersion": xxx,
"location": xxx,
"copy": {
"name": xxx,
"count": xxx
},
"properties": {
"addressPrefix": xxx
}
and just use copyIndex() function. without 'subnets'
Here is the solution.Thanks to #4c74356b41 for your leads.
{
"contentversion":"1.0.0.0",
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"parameters":{
"VNetSettings":{"type":"object"},
"noofsubnets":
{
"type":"int"
}
},
"variables":
{
"vnetname":"[parameters('VNetSettings').name]"
},
"resources":
[
{
"type":"Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(variables('vnetname'), '/',parameters('VNetSettings').subnets[copyIndex()].name)]",
"apiVersion": "2015-06-15",
"location":"[resourceGroup().location]",
"properties":{
"addressPrefix": "[parameters('VNetSettings').subnets[copyIndex()].addressPrefix]"
},
"copy":{
"name":"subnetcopy",
"count":"[parameters('noofsubnets')]"
}
}
]
}
According to https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#property-iteration it should be possible to create multiple values on a resource using copy but I can't make it work. Here is my code...
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"appServiceName": {
"type": "string",
"metadata": {
"description": "Name of app service to apply SSL to."
}
},
"certificateName": {
"type": "string",
"metadata": {
"description": "User friendly certificate resource name"
}
},
"appServicePlan": {
"type": "string",
"metadata": {
"description": "App Service Plan Name"
}
},
"keyVaultId": {
"type": "string",
"metadata": {
"description": "Existing Key Vault resource Id with an access policy to allow Microsoft.Web RP to read Key Vault secrets (Checkout README.md for more information)"
}
},
"hostname": {
"type": "array",
"metadata": {
"description": "Custom hostname for creating SSL binding. This hostname should already be assigned to the Web App"
}
}
},
"resources": [
{
"apiVersion": "2017-03-30",
"type": "Microsoft.Web/sites",
"name": "[parameters('appServiceName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/certificates', parameters('certificateName'))]"
],
"properties": {
"copy": [
{
"name": "hostnames",
"count": "[length(parameters('hostname'))]",
"input": {
"name": "[copyIndex('hostnames')]",
"properties": {
"hostNameSslStates": [
{
"name": "[[copyIndex(hostname)]]",
"sslState": "SniEnabled",
"thumbprint": "[reference(resourceId('Microsoft.Web/certificates', parameters('certificateName'))).Thumbprint]",
"toUpdate": true
}
]
}
}
}
]
}
},
{
"type": "Microsoft.Web/certificates",
"name": "[parameters('certificateName')]",
"apiVersion": "2016-03-01",
"location": "[resourceGroup().location]",
"properties": {
"keyVaultId": "[parameters('keyVaultId')]",
"keyVaultSecretName": "[parameters('certificateName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms',parameters('appServicePlan'))]"
}
}
]
}
And it returns Error: Code=InvalidTemplate; Message=Deployment template l
anguage expression evaluation failed: 'Unable to parse language expression 'copyIndex(hostname)]': expecte
d token 'LeftParenthesis' and actual 'RightParenthesis'.'. Please see https://aka.ms/arm-template-expressi
ons for usage details.
Any ideas what am I doing wrong?
Thanks in advance!
the error gives is away:
change "[[copyIndex(hostname)]]", to "[copyIndex('hostname')]"
you even have it right in other places, why not here?
and you probably want to do this:
"[parameters('hostname')[copyIndex('hostname')]]"
I've looked at the https://github.com/Azure/azure-quickstart-templates/tree/master/101-servicebus-topic example. Now I'm trying to figure out how to create several topics when running the deploy script using nested resource looping (https://azure.microsoft.com/en-us/documentation/articles/resource-group-create-multiple/#looping-on-a-nested-resource).
It would be nice to just define an array in the value for serviceBusTopicName and then somehow creating topics by looping through it, instead of doing it manually.
I am getting the following error when trying to deploy.
Error: Code=InvalidTemplate; Message=Deployment template validation failed: 'The template resource '[parameters('serviceBusTopicName')[copyIndex()]]' at line '72' column '14' is not valid.
Copying nested resources is not supported. Please see https://aka.ms/arm-copy/#looping-on-a-nested-resource for usage details.'.
This is the template.json that I have tried to get to work.
"parameters": {
"serviceBusNamespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusTopicName": {
"type": "array",
"metadata": {
"description": "Name of the Topic"
}
},
"serviceBusApiVersion": {
"type": "string",
"defaultValue": "2015-08-01",
"metadata": {
"description": "Service Bus ApiVersion used by the template"
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"name": "[parameters('serviceBusNamespaceName')]",
"type": "Microsoft.ServiceBus/Namespaces",
"location": "[variables('location')]",
"kind": "Messaging",
"sku": {
"name": "StandardSku",
"tier": "Standard"
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"name": "[parameters('serviceBusTopicName')]",
"type": "Topics",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceName'))]"
],
"properties": {
"path": "[parameters('serviceBusTopicName')]"
},
"copy": {
"name": "datasetcopy",
"count": "[length(parameters('serviceBusTopicName'))]"
}
}
]
},
parameters.json
{"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceName": {
"value": "ServiceBus"
},
"serviceBusTopicName": {
"value": [
"Person",
"Stadium",
"Team"
]
},
"serviceBusApiVersion": {
"value": "2015-08-01"
}
}
As #Lain said, copying nested resource isn't supported as of now Check Here. For deploying multiple resource you have to move it to root. I just finished my POC for deploying multiple topics (Just topics assuming Namespace already exists) here is the code. I am passing topic names as a comma separated string:
{
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Service Bus namespace"
}
},
"serviceBusTopicName": {
"type": "string",
"metadata": {
"description": "Comma seperated Topic Names"
}
},
"serviceBusApiVersion": {
"type": "string",
"defaultValue": "2015-08-01",
"metadata": {
"description": "Service Bus ApiVersion used by the template"
}
}
},
"variables": {
"location": "[resourceGroup().location]",
"sbVersion": "[parameters('serviceBusApiVersion')]",
"TopicNames": "[split(parameters('serviceBusTopicName'), ',')]"
},
"resources": [{
"apiVersion": "[variables('sbVersion')]",
"name": "[concat(parameters('serviceBusNamespaceName'), '/', variables('TopicNames')[copyIndex()])]",
"type": "Microsoft.ServiceBus/Namespaces/Topics",
"copy": {
"name": "TopicNameCopy",
"count": "[length(variables('TopicNames'))]"
},
"properties": {
"path": "[variables('TopicNames')[copyIndex()]]"
}
}]
}
The link in the error message goes through this pretty well, but you can't have loops in nested resources, you need to push the resource up to the top level, and then link the resources together using names. This template will do what you seem to be trying to do:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"serviceBusNamespaceName": {
"type": "string",
"metadata": {
"description": "Name of the Service Bus Namespace"
}
},
"serviceBusTopicNames": {
"type": "array",
"metadata": {
"description": "Name of the Service Bus Topic"
}
}
},
"variables": {
"sbVersion": "2015-08-01"
},
"resources": [
{
"apiVersion": "[variables('sbVersion')]",
"name": "[parameters('serviceBusNamespaceName')]",
"type": "Microsoft.ServiceBus/namespaces",
"location": "[resourceGroup().location]",
"properties": {
}
},
{
"apiVersion": "[variables('sbVersion')]",
"name": "[concat(parameters('serviceBusNamespaceName'), '/', parameters('serviceBusTopicNames')[copyIndex()])]",
"type": "Microsoft.ServiceBus/namespaces/Topics",
"dependsOn": [
"[concat('Microsoft.ServiceBus/namespaces/', parameters('serviceBusNamespaceName'))]"
],
"copy": {
"name": "datasetcopy",
"count": "[length(parameters('serviceBusTopicNames'))]"
},
"properties": {
"path": "[parameters('serviceBusTopicNames')[copyIndex()]]"
},
"resources": [
]
}
]
}