We were recently looking for a way to run a script on an Azure Virtual Machine that already existed (i.e. not executing it at provisioning time). Whilst there are ways to do this remotely (using PowerShell remoting, for example), these tend to require updating the VM's networking configuration to open up ports or allow traffic from specific IPs, which was something we were not necessarily able to do in this case.
The solution came by using the Custom Script Extension for the Azure VM. This extension downloads and executes the script specified on the target VM, without requiring any changes to network configuration. The only pre-existing requirement to run the extension is that the Azure Virtual Machine Agent is installed on the VM, but this is installed by default for all VMs created from a Marketplace image.
To add the Custom Script Extension to an existing machine, we can use the
Set-AzureRmVMCustomScriptExtension PowerShell cmdlet. The cmdlet allows you to specify either a URI for the script you wish to execute, or a path in an Azure Storage Blob Container where the script is located (the example below assumes the script has been uploaded to Azure Storage).
The only caveat is that only one instance of the Custom Script Extension can be assigned to a VM at any given time, but if you use the same name for the extension, then the previous one will be overwritten, and the script from the new instance will be executed. Because of this, we have to first query the VM to see if there is an existing Custom Script Extension, and if so, find its name and use that when running the new one.
The script below shows a full example of how to use the
Set-AzureRmVMCustomScriptExtension command to execute (on a VM) a script stored in a Blob Container, including checking whether the specified script exists and is accessible, and querying the VM to check for an existing Custom Script Extension. It assumes that there is a user/service principal already logged in (via
Login-AzureRmAccount). When executing
Set-AzureRmVMCustomScriptExtension at the end, the command will wait for the script to execute on the VM, and return the status of whether it succeeded or not.