Calling Linux Custom Script Extensions from PowerShell

If you run Linux VM’s on Azure, then you at some point will want to call a Custom Script Extension that runs your own script (bash etc) to perform some operations within the virtual machine.

There are a few options for doing this including of course using chef and puppet, or as is documented here simply calling a Custom Script Extension with your own script.

When experimenting with doing this I found a lot of the documentation describing how to do this was out of date principally because it did not use the “customScript” extension type  (publisher  Microsoft.Azure.Extensions).

Note for Windows VM’s you use a different custom extension type “CustomScriptExtension” (publisher Microsoft.Compute) – see the commented section in the middle of the PowerShell script below

Listed below is the PowerShell to execute a command “command2.sh” which is stored as a blob in an Azure storage account in a container named “myscripts”. The PowerShell also grabs any output (stdout) from command2.sh – (getting stderr would be done in a similar way)

This script assumes you are using ARM and have previously logged into Azure from PowerShell (login-AzureRmAccount) and if required set the default subscription (Select-AzureRmSubscription)

$rg='your-resource-group'
$vmname='yourvm'
$storageaccountname='your-storage-account-name'
$cont='myscripts'
$Extensionname='customScript'
$vm = Get-AzurermVM -Name $vmname -ResourceGroupName $rg
# get the storage key
$key = (Get-AzureRmStorageAccountKey -Name $storageaccountname -ResourceGroupName $rg).value[0]
if (!$key) {
    write-output "Could not find a storage key"
    exit
}
#
# check if there's an existing custom script extension
# if there is remove it - your only allowed one at a time
#
$extname = ($VM.Extensions | Where { $_.VirtualMachineExtensionType -eq 'customScript' }).name
if ($extname) {
    write-output "removing existing extension: $extname"
    remove-azurermvmextension -name $extname  -ResourceGroupName $rg  -VMName $vmname -force
    write-output "removed - waiting 10 seconds ...."
    start-sleep -Seconds 10
}
# get extension types
# for windows use:
# Get-AzureRmVMExtensionImage -Location westeurope -PublisherName Microsoft.Compute -Type CustomScriptExtension
# for Linux use:
# Get-AzureRmVMExtensionImage -Location westeurope -PublisherName Microsoft.Azure.Extensions -Type customScript
#
#
#For Linux:
#
# Setup for call to Set-AzureRmExtension
#
$TheURI = "https://$storageaccountname.blob.core.windows.net/myscripts/command2.sh"
$Settings = @{"fileUris" = @($TheURI); "commandToExecute" = "./command2.sh"};
$ProtectedSettings = @{"storageAccountName" = $storageaccountname; "storageAccountKey" = $key};
#
Set-AzureRmVMExtension -ResourceGroupName $rg -Location $vm.location -VMName $vmname -Name "customScript" -Publisher "Microsoft.Azure.Extensions" -Type "customScript" -TypeHandlerVersion "2.0" -Settings $Settings -ProtectedSettings $ProtectedSettings
#
if ($?) {
  write-output "set extension ok"
  #
  # Get script extension output
  #
  $extout=((Get-AzureRmVM -Name $VMName -ResourceGroupName $RG -Status).Extensions | Where-Object {$_.Name -eq $ExtensionName}).statuses.Message
  #
  # Parse the stdout 
  #
  $stdout=$extout.substring($extout.indexof('[stdout]')+8,$extout.indexof('[stderr]')-$extout.indexof('[stdout]')-8)
  $stdout=$stdout.trim()
  write-output "stdout from command: $settings.commandToExecute"
  $stdout
  }
  else
  {
    write-output "set extension problem?"
  }
#
#

 

The above will be particularly useful when developing runbooks that are called as steps in a Azure Site Recovery plan.

If Multiple Linux VM’s are involved in the recovery plan it’s often necessary to query hostnames, assigned IP addresses or other information from Virtual Machine A and feed that  information as parameter into Virtual Machine B etc.  so it can correctly configure itself with Virtual Machine A’s information as part of the failover process.

Eg. As part of the failover plan – custom script extension 1 runs on VM1 (database server) and returns the hostname/ip address etc  – which are then passed as parameters into custom extension script 2 run by VM2 (web server) which using the script reconfigures itself to use the new hostname/ip address given to the database server as it failed over into Azure, as this may be different to what was used ‘on-premise’ (or from the source Azure region if your using Azure to Azure ASR).

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s