PowerShell 5.1 – How to Compare Two Folders

powershell-v5.0windowswindows-server-2019

I'm having a really difficult time figuring out what PS is trying to tell me. I've created a script that is intended to compare the files in two directories. I want to output any differences in Name, Number of files, or length in either directory. Ultimately, I'd like for it to error if there are differences. Here's what I have:

Write-host "$(Get-Date) - Comparing $deploy_src\bin $deploy_dst\bin"
$bin_src = Get-ChildItem $deploy_src
$bin_dst = Get-ChildItem $deploy_dst

if (Compare-Object $bin_src.Name $bin_dst.Name) {
   # throw "Directories differ"
}

And here's the (less than helpful) output I'm seeing:

02/24/2020 09:57:36 - Comparing J:\AdvantageProxy\Development\bin J:\AdvantageProxy\Deploy-QA-2020-02-21\bin
02/24/2020 09:57:36 - done.
Name Length SideIndicator
---- ------ -------------
         38 =>           
         20 <= 

Update: The files are on an FSx share accessible by a Mac. This is what the output is for diff, which shows only .DS_Store in a directory accessed directly from the Mac:

 $ rsync -n -a -i --delete /Volumes/share/AdvantageProxy/Development/bin/. /Volumes/share/AdvantageProxy/Deploy-QA-2020-02-21/bin/.
 *deleting   .DS_Store
 .d..t....... ./
 .d..t....... de/
 .d..t....... es/
 .d..t....... ja/
 .d..t....... ru/

( I used rsync in order to avoid taking the time for diff to compare the contents of the files. … This shows that there's a file in $deploy_dst\bin that isn't in $deploy_src\bin, and the the timestamps on several folders differs. I expect to see something similar with the Powershell solution. )

Also to note – I'm trying to avoid installing additional dependencies, if possible, which is why I'm trying to do this through PS.

Best Answer

I ended up creating my own solution. The relevant parts of it look like this:

      function Compare_Directory
      {
          [CmdletBinding()]
          Param(
               [string]
              [Parameter(Mandatory=$true)]
              $src_dir,
              [Parameter(Mandatory=$true)]
              [string]
              $dest_dir
          )

          Write-Host "$(Get-Date) - Diffing files in $src_dir to $dest_dir (will only report differences)"

          # Get .FullName to avoid issues with string replace not matching FullName to non-full file names (ie, paths using PSdrives)
          $src_str = (Get-Item $src_dir).FullName
          $dest_str = (Get-Item $dest_dir).FullName

          if ($verbose>1){
            Write-Host "$(Get-Date) - $src_str -> $dest_str"
          }

          # Get all files under $folder1, filter out directories
          $src_files = Get-ChildItem  $src_dir -force | Where-Object { -not $_.PsIsContainer }  # -Recurse
          # -force will pick up dotfiles (or windowspeak, files with the hidden attribute set)

          $i=0
          $mismatches=0
          $src_files | ForEach-Object {

                  $src_fl = (Get-Item $_.FullName -force)
                  $dest_flnm = $_.FullName.replace($src_str, $dest_str)
                  $dest_fl = (Get-Item $dest_flnm -force)

                  # Currently, this will cause an error if a file exists in src directory but not dest directory
                  # I don't know how to write this so that it can error more than once depending on verbosity 
                  #   like the rest of the script and it's not a priority for me.

                  if ($verbose>1){
                    Write-Host "$src_fl ?? $dest_fl"
                  }

                  If ( Compare-Object $src_fl $dest_fl -Property Name, Length ) {

                      # List files not matching
                      Write-Host "src- $src_fl"
                      Write-Host "dest- $dest_fl"

                      # if verbosity <0, fail fast, otherwise provide maximum insight (logging)
                      if ($verbose -lt 0){
                        throw "Verbosity set to intolerant; First mismatch found- $src_fl"
                      }
                      else{
                        $mismatches+=1
                      }

                  }
          }
          Write-Host "$i files compared"
          if ($mismatches -gt 0){
            throw "Mismatching files found: $mismatches"
          }
      }

      # Diff directories in both directions to identify differences in file names

      Write-host "$(Get-Date) - Comparing $backup_src and $deploy_dst (->)"
      Compare_Directory $backup_src $deploy_dst
      Write-host "$(Get-Date) - Comparing $backup_src and $deploy_dst (<-)"
      Compare_Directory $deploy_dst $backup_src

      Write-host "$(Get-Date) - Comparing $deploy_src\bin $deploy_dst\bin (->)"
      Compare_Directory $deploy_src\bin $deploy_dst\bin
      Write-host "$(Get-Date) - Comparing $deploy_src\bin $deploy_dst\bin (->)"
      Compare_Directory $deploy_dst\bin $deploy_src\bin
Related Topic