Azure – Install software on Azure Virtual Machine using Azure Custom Script Extension (CSE)

You may need to install a software (exe, MSI etc..) on your Azure virtual machines as per the on-boarding process. The traditional way of doing this is to RDP to your virtual machine and then install the software.

Azure and PowerShell make this task simple by introducing “Custom Script Extension (CSE)” for Azure Virtual machines. Using CSE you can install the executables without login into the servers. The process also reduces human effort by a lot, hence increasing the ROI for your team.

As an example, let us see how to deploy a BigFix client into an Azure Windows Virtual Machine:

The process requires two scripts:

Script 1: installAgent.ps1

This script does the silent installation of the agents. This script must be uploaded into Azure Storage Account along with the exe/MSI.

Script 2: triggerCSE.ps1

This script installs the CSE on the Windows Azure virtual machine. Checks if the Virtual Machine is STOPPED. If it is stopped, it will start the virtual machine, install the CSE, and then it will stop the virtual machine.

Steps to be followed

  1. Upload all the necessary files (BigFix installation files) into Azure Storage account and provide Anonymous access to the container.
  2. Upload the installAgent.ps1 PowerShell script into Azure Storage account and provide Anonymous access to the container.
  3. Execute the triggerCSE.ps1 from your laptop or you can completely automate the solution using Azure Automation Account.




# Script to install Big Fix agents in Singapore region

# Create a directory to hold BigFix files

new-item 'c:\bigfix' -ItemType directory -force

# Copy BigFix files from Azure storage to local directory

Invoke-WebRequest -Uri -outfile 'c:\bigfix\clientsettings.cfg'

Invoke-WebRequest -Uri -outfile 'c:\bigfix\masthead.afxm'

Invoke-WebRequest -Uri -outfile 'c:\bigfix\setup.exe'

# Execute the setup file

$arguments = "/S /v/qn"

$filepath = "c:\bigfix\setup.exe"

Start-Process $filepath $arguments -wait




##### Installing BigFix client on virtual machine #####

        # Declaring variables

        # storage account name where the custom script is stored

        $storage_account_name = "<INSTERT_STORAGE_ACCOUNT_NAME>"

        # storage account key of where the custom script is stored

        $storage_account_key = "<INSERT_STORAGE_ACCOUNT_KEY>"

        # custom script file name

        $bigfix_file_name = "installAgent.ps1"

        # container name where the custom script is stored

        $bigfix_container_name_singapore = "<INSERT_AZURE_STORAGE_CONTAINER_NAME>"

        # Assuming the state of the virtual machine is not de-allocated

        $is_dellocated = $false



        # Checking if the Webhook data has the Resource Group and Virtual Machine.

        if($resource_group -eq $null -or $vm_name -eq $null){

            "Either Resource Group or Virtual Machine name, not present. This could be because the input variables could be misspelled. Make sure the input names are - 'ResourceGroup' and 'VirtualMachine'. " | write-output



        #### Checking if the Virtual Machine is a Windows machine ########

        # Obtaining the Virtual Machine object

        $vm = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name

        # Obtaining the Virtual Machine status object

        $vm_status = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name -Status

        "Displaying the status of Virtual machine...." | write-output

        $vm_status.Statuses[1].DisplayStatus | write-output

        "" | write-output

        "" | write-output

        "Checking if the VM is Windows or not. Expect some output below if the Virtual machine is Windows... If you DONOT GET ANY OUTPUT, STOP EXECUTING..." | write-output

        $vm.OSProfile.WindowsConfiguration | write-output


        if($vm.OSProfile.WindowsConfiguration -eq $null){

            "The Virtual machine is either a custom image or is not Windows Virtual Machine. Cannot proceed with installing Custom Script Extenstion.. " | write-output






        ######## Checking the status of the Virtual Machine ########


            VM Generalized --> Do not take any action. Exit Execution

            VM Deallocated --> Start the Virtual Machine

            VM Running --> Do not take any action, Proceed with Execution


        if($vm_status.Statuses[1].DisplayStatus -eq "VM Generalized"){

            "Virtual Machine is in the GENERALIZED state. Do not proceed further... " | write-output

            "" | write-output

            "" | write-output



        if($vm_status.Statuses[1].DisplayStatus -eq "VM deallocated"){

            "Virtual Machine is STOPPED. Starting the virtual machine... " | write-output

            $is_dellocated = $true

            $vm | Start-AzureRmVM

            "Successfully started Virtual Machine.." | write-output

            ""| write-output

            "" | write-output


        if($vm_status.Statuses[1].DisplayStatus -eq "VM running"){

            "Virtual Machine is already RUNNING. Proceeding with agents installation" | write-output

            "" | write-output

            "" | write-output



        # Checking if the virtual machine already has a Custom Script Extension

        $vm = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name

        $vm_status = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name -Status

        $vm_extensions = $vm.Extensions

        foreach($vm_extensions_iterator in $vm_extensions){

            if($vm_extensions_iterator.VirtualMachineExtensionType -eq "CustomScriptExtension"){

                "Removing the CSE..." | write-output

                Remove-AzureRmVMCustomScriptExtension -Name $vm_extensions_iterator.Name -ResourceGroupName $resource_group -VMName $vm_name -force

                "Removed  the CSE " | write-output

                "" | write-output

                "" | write-output



        # Re-creating the Virtual Machine object, since one of the above condition - starts the virtual machine

        $vm = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name

        $vm_status = get-azurermvm -ResourceGroupName $resource_group -Name $vm_name -Status

        ########### Installing BIGFIX client via Azure Custom Script Extension ###########

        if($vm_status.Statuses[1].DisplayStatus -eq "VM running" -and $vm.OSProfile.WindowsConfiguration -ne $null){

            "Installing BigFix extension..." | write-output

            # azure powershell cmdlet to execute add the custom script extension and to execute the powershell file

            Set-AzureRmVMCustomScriptExtension -ResourceGroupName $resource_group -Location $vm.Location -VMName $vm_name -Name "ibm_bigfix_agent_install_extension" -TypeHandlerVersion "1.1" -StorageAccountName $storage_account_name -StorageAccountKey $storage_account_key -FileName $bigfix_file_name -ContainerName $bigfix_container_name_singapore


        "waiting for 10 seconds..." | write-output

        "" | write-output

        "" | write-output

        Start-Sleep -s 10

        ######## Stopping the Virtual machine that we had started ########

        if($is_dellocated -eq $true){

            "We had started the virtual machine before installing the BigFix agent. STOPPING the virtual machine to preserve the initial state..." | write-output

            $vm | Stop-AzureRmVM -force

            "Successfully stopped the virtual machine" | write-output

            "" | write-output

            "" | write-output




As an enhancement, you can add additional checks, create a log file and have it uploaded to another Storage Account. Or, create an Azure Storage Table, and write the updates to it tracking how many virtual machines the CSE is installed.


Click here to download my PowerShell scripts for Free !!

Click here for Azure tutorial videos !!



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s