Generating Unique GUIDs in Azure Resource Manager Templates

3 minute read

If you have worked on ARM templates, you have probably already faced challenges when you need to use GUIDs within the templates. Currently there are several ways to generate GUID that  I can find on the Internet:

Few weeks ago, I was working on an ARM template, where I need to generate 100+ Azure Automation runbook job schedules. For each job schedule, the ‘name’ property is a GUID, which needed to be unique. It is not practical for me to generate 100+ GUIDs using above mentioned methods (i.e. generating over 100 GUIDs in PowerShell, or calling nested template over 100 times).

After some research, I found recently Microsoft has added a “guid()” function in ARM template - https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-string#guid. According to the GitHub source control history for this documentation page, the “guid()” function was added to the documentation in September 2017.

The guid() function requires a mandatory baseString parameter, it is used in the hash function to create the GUID. Additionally, you can optionally add one or more additional strings to create the value that specifies the level of uniqueness.

According to the documentation:

This function is helpful when you need to create a value in the format of a globally unique identifier. You provide parameter values that limit the scope of uniqueness for the result. You can specify whether the name is unique down to subscription, resource group, or deployment. The returned value is not a random string, but rather the result of a hash function.The returned value is 36 characters long. It is not globally unique.

Although the GUIDs generated by the guid() function is not globally unique, I could manage to generate 100+ unique GUIDs in the scope of the template deployments by passing different strings to the function as baseStrings. In my case, since Azure Automation job schedules are basically the link between runbooks and schedules, there’s a one-to-one relationship between job schedules and schedules, I passed in the schedule name into the guid() function as the baseString. However, this method only works for the first time. Based on my experience, if I deploy the template the 2nd time (to the same resource group), the deployment will fail because the names (guid) for the job schedules already exist. This is because the GUIDs are generated based on the baseStrings, and are not globally unique. in another world, the same GUIDs are used in multiple deployments.

To solve my problem, I needed to provide an additional string that is unique to each deployment. Luckily, there is also a uniqueString() function provided in ARM (https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-string#uniquestring). To make this string unique, I have passed 2 strings to the uniqueString() function: the deployment name and the current time stamp in ticks. Theoretically, as long as you not deploying the same template within 1 millisecond, the unique string generated by uniqueString() function will be globally unique. To implement this, I firstly get the current date time in ticks using PowerShell and pass it into to the ARM template as one of the parameters. I then generate a unique string in the variables section of the ARM template. and I’d then pass this unique string to each guid() function as an additional parameter.

To visualise it, this is what I have done:

  1. Define an input parameter for the current UTC date time in ticks in the ARM template:
"parameters": {
   "_CurrentDateTimeInTicks": {
     "type": "string",
     "minLength": 18,
     "maxLength": 18,
     "metadata": {
       "description": "the current datetime in ticks. this is used to generate a unique string for every deployment"
     }
   }
}
  1. Generate a globally unique string in the variables section of the ARM template:
"variables": {
   "UniqueStringBasedOnTimeStamp": "[uniqueString(deployment().name, parameters('_CurrentDateTimeInTicks'))]",
},
  1. Generate GUIDs wherever is required. i.e. for my jobSchedule name:
"name": "[guid('AzureAutomationJobName', variables('UniqueStringBasedOnTimeStamp'))]"
  1. Get current UTC date time in ticks in PowerShell
$UTCNow = (Get-Date).ToUniversalTime()

$UTCTimeTick = $UTCNow.Ticks.tostring()
  1. Create an ARM template deployment in PowerShell and pass the UTC time in ticks to the template
$TemplateParameters = @{
   '_CurrentDateTimeInTicks' = $UTCTimeTick
}

New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName  -TemplateFile $TemplateFilePath @TemplateParameters

Conclusion

By using the combination of deployment name and current time stamp, we can generate a globally unique string, and then using this unique string to generate GUIDs that we can pretty much guarantee it will be globally unique.

Leave a comment