Microsoft Azure makes it easy for an administrator to spin up a virtual machine using a couple of options: Microsoft Azure Portal, where the administrator has to enter all the information to provision the VM; ARM templates where a file can be used to fill out all the inputs required; or using PowerShell where those same inputs are passed through the command line. Besides the options listed above to provision VMs, we can take advantage of the extensions feature where the administrator can add one extra layer of automation during the VM provisioning process. The feature has some built-in extensions from Microsoft, and it is open for partners to add their software when provisioning a VM. Some of those extensions can provide Infrastructure as a Code (IaC) from well-known solutions such as Chef, Puppet, and PowerShell DSC (Desired State Configuration) to configure agents to make sure that newly provisioned VMs will receive the desired agent and from that point on receiving the configuration on the servers. In some cases, the Infrastructure as a Code may be too much depending on the scenario, and Microsoft Azure has a feature that can help to automate some of the processes. This automation extension is called custom script extensions and that is going to be our focus in this article.
There is also an option to use remote PowerShell to execute a set of commands in any given VM, but there are some requirements, such as permissions to connect to the VM, firewall and network security groups will require some changes. Custom script extensions allow an administrator to run a script on a newly provisioned VM, and by doing that we can configure several initial components of a VM and, in some cases, it could be enough to define a baseline or initial configuration for new servers.
Using custom script extensions
The first step is to create the initial PowerShell script that is going to be used for custom script extensions. Our script will start small and simple; we will save the two lines below as VMExtension.ps1, and the script itself will create a registry key and a folder, and both will be AppX. Save the script locally and we will upload it during our next step.
New-Item -Path “HKLM:\Software\AppX” Mkdir C:\AppX
During the provision of a new VM, in the third section, there is an option labeled Extensions. Click on it and on the new blade click Add extension. A list containing all current extensions will be generated. Select Custom Script Extension. A new blade with a brief summary of the extension will be displayed. Click on Create.
The next step is to upload the PowerShell script that we created in the first step. It will be copied to a temporary storage and executed on our VM as part of the provisioning process.
After completing the VM provisioning, the administrator can check the progress of the process, and a new resource named Microsoft.CustomScriptExtension will be listed, and that informs if the script was executed properly or not.
Logging into the VM for the first time, the administrator can check for the AppX folder and registry entries defined in the custom script. As we can see in the image below, both entries were created by the script.
If there is a need for troubleshooting, the administrator can check the log files generated during the process on this local folder C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension.
Installing software with custom script extensions
We went through the process to create two simple settings (registry and file system) in the previous section, however, we can do so much more to automate the provisioning process of a new VM. We can install software taking advantage of Azure Storage to store the files required for custom script extensions. We can start by creating a storage account in the Azure Portal. Make sure that the type is blob storage.
After creating the new storage account, click on it, and click on Containers, create a new one (we will call it scripts), and define the access to blob (anonymous read access for blobs only), and click OK.
Click on Overview located on the left, and click on Open in Explorer (if you don’t have Azure Storage Explorer, which is a fantastic tool to manage storage accounts, the software can be found here and it is available for Windows, Mac, and Linux platforms). Using Azure Storage Explorer will be useful for two task: First upload the MSI file that we want to use in our custom script extensions (we will be using GreenShot.exe, which is a great and free software for screen capture); second, we will select the file that we have just uploaded and we will click on Copy URL. We will need that URL to download the file from our PowerShell script.
Now that we have a storage account that has public access, we can update our script to copy the file from our storage account and install it silently. Note: We made it simple by having a public accessible storage account, however in an enterprise environment, the solution would use virtual network service endpoints to protect the traffic between the virtual networks/VMs and the Storage Account without exposing the files to the Internet. Another method to protect it is using the storage account key to enforce that the access is secure and there is no public access to the file. The script is simple and only four lines of code, but it is creating a folder, registry key, downloading a file, and installing it, and that gives some idea what can be accomplished to automate new provisioned VMs using this feature.
When provisioning another VM and specifying the updated script, we can see that the solution worked as expected because a new popup of Greenshot is being displayed as soon as the initial administrator logs in the VM.
Useful for several scenarios
In this article, we went over a couple of tasks that can be performed using the custom script extensions feature, which can be useful for several scenarios for any given enterprise using IaaS (Infrastructure as a Service) in Microsoft Azure. Custom script extensions work with Windows Server 2008 R2 and higher operating systems and require that the VM has access to the Internet (to download the script). We can execute the same custom script extensions again using the parameter -ForceReRun with Set-AzureRmVMCustomScript cmdlet. This feature integrates with ARM templates and can be added to your existent templates. It also can be triggered using Azure CLI, PowerShell, Azure Portal (the option that we used in this article), and Azure VM Rest API.
Photo credit: Shutterstock