Automate #Azure Blob Snapshot purging/deletes with @Cerebrata

The pricing model for snapshots can get rather complicated, so we need a way to automate the purging of snapshots.
Read how snapshots can accrue additional costs

Lets minimize these costs! We use this script to backup and manage snapshot retention for all our Neo4j Databases hosted in the Azure Cloud.

So a solution I have is that:
We have a retention period in days for all snapshots e.g. 30 days
We have a retention period for the last day of the month backups e.g. 180 days

1. The purging will always ensure that there is always at least ONE snapshot, so it will never delete a backup if it is the only backup for a base blob.

2. The purging will delete snapshots greater than the retention period, respecting rule 1

3. The purging will delete snapshots greater than the last day month retention period, respecting rule 1

You can then schedule this script to run after the Backup Script in TeamCity or some other build server scheduler.

	[parameter(Mandatory=$true)] [string]$AzureAccountName,
	[parameter(Mandatory=$true)] [string]$AzureAccountKey,
	[parameter(Mandatory=$true)] [array]$BlobContainers, #Blob Containers to backup
	[parameter(Mandatory=$true)] [int]$BackupRetentionDays, #Days to keep snapshot backups
	[parameter(Mandatory=$true)] [int]$BackupLastDayOfMonthRetentionDays # Days to keep last day of month backups

if( $BackupRetentionDays -ge $BackupLastDayOfMonthRetentionDays )
	$message = "Argument Exception: BackupRentionDays cannot be greater than or equal to BackupLastDayOfMonthRetentionDays"
	throw $message

Add-Type -Path 'C:\Program Files\Windows Azure SDK\v1.6\ref\Microsoft.WindowsAzure.StorageClient.dll'

$cred = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey($AzureAccountName,$AzureAccountKey)
$client = New-Object Microsoft.WindowsAzure.StorageClient

function PurgeSnapshots ($blobContainer)
	$container = $client.GetContainerReference($blobContainer)
	$options = New-Object  Microsoft.WindowsAzure.StorageClient.BlobRequestOptions
	$options.UseFlatBlobListing = $true
	$options.BlobListingDetails = [Microsoft.WindowsAzure.StorageClient.BlobListingDetails]::Snapshots

	$blobs = $container.ListBlobs($options)
	$baseBlobWithMoreThanOneSnapshot = $container.ListBlobs($options)| Group-Object Name | Where-Object {$_.Count -gt 1} | Select Name

	#Filter out blobs with more than one snapshot and only get SnapShots.
	$blobs = $blobs | Where-Object {$baseBlobWithMoreThanOneSnapshot  -match $_.Name -and $_.SnapshotTime -ne $null} | Sort-Object SnapshotTime -Descending

	foreach ($baseBlob in $baseBlobWithMoreThanOneSnapshot )
		 $count = 0
		 foreach ( $blob in $blobs | Where-Object {$_.Name -eq $baseBlob.Name } )
				$count +=1
				$ageOfSnapshot = [System.DateTime]::UtcNow - $blob.SnapshotTime
				$blobAddress = $blob.Uri.AbsoluteUri + "?snapshot=" + $blob.SnapshotTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ")

				#Fail safe double check to ensure we only deleting a snapshot.
				if($blob.SnapShotTime -ne $null)
					#Never delete the latest snapshot, so we always have at least one backup irrespective of retention period.
					if($ageOfSnapshot.Days -gt $BackupRetentionDays -and $count -eq 1)
						Write-Host "Skipped Purging Latest Snapshot"  $blobAddress

					if($ageOfSnapshot.Days -gt $BackupRetentionDays -and $count -gt 1 )
					    #Do not backup last day of month backups
						if($blob.SnapshotTime.Month -eq $blob.SnapshotTime.AddDays(1).Month)
							Write-Host "Purging Snapshot "  $blobAddress
						#Purge last day of month backups based on monthly retention.
						elseif($blob.SnapshotTime.Month -ne $blob.SnapshotTime.AddDays(1).Month)
							if($ageOfSnapshot.Days -gt $BackupLastDayOfMonthRetentionDays)
							Write-Host "Purging Last Day of Month Snapshot "  $blobAddress
							Write-Host "Skipped Purging Last Day Of Month Snapshot"  $blobAddress
					if($count % 5 -eq 0)
						Write-Host "Processing..."
					Write-Host "Skipped Purging "  $blobAddress

foreach ($container in $BlobContainers)
	Write-Host "Purging snapshots in " $container
	PurgeSnapshots $container


2 thoughts on “Automate #Azure Blob Snapshot purging/deletes with @Cerebrata

  1. I know we have Cerebrata in the heading without the cmdlets, I am hoping they will post an update soon where this feature is built into their cmdlets =) They pretty good with this like that, so watch this space if they update their cmdlets library.

  2. Hi Romiko,

    As of now, there is no direct way of deleting blob snapshots using our Cmdlets. However there is a workaround. Though to be honest I think the solution you have put above is more elegant. In any case, here it goes:

    1. Get the list of all blobs in the blob container using “Get-Blob” cmdlet and specify “-IncludeSnapshots” and “-ListAll” switch parameter. This will list all the blobs in the blob container and their snapshots as well. This will return a collection of type “Cerebrata.AzureUtilities.AzureManagementCmdlets.Storage.BlobContext”.

    2. Loop through this list to find out the blobs where BlobUrl property contains “snapshot=” in the URL. This can be either done by searching for this text in the URL or checking the querystring part of the URL. I would recommend latter approach. If this string is present that means the blob is actually a snapshot of another blob.

    3. Get the value of the snapshot parameter. It would represent the date/time in UTC when the snapshot was taken. This date/time value can now be used for creating delete logic i.e. if this date/time is older than a month then we need to delete the blob.

    4. To delete the blob, call “Remove-Blob” and pass this blob URL.

    Hope this helps.



Leave a Reply

Please log in using one of these methods to post your comment: 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