Using Azure Custom Script Extension to execute scripts on Azure VMs

With Azure Custom Script Extension you can download and execute scripts on Azure virtual machines. This extension is useful for post deployment configuration, software installation, or any other configuration / management task. Scripts can be downloaded from Azure storage or GitHub, or provided to the Azure portal at extension run time.

In this blog post I'm going to explain how you can use the Azure Custom Script Extension to execute a PowerShell script multiple times on an Azure Windows VM from an Azure Automation Runbook.

Why use the Azure Custom Script Extension?

There are multiple ways to execute a PowerShell script on a Windows Virtual machine in Azure.

PowerShell Remoting

Desired State Configuration script resource

Custom Script Extension

Let's go through each of them.

Ad 1. PowerShell Remoting

The advantages are:

PowerShell Remoting does not need an extra agent or extension installation on VM

With PowerShell Remoting you are able to run a script against multiple VMs a the same time.

PowerShell Remoting also allows an interactive session (not really a use-case for calling a script from an Azure Automation Runbook)

Connect to Azure Windows VM and install the PSWindowsUpdate Module using the following PowerShell code from an elevated PowerShell prompt:

Install-Module -name PSWindowsUpdate -Scope AllUsers

Remark:

You can also have the Custom Script Extension (PowerShell) script download and install the PSWindowsUpdate PowerShell Module.

Step 2. Create PowerShell script (Install-WindowsUpdate.ps1)

We want to install all Windows Updates which can be achieved with the following command from the PSWindowsUpdate module.

Get-WUInstall -WindowsUpdate -AcceptAll -AutoReboot -Confirm:$FALSE

This command will get list of available updates, next download and install it from Windows Update Server as source. Does not ask for confirmation updates, installs all available updates, does not ask for reboot if needed and does not prompt for confirmation.

Store the Install-WindowsUpdate.ps1 script on your local machine (example: c:\temp\Install-WindowsUpdate.ps1) before uploading the script to the Storage Container.

Step 3. Store Install-WindowsUpdate.ps1 in Azure Blob storage

We first need to create an Azure Blob Storage Container to store the Install-WindowsUpdate.ps1 script.

Use the following script to create a new Storage Account with a Blob Container.

Although the Set-AzureRmVMCustomScriptExtension cmdlet can configure and rerun Custom Script extensions it has one small drawback and that is that it is blocking the call until it finishes the script on the Azure VM. For scripts that don't take a while to finish this is not a problem but for the Windows Update installation Get-WUInstall cmdlet this can take quite some time to finish.

That's why I choose to use the Azure REST API directly instead of using the Set-AzureRmVMCustomScriptExtension cmdlet in the Azure Automation Runbook. This will save us Runbook running costs.

If you are using the Set-AzureRmVMCustomScriptExtension cmdlet in your Runbook make sure you have installed the latest AzureRM.Compute PowerShell module in Azure Automation, because this Runbook needs the Set-AzureRmVMCustomScriptExtension cmdlet with the ForceReRun parameter!
You can update the AzureRM PowerShell modules in your Azure Automation Account using the Update Azure Modules button.

You can now create a new WindowsUpdatePS Runbook with the following code in your Azure Automation Account.

This Runbook shows the usage of the Set-AzureRmVMCustomScriptExtension cmdlet which has the drawback that it is blocking the call until it finishes the script on the Azure VM. And that's why you see the timeout message error for the Runbook.