I'm trying to make my parameter file a bit smarter but for the life of me can't figure out how to do so. I have a parameters.json file with 2 params: env & commonTags. env takes a string from my DevOps pipeline, and I need this parameter to fill a value in the commonTags-object parameter. See code snippet below:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"env": {
},
"location": {
"value": "westeurope"
},
"commonTags": {
"value": {
"contact":"dr#balloon.com",
"costcenter": "99999",
"env": "[parameters('env')]",
"criticality": "[parameters('env') == 'prd' ? 'high', 'low']"
}
}
}
}
The only other option I see is to set the env-specific parameters in the template file. Either by merging with the existing parameters or by setting the value of commonTags in the template file entirely. But I'd rather keep my template files free of parameter values and have these all located in a central parameter file.
Can anybody point me in the right direction? I can't seem to find anything online.
Many thanks!
You cannot nest parameters as you are trying to do here.
Instead, you can make use of conditional directly in your main arm template coupled with inline parameters. Let's take a simple Storage Account as an example.
azuredeploy.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string"
},
"env": {
"type": "string"
},
"costcenter": {
"type": "string"
},
"contact": {
"type": "string"
},
"storageAccountType": {
"type": "string",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"metadata": {
"description": "Storage Account type"
}
}
},
"variables": {
"storageAccountName": "[concat('store', uniquestring(resourceGroup().id))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountType')]"
},
"tags": {
"contact": "[parameters('contact')]",
"costcenter": "[parameters('costcenter')]",
"env": "[parameters('env')]",
"criticality": "[if(equals(parameters('env'),'prd'),'high','low')]"
},
"kind": "StorageV2"
}
]
}
azuredeploy.parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountType": {
"value": "Standard_LRS"
},
"costcenter": {
"value": "99999"
},
"contact": {
"value": "dr#balloon.com"
},
"location": {
"value": "westeurope"
}
}
}
Note that the tag names remain static - there are ways to pass them inline instead/as well - see this answer.
From these, you can then use Az CLI or Powershell to deploy your template, the parameters kept in a single place and the dynamically provide the remaining one like env.
Example using Powershell :
New-AzResourceGroupDeployment -Name $deploymentName -ResourceGroupName $rgName -TemplateFile .\azuredeploy.json -TemplateParameterFile .\azuredeploy.parameters.json -env $env
Related
I am getting Template validation failed: The template resource 'reports' for type 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Common.Entities.TemplateGenericProperty`1[System.String]' at line '34' and column '79' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see https://aka.ms/arm-template/#resources for usage details. when I make ARM to create containers from the array in parameters file.
Issue line: "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
Here is my ARM template file.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"metadata": {
"description": "The name of the storage account"
}
},
"storageContaners": {
"type": "string",
"metadata": {
"description": "The name of the blob containers"
}
}
},
"functions": [],
"variables": {
},
"resources": [
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2021-04-01",
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2021-04-01",
"name": "[parameters('storageContaners')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
],
"properties": {
"publicAccess": "Blob"
}
}
],
"outputs": {}
}
Here is my ARM parameters file.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"value": "mystorageaccount"
},
"storageContaners": {
"value": "reports"
}
}
}
I have tried changing name to different types but no luck.
Can anybody please help me to figure it out the cause?
The name parameters under the nested resources must be one level less than the type.
Here type has 4 level(separated by 3 / ). So name must have 3 level (separated by 2 /).
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"name": "[concat(parameters('storageAccountName'), '/default/', parameters('storageContaners')]",
This applies when having nested resources under parent resource.
I am creating ARM template for Route table creation. A simple ARM template downloaded from the template deployment is failing. After I run the ARM template, it asks for the name and throws the below error.
I have tried giving names like routeVnet, vnetroute etc.
Saw some posts where giving the combination of lowercase uppercase in name will fix the issue. But it doesn't work here.
The arm template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.5",
"parameters": {
"name": {
"type": "string"
},
"location": {
"type": "string"
},
"tagsByResource": {
"type": "object",
"defaultValue": {},
"metadata": {
"description": "Optional tags provided by the user via createUiDefinition.json"
}
},
"disableBgpRoutePropagation": {
"type": "bool"
}
},
"variables": {},
"resources": [
{
"apiVersion": "2019-02-01",
"type": "Microsoft.Network/routeTables",
"name": "[parameters('name')]",
"location": "[parameters('location')]",
"tags": "[ if(contains(parameters('tagsByResource'), 'Microsoft.Network/routeTables'), parameters('tagsByResource')['Microsoft.Network/routeTables'], json('{}')) ]",
"properties": {
"disableBgpRoutePropagation": "[parameters('disableBgpRoutePropagation')]"
}
}
],
"outputs": {}
}
The parameter template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"value": "eastus"
},
"Name": {
"value": ""
},
"tagsByResource": {
"value": {}
},
"disableBgpRoutePropagation": {
"value": true
}
}
}
The problem is with your parameter file where you are passing parameter name as "Name", in template your parameter is name while in parameter file you have mentioned it as Name.
The correct parameter file will look like:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"value": "eastus"
},
"name": {
"value": "routeVnet12"
},
"tagsByResource": {
"value": {}
},
"disableBgpRoutePropagation": {
"value": true
}
}
}
I am deploying resource group using arm templates
Below is the command and error I am getting
az deployment create --name test-deployment --template-file azuredeploy.json --parameters azuredeploy.parameters.json -l westus2
This command has been deprecated and will be removed in a future release. Use 'deployment sub create' instead.
{'additionalProperties': {}, 'code': 'InvalidTemplate', 'message': "Deployment template validation failed: 'The template reference 'DEV-AI-POC-WESTUS2-RG' 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.'.", 'target': None, 'details': None, 'additionalInfo': [{'additionalProperties': {}, 'type': 'TemplateViolation', 'info': {'lineNumber': 0, 'linePosition': 0, 'path': ''}}]}
azuredeploy.json:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"enviroment": {
"type": "string",
"defaultValue": "poc"
},
"location": {
"type": "string",
"defaultValue": "West US"
},
"depattmentName": {
"type": "string"
},
"project": {
"type": "string"
}
},
"variables": {
"rgName": "[concat(toupper(parameters('depattmentName')), '-', toupper(parameters('project')), '-', toupper(parameters('enviroment')), '-', toupper(replace(parameters('location'), ' ', '')), '-', 'RG')]",
"rgDeploymentName": "[concat(deployment().name, '-rg')]",
"_artifactsLocation": "https://xxxxxxx/xxxxxx"
},
"resources": [
{
"name": "[variables('rgDeploymentName')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"ResourceGroup": "[variables('rgName')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(variables('_artifactsLocation'),'/src/arm/templates/resourcegroup.json')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"rgName": {
"value": "[variables('rgName')]"
},
"rgLocation": {
"value": "[parameters('location')]"
}
}
}
}
],
"outputs": {
"resourceGroups": {
"type": "object",
"value": "[reference(variables('rgName'))]"
}
}
}
azuredeploy.parameters.json:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"value": "westus2"
},
"depattmentName": {
"value": "Dev"
},
"project": {
"value": "AI"
},
"enviroment": {
"value": "poc"
}
}
}
resourcegroup.json(calling template)
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string"
}
},
"variables": {
"storageAccountType": "Standard_LRS"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('storageAccountName')]",
"apiVersion": "2018-02-01",
"location": "[resourceGroup().location]",
"sku": {
"name": "[variables('storageAccountType')]"
},
"kind": "Storage"
}
],
"outputs": {
"storageDetails": {
"type": "string",
"value": "[concat(parameters('storageAccountName'), '-', variables('storageAccountType'))]"
}
}
}
Can anyone please help me to fix,
I have to deploy/crease resource group if not exist in azure portal using arm template. arm template should be called through uri in blob storage.
what it tells you is that your output is not valid, you dont have a resource or resource copy with that name, because you are attempting to create a deployment (not a resource group) in another resource group, so the reference function doesnt know about that and hence fails.
So you need to first create the resource group and then create a deployment to that group
Is it possible to get the ARM template as it was during runtime in the Azure Portal with the variables and parameters resolved?
Example below:
AzureDeploy.json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"type": "string",
"defaultValue": "dev",
},
"storageSKU": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_RAGRS",
"Standard_ZRS",
"Premium_LRS",
"Premium_ZRS",
"Standard_GZRS",
"Standard_RAGZRS"
]
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"storageAccountName": "[concat('companyname',parameters('environment'),'sa01'))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageName')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageSKU')]"
},
"kind": "StorageV2",
"properties": {
"supportsHttpsTrafficOnly": true
}
}
]
}
AzureDeploy.parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"value": "dev"
}
}
}
If this deployment was to fail on something such as the name or the SKU, would I be able to access the portal or somehow see how these values were resolved when the script was ran?
The deployment happens in a CD pipeline in AzureDevops and I have control of the variable groups etc. so I know what is being passed in but not how it resolves. In a more complex template, I have an error claiming an Id is not set on a Logic App API connection but I cannot tell if the error is due to the variable I am using in the concat function or if the value is genuinely incorrect (resolving okay according to data passed in).
If anyone is familiar with troubleshooting these through the deployments blade in Azure then you may have some tips on how to see a more detailed view.
Thanks,
Edit:
The code below triggers Intellisense in Visual Studio 2019 but has been confirmed working during deployment. No warnings in VS Code as per comments. Majority of code omitted for brevity.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environment": {
"type": "string",
"defaultValue": "dev"
},
"increment": {
"type": "string",
"defaultValue": "01"
},
"keyvaultName": {
"type": "string",
"defaultValue": "randomKeyVaultName",
"metadata": {
"description": "Keyvault Name for deployment"
}
}
},
"variables": {
"uniqueKeyVaultName": "[parameters('keyvaultName')]"
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults/secrets",
"apiVersion": "2016-10-01",
"name": "[concat(variables('uniqueKeyVaultName'), '/407045A0-1B78-47B5-9090-59C0AE9A96F6')]",
"location": "northeurope",
"dependsOn": [
"[resourceId('Microsoft.Resources/deployments', 'cosmosdb_linkedtemplate')]"
],
"properties": {
"contentType": "Graph",
"value": "[concat('{''D'': ''DatabaseName'', ''U'': ''https://randomcosmosdb-',parameters('environment'),'-cdb-',parameters('increment'),'.documents.azure.com'', ''C'': ''CollectionName'', ''K'': ''',reference('cosmosdb_linkedtemplate').outputs.accountKey.value,'''}')]",
"attributes": {
"enabled": true
}
}
}
],
"outputs": {}
}
If you want to see the evaluated template there are a few things you can do to get it without deploying:
1) call the /validate api: https://learn.microsoft.com/en-us/rest/api/resources/deployments/validate -- but you need to use an older apiVersion at the moment (e.g. 2017-05-01)... the response will contain the fully evaluated template. If you have an older version of PowerShell or the CLI, you can see the response from the rest API by using the -debug switch. But keep in mind, the more recent versions of PS/CLI will use a newer apiVersion and those don't return the full template (at this time).
2) The /whatif api will also return evaluated JSON but there's a bit more to wade through if all you're after is the evaluated template: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-deploy-what-if
Tha help?
According to the Microsoft Documentation, it is now possible to create Resource Groups and deploy resources to the newly created resource group. There is a small catch though, at the very beginning, we have this disclaimer -
Subscription level deployment is different from resource group deployment in the following aspects:
Schema and commands
The schema and commands you use for subscription-level deployments are different than resource group deployments.
For the schema, use https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#
This throws a major issue, the azuredeploy.json is no longer recognized as the deployment template as it is not using the resource deployment schema (https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#).
So, the other option was to create the Resource Group as a Nested Template and put a dependsOn for the child resources that will be created, this now allowed me to Deploy/Validate the file. However, this possesses a new issue. Even though a dependsOn dictates that the resource group is created, it still fails to recognize this and comes back with an error - resource group could not be found, hence the resources could not be deployed. I tried using a Linked Template (I know this does not make any difference, but still)
Anyone, managed to do this by any chance?
Created Resource Groups and deployed resources at the same time.
Overcome the hurdle of trying to use DependsOn and still not get the right deployment or validation?
Adding my code.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "North Europe"
},
"FirstResourceGroupName": {
"type": "string",
"defaultValue": "myFirstRG"
},
"FirstBlobStorageName": {
"type": "string",
"defaultValue": "North Europe"
}
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "ResourceGroupDeployment",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('location')]",
"name": "[parameters('FirstResourceGroupName')]",
"properties": {}
}
],
"outputs" : {}
}
}
},
{
//ResourceDeployment
"type": "Microsoft.Resources/deployments",
"name": "StorageDeployment",
"apiVersion": "2017-05-10",
"dependsOn": [
"[concat('Microsoft.Resources/deployments/', 'ResourceGroupDeployment')]"
//"ResourceGroupDeployment"
],
"resourceGroup": "[parameters('FirstResourceGroupName')]",
"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.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"name": "[parameters('FirstBlobStorageName')]",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS"
}
}
],
"outputs": {}
}
}
}
],
"outputs": {}
}
The solution proposed by MS is good, when you are not using Visual Studio or Portal for deployment. My major issue was the validation of the template which again will not work for subscription level deployment, as it uses a schema that is not recogonised as an ARM.
It may work as #4c74356b41 suggested through any other means i.e. cli\sdks\rest api, but I did not go down that path.
The other solution I had was to run a powershell script by adding a step on the Azure DevOps pipeline. Which was the closest I came to making this work, but again the validation to check if my deployment would succeed, still was up in the air. I did not want my release pipeline to fail because of an invalid template.
Here is what I have gathered, the reason why the validation failed (even with deploying the RG and using a dependsOn) was because the Resource Groups will not be created until you deploy the template. The template deployment will not happen unless it passes validation as the Resource Groups does not exist. So we are stuck in a loop. The two options are either create them manually on the portal before validating (this defies the point of automation) or use a simple powershell step before validating them. The latter is what I have gone with. I know this is unorthodoxed, but works.... and also validates my template.
NOTE - The solution is different from the original problem, as I have used multiple resource group creation. According to MS documentation, you can have up to 5 RG deployed this way.
First, create a resource group file that will hold the resource groups you'd want to create. It will be just a simple JSON file like,
{
"rgNames":
{
"rg1": { "rg": "resource-group-main" },
"rg2": { "rg": "resource-group-backup" }
}
}
Use the same values you have added to this file as a parameter, so you can use them to deploy resources to.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"ResourceGroups": {
"type": "object",
//If you are changing this value !!!! Please make sure you are also updating the same in the ResourceGroups.ARM.json !!!!
"allowedValues": [
{
"rgNames":
{
"rg1": { "rg": "resource-group-main" },
"rg2": { "rg": "resource-group-backup" }
}
}
]
}
}
Second, change the PS script to include the code where it will loop through the list of resource groups it need to deploy.
# Set '$RGTemplateFile' parameter to be the name of the file you added to your project
$rgFile = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($PSScriptRoot, $RGTemplateFile))
$rgString = Get-Content -Raw -Path $rgFile | ConvertFrom-Json
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMembers {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]#{Key = $key; Value = $obj."$key"}
}
}
$rgValues = $jsonParam | Get-ObjectMembers | foreach {
$_.Value | Get-ObjectMembers | foreach {
[PSCustomObject]#{
RGName = $_.value.rgNames | select -First 1
}
}
}
foreach ($values in $rgValues)
{
New-AzureRmResourceGroup -Name $values.RGName -Location $ResourceGroupLocation -Verbose -Force
}
add the above code, just before where it performs a validation -
if ($ValidateOnly) {
$ErrorMessages = Format-ValidationOutput (Test-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName `
-TemplateFile $TemplateFile `
-TemplateParameterFile $TemplateParametersFile `
#OptionalParameters)
:
Finally, change the deployment template file (azuredeploy.json) to do either a nested template deployment or a linked template to deploy resources on the RG you have declared.(I have used Linked, as it looks neater)
"variables": {
"rg1Name": "[parameters('ResourceGroups')['rgNames']['rg1'].rg]",
"rg2Name": "[parameters('ResourceGroups')['rgNames']['rg2'].rg]",
"blob1Name": "[parameters('blob1')]",
"blob2Name": "[parameters('blob2')]",
"arm1": "[concat(parameters('_artifactsLocation'), 'rg1/rg1.ARM.json', parameters('_artifactsLocationSasToken'))]",
"arm2": "[concat(parameters('_artifactsLocation'), 'rg2/rg2.ARM.json', parameters('_artifactsLocationSasToken'))]"
},
"resources": [
{
//RG1 Resources Deployment
"type": "Microsoft.Resources/deployments",
"name": "RG1Resources",
"apiVersion": "2017-05-10",
"resourceGroup": "[variables('rg1Name')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('arm1')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"blob1Name": {
"value": "[variables('blob1Name')]"
}
}
}
},
{
//RG2 Resources Deployment
"type": "Microsoft.Resources/deployments",
"name": "RG2Resources",
"apiVersion": "2017-05-10",
"resourceGroup": "[variables('rg2Name')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[variables('arm2')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"blobName": {
"value": "[variables('blob2Name')]"
}
}
}
}
],
"outputs": {}
}
Your rg1.ARM.json and rg2.ARM.json files looks like, obviously one could have more than one resource.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"blobName": {
"type": "string"
}
},
"variables": {
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"name": "[parameters('blobName')]",
"kind": "StorageV2",
"apiVersion": "2018-07-01",
"location": "[resourceGroup().location]",
"sku": {
"name": "Standard_LRS"
},
"properties": {}
}
],
"outputs": {
}
}
Once this is set up, you will be able to validate the file as the PS script will create the RG's for you before it passes through validation.
Example taken from official documentation:
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.1",
"parameters": {
"rgName": {
"type": "string"
},
"rgLocation": {
"type": "string"
},
"storagePrefix": {
"type": "string",
"maxLength": 11
}
},
"variables": {
"storageName": "[concat(parameters('storagePrefix'), uniqueString(subscription().id, parameters('rgName')))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[parameters('rgLocation')]",
"name": "[parameters('rgName')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2018-05-01",
"name": "storageDeployment",
"resourceGroup": "[parameters('rgName')]",
"dependsOn": [
"[resourceId('Microsoft.Resources/resourceGroups/', parameters('rgName'))]"
],
"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.Storage/storageAccounts",
"apiVersion": "2017-10-01",
"name": "[variables('storageName')]",
"location": "[parameters('rgLocation')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS"
}
}
]
}
}
}
]
}
does exactly what you need.
https://learn.microsoft.com/en-us/azure/azure-resource-manager/deploy-to-subscription#create-resource-group-and-deploy-resources