function Compare-File { <# .SYNOPSIS Compares two files, displaying differences in a manner similar to traditional console-based diff utilities. #> param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $CompareFrom, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] $CompareTo, [switch]$Porcelain ) $CompareFrom = (Resolve-Path $CompareFrom).Path $CompareTo = (Resolve-Path $CompareTo).Path $totalFormatWidth = 11 # 5 for numbers, 6 for 2x ' : ' as separators $screenWidth = Get-ConsoleDisplayWidth $fixedWidth = ($screenWidth - ($screenWidth % 2) - $totalFormatWidth) / 2 $fileHeaderPrint = " " $fileHeaderFrom = Select-RightSubstringWithPadLeft -String $CompareFrom -Length $fixedWidth $fileHeaderTo = Select-RightSubstringWithPadLeft -String $CompareTo -Length $fixedWidth ## Get the content from each file $contentFrom = Get-Content -Path $CompareFrom $contentTo = Get-Content -Path $CompareTo ## Compare the two files. Get-Content annotates output objects with ## a 'ReadCount' property that represents the line number in the file ## that the text came from. $comparedLines = Compare-Object -ReferenceObject $contentFrom -DifferenceObject $contentTo -IncludeEqual | Sort-Object { $line.InputObject.ReadCount } if ($comparedLines.Count -eq 0) { if (!$Porcelain) { "$fileHeaderPrint : $fileHeaderFrom : $fileHeaderTo" Write-Host "Contents were the same" } return } $shortestFileLength = [Math]::Min($contentFrom.Length, $contentTo.Length) $lineNumberColor = $PSStyle.ForegroundColor.LightCyan $reset = $PSStyle.Reset $diffLeftColor = $PSStyle.ForegroundColor.LightRed $diffRightColor = $PSStyle.ForegroundColor.Green $lineNumber = 0 $fromResults = @{} $toResults = @{} $lineNumbers = @() foreach ($line in $comparedLines) { $lineNumber = $line.InputObject.ReadCount if($line.SideIndicator -eq "=>") { $lineNumbers += $lineNumber $lineOperation = "added" $fromResults[$lineNumber] = $line.InputObject } elseif($line.SideIndicator -eq "<=") { $lineNumbers += $lineNumber $lineOperation = "deleted" $toResults[$lineNumber] = $line.InputObject } } if ($lineNumbers.Count -gt 0) { $lineNumbers = $lineNumbers | Sort-Object | Get-Unique $groups = Group-Numbers -Values $lineNumbers $printedLineNumbers = @() $print = @("$fileHeaderPrint : $fileHeaderFrom : $fileHeaderTo") foreach ($group in $groups) { $first = $group[0] - 2 if ($first -lt 0) { $first = 0 } $last = $group[-1] + 2 if ($last -gt $shortestFileLength) { $last = $shortestFileLength } for ($i = $first; $i -lt $last; $i++) { # We already wrote the line somewhere else (think overlaps) if ($printedLineNumbers -contains $i) { continue } if ($lineNumbers -contains $i) { # We need to print this as a difference $diffLeftColor = $PSStyle.ForegroundColor.LightRed $diffRightColor = $PSStyle.ForegroundColor.Green $to = $toResults[$lineNumber] $from = $fromResults[$lineNumber] } else { # This is not a difference line, print it "normally" $to = $contentTo[$i] $from = $contentFrom[$i] $diffLeftColor = $PSStyle.Reset $diffRightColor = $PSStyle.Reset } $lineNumberLead = "$lineNumber".PadLeft(5, ' ') $from = "$from".PadRight($fixedWidth," ").Substring(0,$fixedWidth) $to = "$to".PadRight($fixedWidth," ").Substring(0,$fixedWidth) $print += "$lineNumberColor$("$i".PadLeft(5))$reset : $diffLeftColor$from$reset : $diffRightColor$to$reset" $printedLineNumbers += $i } } if ($print.Count -gt 0) { $print } else { } } $print = @() foreach ($lineNumber in $lineNumbers) { $lineNumberLead = "$lineNumber".PadLeft(5, ' ') $from = $fromResults[$lineNumber] $from = "$from".PadRight($fixedWidth," ").Substring(0,$fixedWidth) $to = $toResults[$lineNumber] $to = "$to".PadRight($fixedWidth," ").Substring(0,$fixedWidth) $print += "$($PSStyle.ForegroundColor.LightCyan)$lineNumberLead$($PSStyle.Reset) : $($PSStyle.ForegroundColor.LightRed)$from$($PSStyle.Reset) : $($PSStyle.ForegroundColor.Green)$to$($PSStyle.Reset)" } if ($print.Count -gt 0) { "$fileHeaderPrint : $fileHeaderFrom : $fileHeaderTo" $print } else { } }