Compare your files or text with PowerShell

Some time ago I read about a library for text comparison named DiffPlex. It looked interesting so I decided I would give it a try.

After some tests how it works I created a PowerShell module that creates diff of given old & new text and returns corresponding objects. It can write the result to console as well.

Example

I'll create two test files and the show how to compare them.

[1]: ipmo c:\temp\TextDiff.psm1
[2]: "This is first file
that will be used for demonstration
The time is $(date)" > c:\temp\diff1.txt
[3]: sleep -sec 2; "This is second file
that will be used for demonstration
The time is $(date)
Some added line" > c:\temp\diff2.txt

[4]: $d1 = Write-Diff -oldPath C:\temp\diff1.txt -newPath C:\temp\diff2.txt
This is first second file
that will be used for demonstration
The time is 03/30/2010 10:19:1610:19:17
Some added line

[4]: Write-Diff -oldText "a b`r`nc d" -newText "a d`r`n" > $null
a bd
c d

By default colorized output is written to console. You can use -silent to bypass the console output.
If you would like to work with the objects itself, it is possible as well.

[5]: $d1

Text                                     Type
----                                     ----
This                                     u         #unchanged
is                                       u
first                                    d         #deleted
second                                   a         #added
file                                     u
...                                      separator #newline separator
that will be used for demonstration...   u
The                                      u
time                                     u
is                                       u
03/30/2010                               u
10:19:16                                 d
10:19:17                                 a
...                                      separator
Some added line...                       a
...                                      u

Code

The code here doesn't contain error checking. You can download the full version.

You will also need assembly DiffPlex.dll that can be either downloaded at DiffPlex home page or below.

Add-Type -path (join-path $psflash data\src\PowerShell\bin\DiffPlex.dll)

function New-DiffItem {
    param(
        [Parameter(Mandatory=$true)]
        [string]$text, 
        [Parameter(Mandatory=$true)][ValidateSet('u','a','d','separator')]
        [string]$type
    )
    New-Object PSObject -Property @{ Text=$text; Type=$type }
}

function Get-DiffItem {
    param(
        [DiffPlex.DiffBuilder.Model.DiffPiece]$oldItem,
        [DiffPlex.DiffBuilder.Model.DiffPiece]$newItem,
        [string]$itemSeparator,
        [int]$index
    )
    switch($oldItem.Type) {
        'Unchanged' { New-DiffItem "$($oldItem.Text)$itemSeparator" u }
        'Deleted'   { New-DiffItem "$($oldItem.Text)$itemSeparator" d
                      if ($newItem.Type -eq 'Inserted') { 
                          New-DiffItem "$($newItem.Text)$itemSeparator" a 
                      }
                    }
        'Imaginary' { New-DiffItem "$($newItem.Text)$itemSeparator" a }
        'Modified'  {
            0..($oldItem.SubPieces.Count-1) | 
                % { 
                    $oldWord,$newWord = $oldItem.SubPieces[$_],$newItem.SubPieces[$_]
                    Get-DiffItem $oldWord $newWord -itemSeparator "" $_
                }
            New-DiffItem $itemSeparator separator
        }
    }
}
function Write-Diff {
    [CmdletBinding(DefaultParameterSetName='text')]
    param(
        [Parameter(Mandatory=$true,Position=0,ParameterSetName='text')]
        [string]$oldText,
        [Parameter(Mandatory=$true,Position=1,ParameterSetName='text')]
        [string]$newText,
        [Parameter(Mandatory=$true,Position=0,ParameterSetName='file')]
        [string]$oldPath,
        [Parameter(Mandatory=$true,Position=1,ParameterSetName='file')]
        [string]$newPath,
        [Parameter()][switch]$Silent
    )
    if ($oldPath) { 
        $oldText = [IO.File]::ReadAllText($oldPath, [Text.Encoding]::Default) 
    }
    if ($newPath) { 
        $newText = [IO.File]::ReadAllText($newPath, [Text.Encoding]::Default) 
    }
    
    $differ  = New-Object DiffPlex.Differ
    $sdiffer = New-Object DiffPlex.DiffBuilder.SideBySideDiffBuilder $differ
    $sdiff   = $sdiffer.BuildDiffModel($oldText, $newText)
    
    $ret = New-Object Collections.ArrayList
    0..($sdiff.OldText.Lines.Count-1) | 
        % { 
            $oldLine,$newLine = $sdiff.OldText.Lines[$_],$sdiff.NewText.Lines[$_]
            $ret += @(Get-DiffItem $oldLine $newLine -itemSeparator "`r`n" $_)
        }
    [PsObject[]]$ret
    if (!$Silent) {
        $ret | % { 
            $r = $_;
            switch($r.Type) {
                'u' { Write-Host $r.Text -NoNewline }
                'd' { Write-Host $r.Text -NoNewline -ForegroundColor Red }
                'a' { Write-Host $r.Text -NoNewline -ForegroundColor Green }
                'separator' { Write-Host $r.Text -NoNewline }
            }
        }
    }
}

Export-ModuleMember Write-Diff

Note that you will need to edit line Add-Type -path (join-path $psflash data\src\PowerShell\bin\DiffPlex.dll) according to the location where DiffPlex.dll is stored in your computer.

Download

Current version of DiffPlex.dll that can be downloaded at DiffPlex home page.

Meta: 2010-03-30, Pepa

Tags: PowerShell