Blog Post

Azure Database Support Blog
3 MIN READ

Automate exporting of azure sql database as .bacpac to blog storage.

v-pekapa's avatar
v-pekapa
Copper Contributor
Jun 22, 2021

 

Important Note: This article is based on RunAs Account and AzureRM PS module, which is not supported anymore, an updated version shared by Jose Merchol Gomera Olmos here

Thank you, Jose and Alberto, for your comments and contribution.

 

Login to Azure Portal-->Go to automation account -->Runbooks-->browse gallery -->type backup azure sql databases to blob storage and import the module.

  1. Open the run book and click edit.


     

  2. Download the code and replace the with your details as shown below:
    <#
    .OUTPUTS
    	Human-readable informational and error messages produced during the job. Not intended to be consumed by another runbook.
    
    #>
    
    
        $RESOURCEGROUPNAME = '<ResourceGroupName>'
        $DatabaseServerName = '<DatabaseName>'
        $DatabaseAdminUsername = '<AdminAccountHere>'
        $DatabaseAdminPassword = '<YourPasswordHere>'
        $DatabaseNames = '<DatabaseNaem>'
        $StorageAccountName = '<StorageAccountName>'
        $BlobStorageEndpoint = 'https://<StorageAccountName>.blob.core.windows.net/'
        $StorageKey = '<StorageAccessKey>'
        $BlobContainerName = '<ContainerName>'
        $RetentionDays = '10'
    
    
    $ErrorActionPreference = 'stop'
    
    function Login() {
    	$connectionName = "AzureRunAsConnection"
    	try
    	{
    		$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName         
    
    		Write-Verbose "Logging in to Azure..." -Verbose
    
    		Add-AzureRmAccount `
    			-ServicePrincipal `
    			-TenantId $servicePrincipalConnection.TenantId `
    			-ApplicationId $servicePrincipalConnection.ApplicationId `
    			-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint | Out-Null
    	}
    	catch {
    		if (!$servicePrincipalConnection)
    		{
    			$ErrorMessage = "Connection $connectionName not found."
    			throw $ErrorMessage
    		} else{
    			Write-Error -Message $_.Exception
    			throw $_.Exception
    		}
    	}
    }
    
    function Create-Blob-Container([string]$blobContainerName, $storageContext) {
    	Write-Verbose "Checking if blob container '$blobContainerName' already exists" -Verbose
    	if (Get-AzureStorageContainer -ErrorAction "Stop" -Context $storageContext | Where-Object { $_.Name -eq $blobContainerName }) {
    		Write-Verbose "Container '$blobContainerName' already exists" -Verbose
    	} else {
    		New-AzureStorageContainer -ErrorAction "Stop" -Name $blobContainerName -Permission Off -Context $storageContext
    		Write-Verbose "Container '$blobContainerName' created" -Verbose
    	}
    }
    
    function Export-To-Blob-Storage([string] $RESOURCEGROUPNAME, [string]$databaseServerName, [string]$databaseAdminUsername, [string]$databaseAdminPassword, [string[]]$databaseNames, [string]$storageKey, [string]$blobStorageEndpoint, [string]$blobContainerName) {
    	Write-Verbose "Starting database export to databases '$databaseNames'" -Verbose
    	$securePassword = ConvertTo-SecureString –String $databaseAdminPassword –AsPlainText -Force 
    	$creds = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $databaseAdminUsername, $securePassword
    
    	foreach ($databaseName in $databaseNames.Split(",").Trim()) {
    		Write-Output "Creating request to backup database '$databaseName'"
    
    		$bacpacFilename = $databaseName + (Get-Date).ToString("yyyyMMddHHmm") + ".bacpac"
    		$bacpacUri = $blobStorageEndpoint + $blobContainerName + "/" + $bacpacFilename
    		$exportRequest = New-AzureRmSqlDatabaseExport -ResourceGroupName $RESOURCEGROUPNAME –ServerName $databaseServerName `
    			–DatabaseName $databaseName –StorageKeytype "StorageAccessKey" –storageKey $storageKey -StorageUri $BacpacUri `
    			–AdministratorLogin $creds.UserName –AdministratorLoginPassword $creds.Password -ErrorAction "continue"
    		
    		# Print status of the export
    		Get-AzureRmSqlDatabaseImportExportStatus -OperationStatusLink $exportRequest.OperationStatusLink -ErrorAction "Stop"
    	}
    }
    
    function Delete-Old-Backups([int]$retentionDays, [string]$blobContainerName, $storageContext) {
    	Write-Output "Removing backups older than '$retentionDays' days from blob: '$blobContainerName'"
    	$isOldDate = [DateTime]::UtcNow.AddDays(-$retentionDays)
    	$blobs = Get-AzureStorageBlob -Container $blobContainerName -Context $storageContext
    	foreach ($blob in ($blobs | Where-Object { $_.LastModified.UtcDateTime -lt $isOldDate -and $_.BlobType -eq "BlockBlob" })) {
    		Write-Verbose ("Removing blob: " + $blob.Name) -Verbose
    		Remove-AzureStorageBlob -Blob $blob.Name -Container $blobContainerName -Context $storageContext
    	}
    }
    
    Write-Verbose "Starting database backup" -Verbose
    
    $StorageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageKey
    
    Login
    
    Create-Blob-Container `
    	-blobContainerName $blobContainerName `
    	-storageContext $storageContext
    	
    Export-To-Blob-Storage `
    	-resourceGroupName $RESOURCEGROUPNAME `
    	-databaseServerName $DatabaseServerName `
    	-databaseAdminUsername $DatabaseAdminUsername `
    	-databaseAdminPassword $DatabaseAdminPassword `
    	-databaseNames $DatabaseNames `
    	-storageKey $StorageKey `
    	-blobStorageEndpoint $BlobStorageEndpoint `
    	-blobContainerName $BlobContainerName
    	
    
    	
    Write-Verbose "Database backup script finished" -Verbose
    

