如何在 Windows Powershell 中比较两个文件夹的差异?

如何在 Windows Powershell 中比较两个文件夹的差异?

我正在尝试使用 Windows Powershell 查找两个文件夹结构内容的差异。我使用了以下方法来确保文件名相同,但此方法并未告诉我文件的内容是否相同:

$firstFolder = Get-ChildItem -Recurse folder1
$secondFolder = Get-ChildItem -Recurse folder2
Compare-Object -ReferenceObject $firstFolder -DifferenceObject $secondFolder

描述的技术这个 ServerFault 问题适用于比较单个文件,但这些文件夹包含数百个不同深度的文件。

解决方案不一定需要告诉我文件中具体有什么不同 - 只需告诉我它们不同即可。我对元数据(例如日期)的差异不感兴趣,因为我已经知道它们是不同的。

答案1

如果您想将比较包装到循环中,我将采取以下方法:

$folder1 = "C:\Users\jscott"
$folder2 = "C:\Users\public"

# Get all files under $folder1, filter out directories
$firstFolder = Get-ChildItem -Recurse $folder1 | Where-Object { -not $_.PsIsContainer }

$firstFolder | ForEach-Object {

    # Check if the file, from $folder1, exists with the same path under $folder2
    If ( Test-Path ( $_.FullName.Replace($folder1, $folder2) ) ) {

        # Compare the contents of the two files...
        If ( Compare-Object (Get-Content $_.FullName) (Get-Content $_.FullName.Replace($folder1, $folder2) ) ) {

            # List the paths of the files containing diffs
            $_.FullName
            $_.FullName.Replace($folder1, $folder2)

        }
    }   
}

请注意,这将忽略不存在的文件同时 $folder1$folder2

答案2

我采用了 jscott 的答案,并对其进行了扩展,以便输出一个文件夹中存在但另一个文件夹中不存在的文件,供对此类功能感兴趣的人使用。请注意,它还显示了所取得的进展,因为考虑到文件夹很大且没有太多差异,我很难看到这一点。在我看来,脚本似乎被挂住了。以下是该脚本的 powershell 代码:

$folder1 = "C:\Folder1"
$folder2 = "C:\Folder2"

# Get all files under $folder1, filter out directories
$firstFolder = Get-ChildItem -Recurse $folder1 | Where-Object { -not $_.PsIsContainer }

$failedCount = 0
$i = 0
$totalCount = $firstFolder.Count
$firstFolder | ForEach-Object {
    $i = $i + 1
    Write-Progress -Activity "Searching Files" -status "Searching File  $i of     $totalCount" -percentComplete ($i / $firstFolder.Count * 100)
    # Check if the file, from $folder1, exists with the same path under $folder2
    If ( Test-Path ( $_.FullName.Replace($folder1, $folder2) ) ) {
        # Compare the contents of the two files...
        If ( Compare-Object (Get-Content $_.FullName) (Get-Content $_.FullName.Replace($folder1, $folder2) ) ) {
            # List the paths of the files containing diffs
            $fileSuffix = $_.FullName.TrimStart($folder1)
            $failedCount = $failedCount + 1
            Write-Host "$fileSuffix is on each server, but does not match"
        }
    }
    else
    {
        $fileSuffix = $_.FullName.TrimStart($folder1)
        $failedCount = $failedCount + 1
        Write-Host "$fileSuffix is only in folder 1"
    }
}

$secondFolder = Get-ChildItem -Recurse $folder2 | Where-Object { -not $_.PsIsContainer }

$i = 0
$totalCount = $secondFolder.Count
$secondFolder | ForEach-Object {
    $i = $i + 1
    Write-Progress -Activity "Searching for files only on second folder" -status "Searching File  $i of $totalCount" -percentComplete ($i / $secondFolder.Count * 100)
    # Check if the file, from $folder2, exists with the same path under $folder1
    If (!(Test-Path($_.FullName.Replace($folder2, $folder1))))
    {
        $fileSuffix = $_.FullName.TrimStart($folder2)
        $failedCount = $failedCount + 1
        Write-Host "$fileSuffix is only in folder 2"
    }
}

答案3

您只需循环遍历已经回答此问题的链接问题的正确答案,然后遍历目录树并比较每个具有相同名称的文件。

/编辑:如果这确实是你的疑问,那么它更适合 SO,你似乎是那里的常客。你问的是编程问题。我知道你是为了系统管理员的目的而这样做的,在这种情况下,我会告诉你使用 WinDiff 等专用工具。

答案4

以下函数递归检查多个文件夹(虽然一次两个)用于删除(仅限前者),添加(仅限后者),以及更改(共享名称的文件具有不同的内容

'folder1','folder2' | DiffFolders

功能:

Function DiffFolders {
    Begin {
        $last = $NULL
    }
    Process {
        $current = @{}
        $unchanged = 0
        
        $parent = $_
        $parentPath = (Get-Item -Path $parent).FullName
        $parentRegex = "^$([regex]::escape($parentPath))"
        Get-ChildItem -Path $parentPath -Recurse -File `
        | %{
            $name = $_.FullName -replace $parentRegex,''
            $current.Add($name, (Get-FileHash -LiteralPath $_.FullName).Hash)
            
            if (!$last) {
                return
            }
            
            if (!$last.Contains($name)) {
                [PSCustomObject]@{
                    parent = $parent
                    event = 'Added'
                    value = $name
                }
                return
            }
            
            if ($last[$name] -eq $current[$name]) {
                ++$unchanged
            }
            else {
                [PSCustomObject]@{
                    parent = $parent
                    event = 'Changed'
                    value = $name
                }
            }
            $last.Remove($name)
        }
        
        if ($last) {
            [PSCustomObject]@{
                parent = $parent
                event = 'Unchanged'
                value = $unchanged
            }
            $last.Keys `
            | %{
                [PSCustomObject]@{
                    parent = $parent
                    event = 'Deleted'
                    value = $_
                }
            }
        }
        
        $last = $current
    }
}

这是一个简洁的演示,应该适用于大多数 win10 机器:

PS C:\Program Files\WindowsApps> gci 'Microsoft.NET.Native.Runtime.*_x64__8wekyb3d8bbwe' | %{ $_.Name }
Microsoft.NET.Native.Runtime.1.7_1.7.25531.0_x64__8wekyb3d8bbwe
Microsoft.NET.Native.Runtime.1.7_1.7.27422.0_x64__8wekyb3d8bbwe
Microsoft.NET.Native.Runtime.2.1_2.1.26424.0_x64__8wekyb3d8bbwe
Microsoft.NET.Native.Runtime.2.2_2.2.27011.0_x64__8wekyb3d8bbwe
Microsoft.NET.Native.Runtime.2.2_2.2.28604.0_x64__8wekyb3d8bbwe
PS C:\Program Files\WindowsApps> gci 'Microsoft.NET.Native.Runtime.*_x64__8wekyb3d8bbwe' | %{ $_.Name } | DiffFolders | Out-GridView

我们可以准确地看到在 .NET 运行时中添加和删除了哪些版本的文件,以及哪些文件发生了更改。
未更改的文件没有被提及,但是为了简洁起见,还是算上(我猜通常未更改的文件会比更改的文件多得多)。

在此处输入图片描述

也适用于 Linux,适合在那里运行它的 powershell 用户 :)

对于那些好奇的人来说,未改变的文件是clrcompression.dll,logo.png,,,和logo.pnglogo.pnglogo.png

相关内容