Powershell 比较两个目录文件(名称和哈希)。报告名称是否仅在一个目录中,但忽略它进行哈希检查

Powershell Compare two directories files (Name and Hash). Report if the name is only in one dir but ignore it for the hash check

我有两个目录。一个是来源,一个是可以更改的来源的副本。我需要比较两个目录,看看是否有:

  1. 任一目录中的新文件
  2. 仅在副本中更改的现有文件。

我创建了以下内容,它向我展示了所有内容,但它标记了双方的更改文件。给我同一个文件的两个结果。我想过滤已经比较过的文件,以便只显示一个实例。

这是我的

$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

此 returns <= 和 => 对于任何不同的文件。我只想要一个,但我需要检查两种方式。

这就是我的做法,它比您已有的代码更多,但我相信应该可以满足您的需求。

第一步基本相同,从两个文件夹收集所有 SHA1 哈希并构建对象列表。
然后,在 “差异文件夹”(这将是 复制文件夹)的第一个循环中,按 与参考文件夹相比,基于其哈希值的独特文件参考文件夹中存在文件名称但其哈希值已更改的文件(这将满足你问题的 条件 2)。
最后,第二次循环遍历 “参考文件夹”,以根据文件哈希值 获取此集合的唯一文件

$result 集合将是一个包含新添加的 属性 Status 的对象数组,以帮助识别文件是否已更改或是否唯一。

$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

我正在玩 Compare-object,我能够通过创建一个子数组来让它工作。感谢@Theo 的post。 @Santiago Squarzon 的答案有效,但我仍然很好奇我是否可以做到。

$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
        pn = $($_.fullname).Replace("C:\Temp$Set", "")
        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
        pn = $($_.fullname).Replace("C:\Temp\Default", "")
        fn = $_.fullname
        }})

    Write-host "Comparing..."
    $compare = Compare-Object -ReferenceObject $DefaultArray  -DifferenceObject $SetArray -Property h,pn -IncludeEqual -PassThru | Select-Object n,pn,SideIndicator,fn
    $filecomp = Compare-Object -ReferenceObject $DefaultArray  -DifferenceObject $SetArray -Property pn -IncludeEqual -PassThru | Select-Object n,pn,SideIndicator,fn
        $doSet = $compare | Where-Object { $_.SideIndicator -eq '<=' }
        $doDefault = $compare | Where-Object { $_.SideIndicator -eq '=>' }
        $foSet = $filecomp | Where-Object { $_.SideIndicator -eq '<=' }
        $foDefault = $filecomp | Where-Object { $_.SideIndicator -eq '=>' } 

        if ($foSet) {
            Write-Host "File Delta from Default"  -ForegroundColor Yellow
            $foSet | Format-Table -AutoSize
            }
    
        if ($foDefault) {
            Write-Host "File Delta From Set"  -ForegroundColor Green
            $foDefault | Format-Table -AutoSize
            }
               
#####   Try comparing doSet and doDefault ############################################
    $Dcomp = Compare-Object -ReferenceObject $doSet  -DifferenceObject $doDefault -Property pn -IncludeEqual -PassThru | Select-Object n,pn,SideIndicator,fn
        $DcompSwim = $Dcomp | Where-Object { $_.SideIndicator -eq '==' }
    
        if ($DcompSwim) {
            Write-Host "Hash Delta from Default"  -ForegroundColor Cyan
            $DcompSwim | Format-Table -AutoSize
            }
    
}
check-hash