Backup live data using PowerShell, DiskShadow, and RoboCopy

Robocopy is my go-to tool for quick file-level backups. Unfortunately it doesn't deal well with locked files (live databases, pst files, etc.). In those instances I deploy another great tool - DiskShadow that allows to tap into functionality of Volume Shadow Copy Service (VSS). 

This is the way it works:

  • diskshadow creates a shadow copy of a volume and then mounts it as a normal physical drive.
  • robocopy then does its job by copying data from that mounted virtual drive without having to worry about locked files.
  • Once copying is done dishshadow deletes the shadow copy and dismounts the drive.
  • PoweShell sends notification and logs to your email.

Let's start:

  • We'll need to create 4 files:
    • diskshadow_backup.conf - Main diskshadow backup file.
    • diskshadow_delete_x.conf - Used only to delete abandoned X: drive.
    • robocopy_backup.cmd - robocopy backup script.
    • run_backup.ps1 - PowerShell script to combine everything and then send logs via email. Executed manually or via scheduled task.

 

diskshadow_backup.conf 

 
set context persistent
set metadata D:\Scripts\Logs\diskshadow_result.cab
set verbose on
begin backup
add volume D: alias data_backup
create
EXPOSE %data_backup% X:
exec D:\Scripts\robocopy_backup.cmd
delete shadows exposed X:
end backup
 

diskshadow_delete_x.conf 

 
delete shadows exposed X:
 

robocopy_backup.cmd 

 
REM "============================================================================"
REM "Starting Robocopy Script"
REM "============================================================================"
robocopy "X:\Data" "\\NAS\Backup\Data" /MIR /NP /NDL /R:1 /W:1 /LOG:"D:\Scripts\Logs\robocopy - Data.log"
REM "============================================================================"
REM "Ending Robocopy Script"
REM "============================================================================"
exit 0
 

run_backup.ps1 

 
# Test if drive X: still exists
If (Test-Path X:)
{ Write-Output "============================================================================"
 Write-Output "Deleting abandoned X: drive and associated shadow copy"
 Write-Output "============================================================================"
 diskshadow /s "D:\Scripts\diskshadow_delete_x.conf"
}
Write-Output "============================================================================"
Write-Output "Starting main diskshadow script"
Write-Output "============================================================================"
diskshadow /s "D:\Scripts\diskshadow_backup.conf" /l "D:\Scripts\Logs\diskshadow.log"
Write-Output "============================================================================"
Write-Output "Ending main diskshadow script"
Write-Output "============================================================================"
# Send Email:
Write-Output "============================================================================"
Write-Output "Starting Send Email"
Write-Output "============================================================================"
$mail = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient("mail.authsmtp.com") # SMTP server name or IP
$smtpuser = new-object System.Net.networkCredential 
 
$smtpuser.username = "user123" # SMTP Username
$smtpuser.password = "*******" # SMTP Password
$smtp.Credentials = $smtpuser
 
$mail.From = "Backup Server <This email address is being protected from spambots. You need JavaScript enabled to view it.>"
$mail.to.Add("This email address is being protected from spambots. You need JavaScript enabled to view it.")
$mail.Subject = "Backup Logs"
$mail.Body = "Backup completed. See attached log files for more details"
Write-Output "============================================================================"
Write-Output "Adding attachements"
Write-Output "============================================================================"
$mail.Attachments.Add("D:\Scripts\Logs\diskshadow.log")
$mail.Attachments.Add("D:\Scripts\Logs\robocopy - Data.log")
Write-Output "============================================================================"
Write-Output "Sending Email"
Write-Output "============================================================================"
$smtp.Send($mail)
$mail.Dispose(); # Unlocks locked attachement file.
Write-Output "============================================================================"
Write-Output "Moving Logs"
Write-Output "============================================================================"
Move-Item "D:\Scripts\Logs\diskshadow.log" "D:\Scripts\Logs\Emailed" -force
Move-Item "D:\Scripts\Logs\robocopy - Data.log" "D:\Scripts\Logs\Emailed" -force
Write-Output "============================================================================"
Write-Output "Script completed"
Write-Output "============================================================================"
 

To run PowerShell run_backup.ps1 from a Task Scheduler, create a new task and fill Action fields as follows:

  • Action: Start a Program
  • Program: PowerShell.exe
  • Add Arguments: & 'D:\Scripts\run_backup.ps1' *> 'D:\Scripts\Logs\_PowerShell_.log'

 

February 2018
Windows Server 2008R2
Windows Server 2016

Newsletter

Subscribe to receive occasional updates on new posts.
Your email will not be used for any other purpose and you can unsubscribe at any time.
Please wait