Home > Blockchain >  Powershell Compare two directories files (Name and Hash). Report if the name is only in one dir but
Powershell Compare two directories files (Name and Hash). Report if the name is only in one dir but

Time:03-07

I have two directories. One is the Source one was a Copy of the source that could be changed. I need to compare the two directories to find if there are:

  1. New files in either directory
  2. Existing files that have changed in the Copy only.

I created the following and it shows me all that but it flags the changed files from both sides. Giving me two results for the same file. I want to filter already compared files so that only one instance shows.

Here is what I have

$VDrive = "C:\Temp"
$Set = "GroupA"
function check-hash{
$DefaultDir = "$VDrive\Default\Files"
$SetDir = "$VDrive\$Set\Files"
    
    $SetArray = @()
    $SetArray = @((Get-ChildItem -File -Path $SetDir -Recurse) | Where-Object { $_ -notmatch "Thumbs.db"}| 
    ForEach-Object {
        [PSCustomObject]@{
        h = (Get-FileHash $_.FullName -Algorithm SHA1).Hash
        n = $_.Name
        s = $_.Length
        fn = $_.fullname
        }})
   
    $DefaultArray = @()
    $DefaultArray = @((Get-ChildItem -File -Path $DefaultDir -Recurse) | Where-Object { $_-notmatch "Thumbs.db"}| 
    ForEach-Object {
        [PSCustomObject]@{
        h = (Get-FileHash $_.FullName -Algorithm SHA1).Hash
        n = $_.Name
        s = $_.Length
        fn = $_.fullname
        }})

    Compare-Object -ReferenceObject $DefaultArray  -DifferenceObject $SetArray -Property n,h,s -PassThru | ForEach-Object {
        $Vfile = $($_.fn)
        #if ($_.SideIndicator -eq "==" ) { "===$Vfile in passed Hash Check" } 
        if ($_.SideIndicator -eq "<=" ) { "Hash Update $Vfile - Default file Different" }
        if ($_.SideIndicator -eq "=>" )  { "Hash Delete $Vfile - In Set not Default" }
        }           
}
check-hash

This returns <= and => for any file that is different. I just want one but I need to check both ways.

CodePudding user response:

This is how I would do it, it's more code than what you already have but I believe should do what you're looking for.

The firsts steps are mainly the same, gather all SHA1 hashes from both folders and construct a list of objects.
Then, on the first loop over the "difference folder" (this would be the Copy folder), filter by Unique files based on it's hashes compared to the reference folder and files where the Name of the file exists in the reference folder but it's hash has changed (this would meet the condition 2 of your question).
Lastly, the second loop over the "reference folder" to get the unique files of this collection based on the file hashes.

The $result collection would be an array of objects with a newly added property Status to help identify if the file has changed or if it's unique.

$result = [System.Collections.Generic.List[object]]::new()

$sb = {
    process {
        if($_.Name -eq 'Thumbs.db') { return }

        [PSCustomObject]@{
            h  = (Get-FileHash $_.FullName -Algorithm SHA1).Hash
            n  = $_.Name
            s  = $_.Length
            fn = $_.fullname
        }
    }
}

$refFiles  = Get-ChildItem 'path/to/reference/folder' -Recurse -File | & $sb
$diffFiles = Get-ChildItem 'path/to/difference/folder' -Recurse -File | & $sb

foreach($file in $diffFiles) {
    # this file exists on both folders, skip it
    if($file.h -in $refFiles.h) { continue }
    # this file exists on reference folder but has changed
    if($file.n -in $refFiles.n) {
        $file.PSObject.Properties.Add(
            [psnoteproperty]::new('Status', 'Changed in Ref')
        )
        $result.Add($file)
        continue
    }
    # this file does not exist on reference folder
    # based on previous conditions
    $file.PSObject.Properties.Add(
        [psnoteproperty]::new('Status', 'Unique in Diff')
    )
    $result.Add($file)
}

foreach($file in $refFiles) {
    # this file is unique in reference folder, rest of the files
    # not meeting this condition can be ignored since we're
    # interested only in files on reference folder that are unique
    if($file.h -notin $diffFiles.h) {
        $file.PSObject.Properties.Add(
            [psnoteproperty]::new('Status', 'Unique in Ref')
        )
        $result.Add($file)
    }
}

$result | Format-Table
  • Related