Friday, May 3, 2013

PowerShell Robocopy Wrapper - RoboWrapper

Last week I was asked to help review our CTO's backup architecture for his home PCs and Windows Home Server. Apparently, he backs up his PCs to his WHS and replicate using on of the cloud based solution but when he tried to restore, he found out that his backups were corrupt because they were too large. I recommended using xcopy (older version of robocopy) which will copy full and differentials between sources and destination. Rather than write a simple batch file and run it on every machine, I told myself to write a PowerShell wrapper for robocopy and automate the process of backing up machine on a network with logging and alerting capabilities via email for any errors. Here is version 1 of the script which runs synchronously. I will post version 2 that runs asynchronously next week.

$destinationServer = "BKUPMACHINE"
$destinationHardDiskLetter = "C:"
$shareUsername = "Everyone"
$sourceMachines = "MACHINE1","MACHINE2","MACHINE3"

$mailserver = ""
$from = "[email protected]"
$to = "[email protected]"

$defaultDirExclusionSet = "'System Volume Information' *RECYCLE.BIN Windows* 'Program Files*' Recovery ProgramData"
$defaultFileExclusionSet = "pagefile.sys hiberfil.sys *.dat.* *.TMP"
$roboLog = "/LOG+:$LOGFILE`-Robocopy`-$TIMESTAMP.log"
[email protected]{
[email protected]{
"16"="Serious error. robocopy did not copy any files.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"8"="Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded).`n
Check these errors further: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"4"="Some Mismatched files or directories were detected.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log.`
Housekeeping is probably necessary."
"2"="Some Extra files or directories were detected and removed in $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"1"="New files from $SOURCE copied to $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"0"="$SOURCE and $DESTINATION in sync. No files copied.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
$mail = New-Object Net.Mail.SmtpClient($mailserver, 587)
$mail.EnableSsl = $true
$mail.Credentials = New-Object System.Net.NetworkCredential("[email protected]", "Password");

$sourceMachines | % { 
    $defaultShares = @()
$sourceHarddisks = Get-WmiObject Win32_LogicalDisk -ComputerName $_ | where {$_.DriveType -eq 3 } 
$sourceShares =  Get-WmiObject Win32_Share -ComputerName $_
foreach($hd in $sourceHarddisks ) {
 foreach($sh in $sourceShares) {
   if ($sh.Path -eq ($hd.DeviceID + "\")) {
 $defaultShares += $sh.Name

    Invoke-Command -ComputerName $destinationServer -ArgumentList $destinationHardDiskLetter,$_,$shareUsername -ScriptBlock { 
 # Windows ACL Helper functions 
 function Create-WMITrustee([string]$NTAccount){ 
   $user = New-Object System.Security.Principal.NTAccount($NTAccount) 
$strSID = $user.Translate([System.Security.Principal.SecurityIdentifier]) 
$sid = New-Object security.principal.securityidentifier($strSID)  
[byte[]]$ba = ,0 * $sid.BinaryLength      
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()  
$Trustee.SID = $ba 
 function Create-WMIAce{ 

$trustee = Create-WMITrustee $account 
$ace = ([WMIClass] "Win32_ace").CreateInstance()  
$ace.AccessMask = $rights  
$ace.AceFlags = 0 # set inheritances and propagation flags 
$ace.AceType = 0 # set SystemAudit  
$ace.Trustee = $trustee  
 $rights = [System.Security.AccessControl.FileSystemRights]"FullControl"
 $sd = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
 $ace=Create-WMIAce $args[2] $rights 
 $sd.DACL += @($ace.psobject.baseobject)

      $bkupdir = $args[0] + "\Backup\" + $args[1]
      if(-not(Test-Path -Path $bkupdir)){ New-Item -Path $bkupdir -type directory -Force}
 $share = "name='" + $args[1] + "'"
 if(-not(Get-WmiObject Win32_Share -filter $share )) {$wmishares.Create($bkupdir,$args[1],0,5000,"Backup Share",$null,$sd) } 

    #bkup every hard disk by default
    foreach ($sh in $defaultShares ) {
      $roboSource = "\\" + $_ + "\" + $sh
 $roboDestin = "\\" + $destinationServer + "\" + $_ + "\" + $sh.TrimEnd("$")
 robocopy $roboSource $roboDestin /E /ZB /COPYALL /MON:10 /MOT:30 /DCOPY:T /MT:20 $roboLog /XF $defaultFileExclusionSet /XD $defaultDirExclusionSet /XJ /R:3 /W:300 /V /FP /ETA /TEE /SAVE:DailyCopyJob
 $exitCode = $lastExitCode
 if ($roboMessages."$exitCode" -gt $null) {
   Write-EventLog -LogName Application -Source "RoboWrapper" -EventID $exitCode -EntryType $roboMsgTypes."$exitCode" -Message $roboMessages."$exitCode"
$mail.Send($from, $to, "RoboError: " + $roboMsgTypes."$exitCode", $roboMessages."$exitCode")
 else {
   Write-EventLog -LogName Application -Source "RoboWrapper" -EventID $exitCode -EntryType Warning -Message "Unknown ExitCode. EventID equals ExitCode"
$mail.Send($from, $to, "Unknown RoboError", "Unknown ExitCode. EventID equals ExitCode")

1 comment:

  1. GSCopy Pro v6.0 (RoboCopy Alternative) with Open File Agent
    GSCopyPro is a single command-line tool (CLI) that can copy, replicate and move files from one folder to another. This folder can be on the same machine/ server or another server elsewhere. What makes GSCopyPro stand out from other competitors is the fact it works on 32-bit as well as 64-bit systems and has no restrictions. It can easily be scheduled to run as a scheduled task and fully automated. GSCopyPro also comes with an open file agent which can copy files that are locked/ opened by other processes. This feature is supported in all windows versions from widows XP/ 2003 and later.
    Go To:>>