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

No comments

Leave your comment

In reply to Some User
Captcha Image