Yes, I'chiliad dorsum with yet some other Azure specific problem, but judging from the number of issues this problem is mentioned in, and the lack of solutions for information technology, I idea this solution is worth sharing more. I will not go over the concepts of Azure Virtual Machines or the Custom Script Extensions for Azure Virtual Machines. Microsoft gives a pretty great documentation for those, which you lot can read hither.

For the gist of information technology, Custom Script Extensions are used as mail service deployment configuration, or whatever other installation or configuration tasks after deploying a Virtual Auto, which can exist added in an ARM template deployment for that Virtual Auto (VM). Permit's look at the problem I was trying to solve.

My Problem

So I was running two unlike scripts performing 2 different tasks in the deployment, but at different stages of the deployment. Consider the following diagram. (Deplorable for the vague names, I dont believe the bodily details matter hither more than the problem)

So I was performing a chore using Script A at one phase of the deployment. Once Script A finishes execution, I need to deploy a resource R. R'southward deployment depends on the task washed by Script A. One time R is deployed, I wanted to run another Script B. B depends on R's deployment. (Presume A is some pre-configuration for resource R, and B is some post-configuration needing resource R).

Its not that Azure doesnt back up running multiple scripts, they do infact as specified in this example. My effect was that I wanted to run Script B (the second script) at a subsequently phase in the deployment.

