Robocopy provides detailed exit codes that can be captured in PowerShell for decision making. The key values we need to check are:
- Mismatch count (files that would be updated)
- Failed count
- Extras count (files that would be deleted in destination)
- Copied count
Here's how to modify your script to automatically skip mirroring when no changes are detected:
$source = "\\server1\share"
$destination = "\\server2\backup"
$logPath = "C:\temp\robocopy.log"
# First run with /L (dry run) and capture output
$dryRunOutput = robocopy $source $destination /L /NJH /NP /NS /NC /NDL /NFL
# Parse the summary line (last line of output)
$summaryLine = ($dryRunOutput -split "n")[-1].Trim()
# Extract the key values using regex
if ($summaryLine -match "Dirs :\s+\d+\s+\d+\s+(\d+)\s+\d+\s+\d+\s+Files :\s+\d+\s+\d+\s+(\d+)\s+\d+\s+\d+\s+Bytes :\s+\d+\s+\d+\s+(\d+)") {
$mismatchCount = [int]$Matches[1]
$extraCount = [int]$Matches[2]
$copyBytes = [int]$Matches[3]
}
# Only proceed if there are changes detected
if (($mismatchCount + $extraCount + $copyBytes) -gt 0) {
Write-Host "Changes detected (Mismatches: $mismatchCount, Extras: $extraCount, Bytes to copy: $copyBytes)"
$decision = Read-Host "Continue? (Y/N)"
if ($decision -eq "Y") {
robocopy $source $destination /MIR /FFT /Z /W:5 /MT:64 /XX /LOG:$logPath
Invoke-Item $logPath
}
else {
Write-Host "Operation cancelled by user"
}
}
else {
Write-Host "No changes detected - skipping mirror operation"
}
For more robust parsing, consider this function that captures all statistics:
function Get-RobocopyStats {
param([string[]]$output)
$result = @{
DirsTotal = 0
DirsCopied = 0
DirsFailed = 0
FilesTotal = 0
FilesCopied = 0
FilesFailed = 0
BytesCopied = 0
}
$summary = $output[-1] -split '\s+'
$result.DirsTotal = [int]$summary[3]
$result.DirsCopied = [int]$summary[5]
$result.DirsFailed = [int]$summary[7]
$result.FilesTotal = [int]$summary[9]
$result.FilesCopied = [int]$summary[11]
$result.FilesFailed = [int]$summary[13]
$result.BytesCopied = [int64]$summary[15]
return $result
}
Always check the robocopy exit code:
$exitCode = $LASTEXITCODE
if ($exitCode -ge 8) {
Write-Warning "Robocopy encountered serious errors (Exit code: $exitCode)"
}
elseif ($exitCode -ge 4) {
Write-Warning "Robocopy detected mismatched files (Exit code: $exitCode)"
}
When automating file synchronization between servers, we often want to implement conditional logic based on Robocopy's operation results. The key challenge is extracting the summary statistics from Robocopy's output to make intelligent decisions in PowerShell scripts.
Robocopy provides detailed information through both exit codes and its console output. While exit codes give high-level status (0-7), the detailed statistics appear in the final summary:
------------------------------------------------------------------------------
Total Copied Skipped Mismatch FAILED Extras
Dirs : 3 0 3 0 0 0
Files : 15 0 15 0 0 0
Bytes : 450.00 k 0 450.00 k 0 0 0
Times : 0:00:00 0:00:00 0:00:00 0:00:00
Ended : Wednesday, June 15, 2022 3:45:23 PM
Here's an enhanced version of your script that parses Robocopy's output:
$source = "C:\\Source"
$destination = "C:\\Destination"
$logPath = "C:\\Logs\\Robocopy.log"
# First run - dry run to detect changes
$dryRun = robocopy $source $destination /L /NJH /NJS /NDL /NC /NS /NP
# Parse the summary statistics
$summaryLine = $dryRun | Select-Object -Last 8 | Where-Object { $_ -match "^\s*Files\s*:" }
$fileStats = $summaryLine -split "\s+" | Where-Object { $_ -match "^\d+$" }
$totalFiles = [int]$fileStats[0]
$copied = [int]$fileStats[1]
$skipped = [int]$fileStats[2]
$mismatch = [int]$fileStats[3]
$failed = [int]$fileStats[4]
$extras = [int]$fileStats[5]
# Decision logic
if ($mismatch -eq 0 -and $failed -eq 0 -and $copied -eq 0 -and $extras -eq 0) {
Write-Output "No changes detected. Operation not required."
}
else {
$decision = Read-Host "Changes detected (Mismatch: $mismatch, Failed: $failed, Extras: $extras). Continue? (Y/N)"
if ($decision -eq "Y" -or $decision -eq "y") {
robocopy $source $destination /MIR /FFT /Z /W:5 /MT:64 /XX /LOG:$logPath
Invoke-Item $logPath
}
else {
Write-Output "Operation canceled by user."
}
}
For more robust parsing, we can use regex patterns:
$dryRun = robocopy $source $destination /L /NJH /NJS /NDL /NC /NS /NP
$summaryText = $dryRun -join "n"
$pattern = @"
Files\s*:\s*(?<Total>\d+)\s+(?<Copied>\d+)\s+(?<Skipped>\d+)\s+(?<Mismatch>\d+)\s+(?<Failed>\d+)\s+(?<Extras>\d+)
"@
if ($summaryText -match $pattern) {
$changesExist = $matches.Copied -gt 0 -or $matches.Mismatch -gt 0 -or $matches.Failed -gt 0 -or $matches.Extras -gt 0
if (-not $changesExist) {
Write-Output "No changes detected. Skipping copy operation."
exit 0
}
}
For frequent use, wrap this logic in a function:
function Test-RobocopyChanges {
param (
[string]$Source,
[string]$Destination
)
$dryRun = robocopy $source $destination /L /NJH /NJS /NDL /NC /NS /NP
$summaryText = $dryRun -join "n"
$pattern = "Files\s*:\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)"
if ($summaryText -match $pattern) {
return @{
Total = [int]$matches[1]
Copied = [int]$matches[2]
Skipped = [int]$matches[3]
Mismatch = [int]$matches[4]
Failed = [int]$matches[5]
Extras = [int]$matches[6]
HasChanges = ([int]$matches[2] + [int]$matches[4] + [int]$matches[5] + [int]$matches[6]) -gt 0
}
}
return $null
}
$stats = Test-RobocopyChanges -Source $source -Destination $destination
if ($stats -and $stats.HasChanges) {
# Proceed with actual copy
}
Always include proper error handling for production scripts:
try {
$dryRun = robocopy $source $destination /L /NJH /NJS /NDL /NC /NS /NP 2>&1
if ($LASTEXITCODE -ge 8) {
throw "Robocopy failed with error level $LASTEXITCODE"
}
# ... rest of the parsing logic
}
catch {
Write-Error "Error during Robocopy execution: $_"
exit 1
}
For large directory structures, consider these optimizations:
# Use faster options for dry run
$dryRun = robocopy $source $destination /L /NJH /NJS /NDL /NC /NS /NP /R:1 /W:1
# For actual copy operations with logging
robocopy $source $destination /MIR /FFT /Z /W:2 /MT:32 /LOG+:$logPath /TEE /NP
How to Capture Robocopy Summary Statistics in PowerShell for Conditional Mirroring Operations
8 views