Search code examples
powershellcompareobject

Modifying Compare-Object Output file content


I am comparing two text files and sending the difference to an output file. Here is my simple code.

$file1 = (Get-Content .\txt1.txt)
$file2 = (Get-Content .\txt2.txt)
compare-object $file1 $file2 | out-file txt3.txt

(Get-Content -Path .\txt3.txt) |
    ForEach-Object {
        $_ -Replace '=>', 'After'`
           -Replace '<=', 'Before'`
    } |
        Set-Content -Path .\txt3.txt
Get-Content -Path .\txt3.txt

Now here is the output.

InputObject SideIndicator
----------- -------------
banaple     After           
cherry      After           
orange      Before           
strawberry  Before

Is it possible to alternate After and Before so that it would be easier for the user to understand this result? My main concern is if I have difference for a lot of lines and they are displayed like this, all After's on top followed by their corresponding Before's underneath, then it might cause confusion to the user. Or if I can put numbers beside them to point which After and Before are partners.

I hope someone could help me out with this. I'm just starting to familiarize myself with the Compare-Object command but I'm really having a hard time getting the modifications I need. I thank in advance whoever will have the answer for my question :)


Solution

  • If you're comparing both files by their index, meaning, comparing index 0 on file1 with index 0 on file2 and son on I would personally not use Compare-Object at all since it's pretty slow:

    $arr1 = 'orange','strawberry','orange'
    $arr2 = 'banaple','cherry','orange','banana'
    
    # Note: I'm placing those 2 arrays for demonstration purposes only.
    # $arr1 and $arr2 should be changed to:
    # $arr1 = Get-Content .\txt1.txt
    # $arr2 = Get-Content .\txt2.txt
    
    $totalCount = ($arr1.Count, $arr2.Count | Measure-Object -Maximum).Maximum
    
    $arr3 = for($i=0;$i -lt $totalCount;$i++)
    {
        $status = 'NO CHANGE'
    
        if($arr1[$i] -ne $arr2[$i])
        {
            $status = 'UPDATED'
        }
    
        [pscustomobject]@{
            Before = $arr1[$i]
            After = $arr2[$i]
            Status = $status
        }
    }
    
    • $arr3 would result in the following:
    Before     After   Status   
    ------     -----   ------   
    orange     banaple UPDATED  
    strawberry cherry  UPDATED  
    orange     orange  NO CHANGE
               banana  UPDATED 
    
    • If you want to export $arr3 I would recommend you to use CSV as export format:
    $arr3 | Export-Csv absolultepath\to\file3.csv -NoTypeInformation
    
    • If you want to export as a normal text file:
    $arr3 | Out-File absolultepath\to\file3.txt
    

    Same logic but as a function:

    function Compare-Files {
    [cmdletbinding()]
    param(
        [parameter(mandatory)]
        [ValidateScript({Test-Path $_ -PathType Leaf})]
        [System.IO.FileInfo]$BeforeFile,
        [parameter(mandatory)]
        [ValidateScript({Test-Path $_ -PathType Leaf})]
        [System.IO.FileInfo]$AfterFile
    )
    
        $file1 = Get-Content $BeforeFile
        $file2 = Get-Content $AfterFile
    
        $totalCount = ($file1.Count, $file2.Count | Measure-Object -Maximum).Maximum
      
        for($i=0;$i -lt $totalCount;$i++)
        {
            $status = 'NO CHANGE'
    
            if($file1[$i] -ne $file2[$i])
            {
                $status = 'UPDATED'
            }
    
            [pscustomobject]@{
                Before = $file1[$i]
                After = $file2[$i]
                Status = $status
            }
        }
    }
    

    Demo:

    PS /> Compare-Files -BeforeFile .\file1.txt -AfterFile .\file2.txt
    
    Before     After   Status   
    ------     -----   ------   
    orange     banaple UPDATED  
    strawberry cherry  UPDATED  
    orange     orange  NO CHANGE
               banana  UPDATED  
    
    PS /> Compare-Files -BeforeFile .\file1.txt -AfterFile .\file2.txt | Export-Csv ...