使用 powershell 比较三个目录

使用 powershell 比较三个目录

想要比较 3 个 DFS 目录。helios456 为两个目录编写了一个不错的脚本,我尝试修改以满足我的需求,但遇到了瓶颈。Winmerge、Beyond Compare 和 diffmerge 只能执行 2 个。

任何帮助都是极好的。

$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"
    }
}

答案1

您可以使用 Victor Vogelpoel 于 2013 年发布的脚本(网址:http://blog.victorvogelpoel.nl/2013/09/10/powershell-compare-directory-ps1/)您可以Compare-Directory按照以下方式使用此函数来检查多个目录之间的差异:

Compare-Directory -ReferenceDirectory "C:\Folder1" -DifferenceDirectory "C:\Folder2","C:\Folder3"

为了方便以后参考,Victor 发布的完整代码:

function global:Compare-Directory
{
[CmdletBinding()]
param
(
    [Parameter(Mandatory=$true, position=0, ValueFromPipelineByPropertyName=$true, HelpMessage="The reference directory to compare one or more difference directories to.")]
    [System.IO.DirectoryInfo]$ReferenceDirectory,

    [Parameter(Mandatory=$true, position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="One or more directories to compare to the reference directory.")]
    [System.IO.DirectoryInfo[]]$DifferenceDirectory,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Recurse the directories")]
    [switch]$Recurse,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Files to exclude from the comparison")]
    [String[]]$ExcludeFile,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Directories to exclude from the comparison")]
    [String[]]$ExcludeDirectory,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Displays only the characteristics of compared objects that are equal.")]
    [switch]$ExcludeDifferent,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Displays characteristics of files that are equal. By default, only characteristics that differ between the reference and difference files are displayed.")]
    [switch]$IncludeEqual,

    [Parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, HelpMessage="Passes the objects that differed to the pipeline.")]
    [switch]$PassThru
)

begin
{
    function Get-MD5
    {
        [CmdletBinding(SupportsShouldProcess=$false)]
        param
        (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="file(s) to create hash for")]
            [Alias("File", "Path", "PSPath", "String")]
            [ValidateNotNull()]
            $InputObject
        )

        begin
        {
            $cryptoServiceProvider    = [System.Security.Cryptography.MD5CryptoServiceProvider]
            $hashAlgorithm             = new-object $cryptoServiceProvider
        }

        process
        {
            $hashByteArray = ""

            $item = Get-Item $InputObject -ErrorAction SilentlyContinue
            if ($item -is [System.IO.DirectoryInfo])    { throw "Cannot create hash for directory" }
            if ($item)                                     { $InputObject = $item }

            if ($InputObject -is [System.IO.FileInfo])
            {
                $stream         = $null;
                $hashByteArray    = $null

                try
                {
                    $stream                 = $InputObject.OpenRead();
                    $hashByteArray             = $hashAlgorithm.ComputeHash($stream);
                }
                finally
                {
                    if ($stream -ne $null)
                    {
                        $stream.Close();
                    }
                }
            }
            else
            {
                $utf8             = new-object -TypeName "System.Text.UTF8Encoding"
                $hashByteArray     = $hashAlgorithm.ComputeHash($utf8.GetBytes($InputObject.ToString()));
            }

            Write-Output ([BitConverter]::ToString($hashByteArray)).Replace("-","")
        }
    }

    function Get-Files
    {
        [CmdletBinding(SupportsShouldProcess=$false)]
        param
        (
            [string]$DirectoryPath,
            [String[]]$ExcludeFile,
            [String[]]$ExcludeDirectory,
            [switch]$Recurse
        )

        $relativeBasenameIndex = $DirectoryPath.ToString().Length

        # Get the files from the first deploypath
        # and ADD the MD5 hash for the file as a property
        # and ADD a filepath relative to the deploypath as a property
        Get-ChildItem -Path $DirectoryPath -Exclude $ExcludeFile -Recurse:$Recurse | foreach {
            $hash = ""
            if (!$_.PSIsContainer) { $hash = Get-MD5 $_    }

            # Added two new properties to the DirectoryInfo/FileInfo objects
            $item = $_ |
                Add-Member -Name "MD5Hash" -MemberType NoteProperty -Value $hash -PassThru |
                Add-Member -Name "RelativeBaseName" -MemberType NoteProperty -Value ($_.FullName.Substring($relativeBasenameIndex)) -PassThru

            # Test for directories and files that need to be excluded because of ExcludeDirectory
            if ($item.PSIsContainer) { $item.RelativeBaseName += "\" }
            if ($ExcludeDirectory | where { $item.RelativeBaseName -like "\$_\*" })
            {
                Write-Verbose "Ignore item `"$($item.Fullname)`""
            }
            else
            {
                Write-Verbose "Adding `"$($item.Fullname)`" to result set"
                Write-Output $item
            }
        }
    }

    $referenceDirectoryFiles = Get-Files -DirectoryPath $referenceDirectory -ExcludeFile $ExcludeFile -ExcludeDirectory $ExcludeDirectory -Recurse:$Recurse
}

