A very useful feature of performing your backups with PowerShell is that you can redirect your backups easily on pretty much any condition you want, or even run multiple backups asynchronously to different network drives to save saturating a single NIC.
At the simplest level you can push each database backup into it’s own folder. However, just like with T-SQL backups, if the folder doesn’t exist the backup will fail, so we’ll introduce a quick check:
Import-Module "SQLPS" -DisableNameChecking $ServerName = "Server1" $SQLSvr = New-Object -TypeName Microsoft.SQLServer.Management.Smo.Server($ServerName) $Db = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database foreach ($db in $SQLSvr.Databases | Where-Object {$_.Name -ne "tempdb"}){ $Backup = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Backup $Backup.Action = [Microsoft.SQLServer.Management.SMO.BackupActionType]::Database $backup.BackupSetDescription = "Full Back of "+$Db.Name $Backup.Database = $db.Name $BackupFolder = "c:\psbackups\"+$Db.name+"\" if ((Test-Path $BackupFolder) -eq $False){ New-Item $BackupFolder -type Directory } $BackupName = $BackupFolder+$Db.Name+"_"+[DateTime]::Now.ToString("yyyyMMdd_HHmmss")+".bak" $DeviceType = [Microsoft.SqlServer.Management.Smo.DeviceType]::File $BackupDevice = New-Object -TypeName Microsoft.SQLServer.Management.Smo.BackupDeviceItem($BackupName,$DeviceType) $Backup.Devices.Add($BackupDevice) $Backup.SqlBackup($SQLSvr) $Backup.Devices.Remove($BackupDevice) }
Or we can monitor the space left on the backup drive, and if it falls below what we need (plus a margin for safety) the backups move to another area?:
Import-Module "SQLPS" -DisableNameChecking $folders = @() $folders += "c:\psbackups" $folders += "\\server2\backups$" $folders += "\\server3\panicspace$" $FolderCount = 0 $CurrentDrive = New-Object -Com Scripting.FileSystemObject $MarginForError = 200 $ServerName = "Server1" $SQLSvr = New-Object -TypeName Microsoft.SQLServer.Management.Smo.Server($ServerName) $Db = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database foreach ($db in $SQLSvr.Databases | Where-Object {$_.Name -ne "tempdb"}){ $Backup = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Backup $Backup.Action = [Microsoft.SQLServer.Management.SMO.BackupActionType]::Database $backup.BackupSetDescription = "Full Back of "+$Db.Name $Backup.Database = $db.Name $CurrentDrive = $folders[$FolderCount] if (($Db.Size-$Db.SpaceUnused)+$MarginForError -gt ($CurrentDrive.AvailableSpace/1024/1024)){ $FolderCount++ } $BackupName = $Folders[$FolderCount]+"\"+$Db.Name+"_"+[DateTime]::Now.ToString("yyyyMMdd_HHmmss")+".bak" $DeviceType = [Microsoft.SqlServer.Management.Smo.DeviceType]::File $BackupDevice = New-Object -TypeName Microsoft.SQLServer.Management.Smo.BackupDeviceItem($BackupName,$DeviceType) $Backup.Devices.Add($BackupDevice) $Backup.SqlBackup($SQLSvr) $Backup.Devices.Remove($BackupDevice) }
Here we build up an array of possible backup folders ($Folders
), set a $MarginForError
in Mb (in this case I’m setting 200MB) and creating a new Scripting object to hold our drive object. As we loop through the database we check that the AvailableSpace
on the drive is greater that our requirements (AvailableSpace returns space in bytes, so we need to change that to MB), I check each time just in case something else is using the disk and don’t get caught out. If we are short of space we increase the $FolderCount
variable by 1.
When building up the backup target we us $FolderCount
to pick the currently used path from the $Folders
array, and then continue with the backup as normal.
Using $Db.Size
gives us a worst case scenario for the potential size of the backup. Though if you have a lot of free space in your DB it’ll be skewed, this could be corrected by using $Db.spaceavailable
as well (correcting for the differences in return values (Size
is in MB, SpaceAvilable
in KB).
Tomorrow we’ll be looking at Asynchronous backups, allowing you to fire off multiple concurrently running backups from a single script
This post is part of a series posted between 1st September 2013 and 3rd October 2013, an index for the series is available here.
alzdba
I really enjoy this series – wish I would have discovered it sooner !
Specifically in this article (day 6/31) handling redirection of backup target files, shouldn’t the script include a windows file system section to grant write authority for the service account of the involved sql server instance ?
Johan Bijnens – alzdba
Stuart Moore
Hi Johnan,
Glad you’ve enjoyed the series.
Yes, you could include a section to correct the permissions (using the error checking from day 24 (http://stuart-moore.com/day-24-31-days-sql-server-backup-restore-using-powershell-error-checking/), and the
Set-ACL
cmdlet (http://technet.microsoft.com/en-us/library/hh849810.aspx). I tried to keep the examples scripts quite simple to make them easy read.I’m also be wary of letting automated scripts set permissions on the fly, partly because it usually means giving a service account more permissions than you’d like, and also I like to ‘contain’ backups to specific areas so wouldn’t really want them to spread any further without some human involvement.
Cheers
Stuart
alzdba
100 % with you 🙂