Backup And Restore MS SQL Server Using PowerShell

 

Database has always been an integral part of any application be it Web/Desktop/Mobile. If we give an eagle eye statement to what database is, it can be stated that "Database is a bucket where you can dump all your application data for future reuse". Since the inception of software development industry database has always played an important role, they have been in different formats such as file, binaries, most popular in form of database software such as MS SQL Server, MySQL, Oracle etc.

One of the most important aspects or better to say key pain areas for any application delivery is "how to keep database deployment aligned with application deployment". I remember not too long back, we used to create long scripts for database deployment and pass on to database administrator team, who then used to run them on post-development servers. And then long ping-pong of communication as script failed on other environments lots and lots of pain. Scary one... were the ones where DDL used to corrupt the database or used to hamper other systems using the same database.

With new DevOps way of project execution, we have reached a starting point where database and application deployment can be automated dramatically. This reduces the overhead from DBA and developers ***if you follow the rules :) *****

One of the key components of DevOps automation is reducing humans dependency by scripting every workflow requiring humans. In order show some light to that ideology I have been working on database backup and restore scripts using Powershell, below are the scenarios where this can help:

  1. Backup database pre-deployment and restore in case of deployment failure
  2. Version database snapshot with the application, for enabling backward and forward deployment
  3. Data persistence for disaster recovery
  4. Specific version rollback for DEV and Test environment

Below is the script which can be used for backup and restore MS SQL Server database. The beauty of the script is you can use the script standalone or inject in a DevOps pipeline process.

The script loads MS SQL Server objects from Gac for any execution of sql scripts or database object access
  1. [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")  
Verify if the database name exists on the server provided
  1. $QueryDB= " IF (EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE (name = '"+"$dbname"+"'))) BEGIN Select 1 AS IsDbExist END ELSE BEGIN Select 0 AS IsDbExist END"  
  2.  $CDDBCheck= Invoke-Sqlcmd -Query $QueryDB -ServerInstance $($ServerName) -Database $($dbname)  
Check for script execution type i.e. if the user wants to take a backup or wants to restore existing backup
  1. if( $ExecutionType -eq "backup"){}  
If execution type is take backup then create a new directory in location available in $DBBackupPath.
    1. $FileExists = Test-Path $DBBackupPath\$($buildID)  
    2. if($FileExists -eq $False){  
    3. Write-Output "************Folder with Build Id Created************"  
    4. New-Item $DBBackupPath\$($buildID) -type directory  
    5. }  
  • Backup database at buidId folder create in step 4.
    1. Backup-SqlDatabase -ServerInstance $($ServerName) -Database $($dbname) -BackupFile "$DBBackupPath\$($buildID)\$($buildID).bak"  
    In order for the restore to work seamless, we need to first kill all the connections and process accessing the database.
    1. $SQlSvr1 = New-Object Microsoft.SqlServer.Management.Smo.Server "$($ServerName)"  
    2.  $SQlSvr1.KillAllprocesses($($dbname))  
    If execution type is restored, then restore backup from location in $DBBackupPath and adding the desired version folder details.
    1. Restore-SqlDatabase -ServerInstance $($ServerName) -Database $($dbname) -BackupFile "$DBBackupPath\$($buildID)\$($buildID).bak" -ReplaceDatabase  
    The overall script is as below:
    1. param (  
    2.     [string]$buildID, #Use the build id can be string or number   
    3.     [string]$dbname ,#Database name  
    4.     [string]$ServerName,# Database server name  
    5.     [string]$DBBackupPath, #Location where backup file will be saved  
    6.     [string]$ExecutionType #Script execution type for Backup-->backup, for Restore-->restor  
    7.  )  
    8.   
    9.      
    10. Write-Output "************BuildId************" $($buildID)  
    11. Write-Output "************DB Name************" $($dbname)  
    12. Write-Output "**********Server Name**********" $($ServerName)  
    13.   
    14.   
    15. [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")  
    16.   
    17.   
    18.   
    19.   
    20.     Write-Output "************ Start Check Database exists************"  
    21.     $QueryDB=  " IF (EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE (name = '"+"$dbname"+"'))) BEGIN  Select 1 AS IsDbExist END ELSE BEGIN  Select 0 AS IsDbExist END"   
    22.     $CDDBCheck= Invoke-Sqlcmd -Query $QueryDB -ServerInstance $($ServerName)  -Database $($dbname)   
    23.     Write-Output $CDDBCheck  
    24.   
    25.   
    26.     if ($CDDBCheck.IsDbExist -eq 1)  
    27.     {  
    28.       
    29.         if( $ExecutionType  -eq "backup"){  
    30.             $FileExists = Test-Path $DBBackupPath\$($buildID) # D:\CICD_DB_Backup\$($buildID)  
    31.             if($FileExists -eq $False){  
    32.                 Write-Output "************Folder with Build Id Created************"  
    33.                 New-Item $DBBackupPath\$($buildID) -type directory  
    34.              }  
    35.              Write-Output "************DB Backup Started************"  
    36.              Backup-SqlDatabase -ServerInstance $($ServerName) -Database $($dbname) -BackupFile "$DBBackupPath\$($buildID)\$($buildID).bak"   
    37.              Write-Output "************DB Backup End************"  
    38.          }else{  
    39.              $SQlSvr1 = New-Object Microsoft.SqlServer.Management.Smo.Server "$($ServerName)"  
    40.              $SQlSvr1.KillAllprocesses($($dbname))  
    41.   
    42.              Write-Output "************DB Restore Started************"  
    43.              Write-Output "Restoring File : $DBBackupPath\$($buildID)\$($buildID).bak"  
    44.              Restore-SqlDatabase -ServerInstance $($ServerName) -Database $($dbname) -BackupFile "$DBBackupPath\$($buildID)\$($buildID).bak" -ReplaceDatabase   
    45.              Write-Output "************DB Restore End************"  
    46.          }          
    47.   
    48.     }  
    49.     else  
    50.     {  
    51.         Write-Output "************************************************"  
    52.         Write-Output "************Database Server does not exists*****"  
    53.         Write-Output "************************************************"  
    54.     }  

    The script above is "A" way not "THE" way to automate database deployments. There are endless different ways you can automate the deployment. A few are as below:

    • DacPac
    • Batch files
    • DbDeploy.Net

    Summary

    The idea here is to throw some light on how we can use PowerShell to automate database deployment and also use the same PowerShell script if we migrated to any of the DevOps workflows such as using VSTS CICD or Jenkins CICD.