You can get required details from azure portal as shown in below snippets:
To get the Blob container name: Go to the storage account and select the container name where you want to save the bacpac file .

 

 

To find the storage key: Go to Access keys and copy the key as shown in below image:

 

 

You can get the Blob Storage Endpoint from endpoint option as shown in the below image.

 

  1. Now go to runbook and click on edit PowerShell runbook option and replace the existing script with the modified script that you have.

     

  2. Now to automate click on “link to schedule” and schedule the time according to your requirement in order to run the export job and click on create.

     

6.If you want to confirm If bacpac is completed successfully, you can go to job output and check the status of backup.

 

You can also verify the status in SQL Server import and export history wizard as shown below:

 

Once the backup is successful, you can find the .bacpac file in your specific storage account.

 

Points to ponder:

  1. Make sure that you have set the option Allow all azure services to “Yes”.
  2. This functionality works only when public end point has been used and make sure deny public access should be set to “NO"
  3. Also If you encounter any issue related to module is miss then you need to go the below path to fix the issue:
    Go  the automation account-->module-->browse gallery--> Search missing module-->Import
Updated May 19, 2024
Version 2.0

3 Comments

  • jgomera's avatar
    jgomera
    Copper Contributor

    Hope this works, 

    I created a repo with the script changing the Run as Account login to use Manage Identity https://github.com/josegomera/AzureAutomation/tree/master/scripts/sqlDatabase

     

    Also as AlbertoMorillo mentioned the AzureRM modules will be retired, so those were changed to Az. 

     

    There is a migration tool as well: https://www.powershellgallery.com/packages/Az.Tools.Migration/11.0.0

     

  • This article is now obsolete. The script relies on Run As accounts and that type of connection is not supported since September 2023.

     

    In addition, AzureRM modules will be retired on 29 February 2024.