Using the customScriptExtension in Azure Resource Templates

Posted by Rik Hepworth on Sunday, August 23, 2015

Documentation for using the customScriptExtension for Virtual Machines in Azure through Resource Templates is pretty much non-existent at time of writing, and the articles on using it through PowerShell are just plain wrong when it comes to templates. This post is accurate at time of writing and will show you how to deploy PowerShell scripts and resources to an Azure Virtual Machine through a Resource Template.

The code snippet below shows a customScriptExtension pulled from one of my templates.

    {           "type": "Microsoft.Compute/virtualMachines/extensions",           "name": "\[concat(variables('vmADFSName'),'/adfsScript')\]",           "apiVersion": "2015-05-01-preview",           "location": "\[parameters('resourceLocation')\]",           "dependsOn": \[             "\[concat('Microsoft.Compute/virtualMachines/', variables('vmADFSName'))\]",             "\[concat('Microsoft.Compute/virtualMachines/', variables('vmADFSName'),'/extensions/ADFSserver')\]"           \],           "properties": {             "publisher": "Microsoft.Compute",             "type": "CustomScriptExtension",             "typeHandlerVersion": "1.4",             "settings": {               "fileUris": \[                 "\[concat(parameters('\_artifactsLocation'),'/AdfsServer.ps1', parameters('\_artifactsLocationSasToken'))\]",                 "\[concat(parameters('\_artifactsLocation'),'/PSPKI.zip', parameters('\_artifactsLocationSasToken'))\]",                 "\[concat(parameters('\_artifactsLocation'),'/tuServDeployFunctions.ps1', parameters('\_artifactsLocationSasToken'))\]"               \],               "commandToExecute": "\[concat('powershell.exe -file AdfsServer.ps1',' -vmAdminUsername ',parameters('adminUsername'),' -vmAdminPassword ',parameters('adminPassword'))\]"             }           }         }       \]     }

The most important part is the commandToExecute. The documentation tells you to simply list the PowerShell script (something.ps1) you want to run. This won’t work at all! All the extension does is shell whatever you put in commandToExecute. The default association for .ps1 is notepad. All that will do is run up an instance of our favourite text editor as the system account, so you can’t see it.

The solution is to build a command line for powershell.exe, as you can see in my example. I am launching powershell.exe and telling it to load the AdfsServer.ps1 script file. I then specify parameters for the script within the command line. There is no option to pass parameters in through the extension itself.

The fileUris settings list the resources I want to push into the VM. This must include the script you want to run, along with any other supporting files/modules etc. The markup in my example loads the files from an Azure storage account. I specify the base url in the _artifactsLocation parameter and pass in a SaS token for the storage in the parameter _artifactsLocationSasToken. You could just put a url to a world-readable location in there are drop the access token param.

The dependsOn setting allows us to tell the extension to wait until other items in the resource template have been deployed. In this case I push two other extensions into the VM first.

Be aware that the process executed by the extension runs as the system account. I found very quickly that if I wanted to do anything useful with my PowerShell, I needed to use invoke-command within my script. To do that I need the admin credentials, which you can see pass into the command line as parameters.