PowerShell: Extract the summary table from RoboCopy's log file
When automating the copying of files with RoboCopy I wanted to be able to interrogate the summary table at the bottom of its log file - shown below.
Total Copied Skipped Mismatch FAILED Extras
Dirs : 1 0 1 0 0 0
Files : 2 2 0 0 0 0
Bytes : 328.45 m 328.45 m 0 0 0 0
To allow me to analyse the summary table I wrote a PowerShell Cmdlet that extracts it out into PowerShell objects, which I can then feed into other processes/scripts for analysis.
This means tasks like ordering the summary table or finding any failures are now really simple:
Get-Content "C:\robocopy.log" -Raw | Select-RoboSummary | Sort-Object Type | Format-Table
Type Total Copied Skipped Mismatch Failed Extras
---- ----- ------ ------- -------- ------ ------
Bytes 328.45 m 328.45 m 0 0 0 0
Dirs 1 0 1 0 0 0
Files 2 2 0 0 1 0
Get-Content "C:\robocopy.log" -Raw | Select-RoboSummary | Where{ $_.Failed -gt 0 }
function Select-RoboSummary {
[CmdletBinding()]
param (
[parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string]$log,
[parameter(Mandatory=$false,ValueFromPipeline=$false)]
[switch]$separateUnits
)
PROCESS
{
$cellHeaders = @("Total", "Copied", "Skipped", "Mismatch", "Failed", "Extras")
$rowTypes = @("Dirs", "Files", "Bytes")
# Extract rows
$rows = $log | Select-String -Pattern "(Dirs|Files|Bytes)\s*:(\s*([0-9]+(\.[0-9]+)?( [a-zA-Z]+)?)+)+" -AllMatches
if ($rows.Count -eq 0)
{
throw "Summary table not found"
}
if ($rows.Matches.Count -ne $rowTypes.Count)
{
throw "Unexpected number of rows/ Expected {0}, found {1}" -f $rowTypes.Count, $rowsMatch.Count
}
# Merge each row with its corresponding row type, with property names of the cell headers
for($x = 0; $x -lt $rows.Matches.Count; $x++)
{
$rowType = $rowTypes[$x]
$rowCells = $rows.Matches[$x].Groups[2].Captures | foreach{ $_.ToString().Trim() }
if ($cellHeaders.Length -ne $rowCells.Count)
{
throw "Unexpected amount of cells in a row. Expected {0} cells (the amount of headers) but found {1}" -f $cellHeaders.Length,$rowCells.Count
}
$row = New-Object -TypeName PSObject
$row | Add-Member -Type NoteProperty Type($rowType)
for($i = 0; $i -lt $rowCells.Count; $i++)
{
$header = $cellHeaders[$i]
$cell = $rowCells[$i]
if ($separateUnits -and ($cell -match " "))
{
$cell = $cell -split " "
}
$row | Add-Member -Type NoteProperty -Name $header -Value $cell
}
$row
}
}
}