So naively, say you tried adding these 2 scripts in your ARM template, like this:

                                  [                                                      {                                                      "blazon"                  :                                                      "Microsoft.Compute/virtualMachines/extensions"                  ,                                                      "apiVersion"                  :                                                      "2020-12-01"                  ,                                                      "name"                  :                                                      "[concat(variables('vmName'),'/', 'ScriptA')]"                  ,                                                      "location"                  :                                                      "[parameters('location')]"                  ,                                                      "dependsOn"                  :                                                      [                                                      "[concat('Microsoft.Compute/virtualMachines/',variables('vmName'))]"                                                      ],                                                      "properties"                  :                                                      {                                                      "publisher"                  :                                                      "Microsoft.Compute"                  ,                                                      "blazon"                  :                                                      "CustomScriptExtension"                  ,                                                      "typeHandlerVersion"                  :                                                      "1.seven"                  ,                                                      "autoUpgradeMinorVersion"                  :                                                      true                  ,                                                      "settings"                  :                                                      {                                                      "fileUris"                  :                                                      [                                                      "https://SomePublicUrl/HavingThe/ScriptA.ps1"                                                      ],                                                      "commandToExecute"                  :                                                      "powershell.exe -ExecutionPolicy Unrestricted -File ScriptA.ps1"                                                      }                                                      }                                                      },                                                      //                                                      Omitting                                                      R's                                                      deployment                                                      {                                                      "type"                  :                                                      "Microsoft.Compute/virtualMachines/extensions"                  ,                                                      "apiVersion"                  :                                                      "2020-12-01"                  ,                                                      "name"                  :                                                      "[concat(variables('vmName'),'/', 'ScriptB')]"                  ,                                                      "location"                  :                                                      "[parameters('location')]"                  ,                                                      "dependsOn"                  :                                                      [                                                      "[concat('Microsoft.SomeResource/',variables('resourceR'))]"                                                      ],                                                      "backdrop"                  :                                                      {                                                      "publisher"                  :                                                      "Microsoft.Compute"                  ,                                                      "blazon"                  :                                                      "CustomScriptExtension"                  ,                                                      "typeHandlerVersion"                  :                                                      "one.7"                  ,                                                      "autoUpgradeMinorVersion"                  :                                                      true                  ,                                                      "settings"                  :                                                      {                                                      "fileUris"                  :                                                      [                                                      "https://SomePublicUrl/HavingThe/ScriptB.ps1"                                                      ],                                                      "commandToExecute"                  :                                                      "powershell.exe -ExecutionPolicy Unrestricted -File ScriptB.ps1"                                                      }                                                      }                                                      }                                                      ]                                                                  

and I am certain you must have, then your template will non fail validation and start deployment. Only when it reaches the second script, you are greeted with this error:

"Multiple VMExtensions per handler non supported for Bone type 'Windows'. Extension 'ScriptA' with handler 'Microsoft.Compute.CustomScriptExtension' already added."

Ah, equally Microsoft says, you cant utilize multiple custom script extension in i ARM deployment, or can you?

The Solution

So Microsoft technically says you tin't have multiple VM Extensions in i deployment. But in that location is a hack here. If you remove the showtime custom script extension during deployment, earlier the second script extension is deployed, you lot tin can add another custom script extension! 😀 This is information technology, this is how this problem is solved. If this was plenty for y'all, thanks for reading till here. Follow along on how to actually exercise it.

And then in our problems context, we need to remove the custom script extension for script A, before script B is deployed. There are multiple ways to go about it:

  1. ScriptA contains the code to remove itself.
  2. Remove ScriptA using some other way during the deployment.

Obviously i is a simpler style, you can add together a az cli or AzPowerShell command at the end of your script to reomve their custom script extension. I dont adopt that way, considering and then your script needs all these details (name of your resource group, name of the VM, proper noun of the Custom Script extension etc.) and these dont feel like generic scripts (which are improve and easier to test/develop). So lets focus on fashion 2.

Since ARM deployments dont allow you to make any other calls except Create Resource calls, how practise y'all delete a resource in an ARM template deployment? We can use Deployment Scripts and an az CLI command to delete the extension for script A. We can also employ a clever depends on relationship to brand certain everything happens when we want information technology to, every bit shown in the diagram below. Moreover, you tin can also share a managed identity between the Virtual Car and Deployment Script, if your custom script extension also needs an identity.

Now all that remains is to write this down in an ARM template. That template might look like as follows.

Enough talk, show me the ARM template

Then here'southward how my template works. First nosotros volition create the extension for script A. So we deploy R and the deployment script to remove A, which is written as an azure cli script, both dependent on A. And and then we add the extension for script B. (I've but shown the resources section for brevity).

                                  [                                                      {                                                      "blazon"                  :                                                      "Microsoft.Compute/virtualMachines/extensions"                  ,                                                      "apiVersion"                  :                                                      "2020-12-01"                  ,                                                      "proper noun"                  :                                                      "[concat(variables('vmName'),'/', 'ScriptA')]"                  ,                                                      "location"                  :                                                      "[parameters('location')]"                  ,                                                      "dependsOn"                  :                                                      [                                                      "[concat('Microsoft.Compute/virtualMachines/',variables('vmName'))]"                                                      ],                                                      "backdrop"                  :                                                      {                                                      "publisher"                  :                                                      "Microsoft.Compute"                  ,                                                      "type"                  :                                                      "CustomScriptExtension"                  ,                                                      "typeHandlerVersion"                  :                                                      "1.vii"                  ,                                                      "autoUpgradeMinorVersion"                  :                                                      true                  ,                                                      "settings"                  :                                                      {                                                      "fileUris"                  :                                                      [                                                      "https://SomePublicUrl/HavingThe/ScriptA.ps1"                                                      ],                                                      "commandToExecute"                  :                                                      "powershell.exe -ExecutionPolicy Unrestricted -File ScriptA.ps1"                                                      }                                                      }                                                      },                                                      //                                                      Omitting                                                      R'south                                                      deployment                                                      {                                                      "type"                  :                                                      "Microsoft.Resources/deploymentScripts"                  ,                                                      "apiVersion"                  :                                                      "2020-10-01"                  ,                                                      "name"                  :                                                      "RemoveScriptA"                  ,                                                      "location"                  :                                                      "[resourceGroup().location]"                  ,                                                      "kind"                  :                                                      "AzureCLI"                  ,                                                      "identity"                  :                                                      {                                                      "type"                  :                                                      "UserAssigned"                  ,                                                      "userAssignedIdentities"                  :                                                      {                                                      "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('identityName'))]"                  :                                                      {}                                                      }                                                      },                                                      "dependsOn"                  :                                                      [                                                      "[resourceId('Microsoft.Compute/virtualMachines/extensions', variables('vmName'),'ScriptA']"                                                      ],                                                      "properties"                  :                                                      {                                                      "forceUpdateTag"                  :                                                      "[parameters('utcValue')]"                  ,                                                      //                                                      To                                                      forcefulness                                                      run                                                      script                                                      on                                                      redeployment                                                      "AzCliVersion"                  :                                                      "2.2.0"                  ,                                                      "timeout"                  :                                                      "PT30M"                  ,                                                      "arguments"                  :                                                      "[concat(variables('vmName'), ' ', resourceGroup().name)]"                  ,                                                      "scriptContent"                  :                                                      "az vm extension delete -g $2 --vm-name $1 -n ScriptA"                  ,                                                      //                                                      Az                                                      CLI                                                      Control                                                      to                                                      remove                                                      an                                                      extension                                                      "cleanupPreference"                  :                                                      "OnSuccess"                  ,                                                      "retentionInterval"                  :                                                      "P1D"                                                      }                                                      }                                                      {                                                      "type"                  :                                                      "Microsoft.Compute/virtualMachines/extensions"                  ,                                                      "apiVersion"                  :                                                      "2020-12-01"                  ,                                                      "proper noun"                  :                                                      "[concat(variables('vmName'),'/', 'ScriptB')]"                  ,                                                      "location"                  :                                                      "[parameters('location')]"                  ,                                                      "dependsOn"                  :                                                      [                                                      "[concat('Microsoft.SomeResource/',variables('resourceR'))]"                  ,                                                      "[resourceId('Microsoft.Resources/deploymentScripts', 'RemoveScriptA']"                                                      ],                                                      "backdrop"                  :                                                      {                                                      "publisher"                  :                                                      "Microsoft.Compute"                  ,                                                      "type"                  :                                                      "CustomScriptExtension"                  ,                                                      "typeHandlerVersion"                  :                                                      "1.7"                  ,                                                      "autoUpgradeMinorVersion"                  :                                                      true                  ,                                                      "settings"                  :                                                      {                                                      "fileUris"                  :                                                      [                                                      "https://SomePublicUrl/HavingThe/ScriptB.ps1"                                                      ],                                                      "commandToExecute"                  :                                                      "powershell.exe -ExecutionPolicy Unrestricted -File ScriptB.ps1"                                                      }                                                      }                                                      }                                                      ]                                                                  

This is almost the same template that I used and it works perfectly.

That's it for this i. I hope my mail service helps you if you were also trying to achieve something similar. If y'all experience this can be achieved in a better or unlike way, feel free to "@" me at my socials or comment on my weblog. See yous in the next 1.