process
{
    if ($DifferenceDirectory -and $referenceDirectoryFiles)
    {
        foreach($nextPath in $DifferenceDirectory)
        {
            $nextDifferenceFiles = Get-Files -DirectoryPath $nextpath -ExcludeFile $ExcludeFile -ExcludeDirectory $ExcludeDirectory -Recurse:$Recurse

            ###################################################
            # Compare the contents of the two file/directory arrays and return the results
            $results = @(Compare-Object -ReferenceObject $referenceDirectoryFiles -DifferenceObject $nextDifferenceFiles -ExcludeDifferent:$ExcludeDifferent -IncludeEqual:$IncludeEqual -PassThru:$PassThru -Property RelativeBaseName, MD5Hash)

            if (!$PassThru)
            {
                foreach ($result in $results)
                {
                    $path         = $ReferenceDirectory
                    $pathFiles    = $referenceDirectoryFiles
                    if ($result.SideIndicator -eq "=>")
                    {
                        $path         = $nextPath
                        $pathFiles    = $nextDifferenceFiles
                    }

                    # Find the original item in the files array
                    $itemPath = (Join-Path $path $result.RelativeBaseName).ToString().TrimEnd('\')
                    $item = $pathFiles | where { $_.fullName -eq $itemPath }

                    $result | Add-Member -Name "Item" -MemberType NoteProperty -Value $item
                }
            }

            Write-Output $results
        }
    }
}

<#
    .SYNOPSIS
        Compares a reference directory with one or more difference directories.

    .DESCRIPTION
        Compare-Directory compares a reference directory with one ore more difference
        directories. Files and directories are compared both on filename and contents
        using a MD5hash.

        Internally, Compare-Object is used to compare the directories. The behavior
        and results of Compare-Directory is similar to Compare-Object.

    .PARAMETER  ReferenceDirectory
        The reference directory to compare one or more difference directories to.

    .PARAMETER  DifferenceDirectory
        One or more directories to compare to the reference directory.

    .PARAMETER Recurse
        Include subdirectories in the comparison.

    .PARAMETER ExcludeFile
        File names to exclude from the comparison.

    .PARAMETER ExcludeDirectory
        Directory names to exclude from the comparison. Directory names are
        relative to the Reference of Difference Directory path

    .PARAMETER ExcludeDifferent
        Displays only the characteristics of compared files that are equal.

    .PARAMETER IncludeEqual
        Displays characteristics of files that are equal. By default, only
        characteristics that differ between the reference and difference files
        are displayed.

    .PARAMETER PassThru
        Passes the objects that differed to the pipeline. By default, this
        cmdlet does not generate any output.

    .EXAMPLE
        Compare-Directory -reference "D:\TEMP\CompareTest\path1" -difference "D:\TEMP\CompareTest\path2" -ExcludeFile "web.config" -recurse

        Compares directories "D:\TEMP\CompareTest\path1" and "D:\TEMP\CompareTest\path2" recursively, excluding "web.config"
        Only differences are shown. Results:

        RelativeBaseName  MD5Hash                          SideIndicator Item
        ----------------  -------                          ------------- ----
        bin\site.dll      87A1E6006C2655252042F16CBD7FB41B =>            D:\TEMP\CompareTest\path2\bin\site.dll
        index.html        02BB8A33E1094E547CA41B9E171A267B =>            D:\TEMP\CompareTest\path2\index.html
        index.html        20EE266D1B23BCA649FEC8385E5DA09D <=            D:\TEMP\CompareTest\path1\index.html
        web_2.config      5E6B13B107ED7A921AEBF17F4F8FE7AF <=            D:\TEMP\CompareTest\path1\web_2.config
        bin\site.dll      87A1E6006C2655252042F16CBD7FB41B =>            D:\TEMP\CompareTest\path2\bin\site.dll
        index.html        02BB8A33E1094E547CA41B9E171A267B =>            D:\TEMP\CompareTest\path2\index.html
        index.html        20EE266D1B23BCA649FEC8385E5DA09D <=            D:\TEMP\CompareTest\path1\index.html
        web_2.config      5E6B13B107ED7A921AEBF17F4F8FE7AF <=            D:\TEMP\CompareTest\path1\web_2.config

    .EXAMPLE
        Compare-Directory -reference "D:\TEMP\CompareTest\path1" -difference "D:\TEMP\CompareTest\path2" -ExcludeFile "web.config" -recurse -IncludeEqual

        Compares directories "D:\TEMP\CompareTest\path1" and "D:\TEMP\CompareTest\path2" recursively, excluding "web.config".
        Results include the items that are equal:

        RelativeBaseName    MD5Hash                          SideIndicator Item
        ----------------    -------                          ------------- ----
        bin                                                  ==            D:\TEMP\CompareTest\path1\bin
        bin\site2.dll       98B68D681A8D40FA943D90588E94D1A9 ==            D:\TEMP\CompareTest\path1\bin\site2.dll
        bin\site3.dll       9408C4B29F82260CBBA528342CBAA80F ==            D:\TEMP\CompareTest\path1\bin\site3.dll
        bin\site4.dll       0616E1FBE12D468F611F07768D70C2EE ==            D:\TEMP\CompareTest\path1\bin\site4.dll
        ...
        bin\site8.dll       87A1E6006C2655252042F16CBD7FB41B =>            D:\TEMP\CompareTest\path2\bin\site8.dll
        index.html          02BB8A33E1094E547CA41B9E171A267B =>            D:\TEMP\CompareTest\path2\index.html
        index.html          20EE266D1B23BCA649FEC8385E5DA09D <=            D:\TEMP\CompareTest\path1\index.html
        web_2.config        5E6B13B107ED7A921AEBF17F4F8FE7AF <=            D:\TEMP\CompareTest\path1\web_2.config

    .EXAMPLE
        Compare-Directory -reference "D:\TEMP\CompareTest\path1" -difference "D:\TEMP\CompareTest\path2" -ExcludeFile "web.config" -recurse -ExcludeDifference

        Compares directories "D:\TEMP\CompareTest\path1" and "D:\TEMP\CompareTest\path2" recursively, excluding "web.config".
        Results only include the files that are equal; different files are excluded from the results.

    .EXAMPLE
        Compare-Directory -reference "D:\TEMP\CompareTest\path1" -difference "D:\TEMP\CompareTest\path2" -ExcludeFile "web.config" -recurse -Passthru

        Compares directories "D:\TEMP\CompareTest\path1" and "D:\TEMP\CompareTest\path2" recursively, excluding "web.config" and returns NO comparison
        results, but the different files themselves!

        FullName
        --------
        D:\TEMP\CompareTest\path2\bin\site3.dll
        D:\TEMP\CompareTest\path2\index.html
        D:\TEMP\CompareTest\path1\index.html
        D:\TEMP\CompareTest\path1\web_2.config

    .LINK
        Compare-Object
#>
}

相关内容