PowerShell脚本用于比较两个文件夹并将不同的项目复制到第三个文件夹。

huangapple go评论52阅读模式
英文:

PowerShell script to compare 2 folders and copy different items to third folder

问题

我有2个文件夹:SourceFolder和DestinationFolder,它们里面都有相同的子文件夹,并且每个子文件夹中都有相似的文件。我还有一个名为ResultsFolder的第三个文件夹。我需要比较所有文件并执行以下操作:

  1. 如果SourceFolder中有新文件,需要将其复制到ResultsFolder的相应子文件夹中。
  2. 如果任何文件的内容发生更改,需要将其复制到ResultsFolder的相应子文件夹中。

例如,SourceFolder和DestinationFolder都有3个子文件夹:sub1、sub2和sub3。

脚本需要在ResultsFolder中创建sub1子文件夹,并将file2sub1.txt复制到ResultsFolder\sub1中。
另外,如果file1sub2.txt发生了更改(添加或删除了一些字符),脚本需要在ResultsFolder中创建sub2子文件夹,并将file1sub2.txt复制到ResultsFolder\sub2中。
而如果file1sub3.txt没有发生更改,则无需采取任何操作。

我尝试了很多方法,最近我在尝试以下脚本:

$SourceFolder = 'C:\Test\Source\'
$DestinationFolder = 'C:\Test\Destination\'
$ResultsFolder = 'C:\Test\Results\'

$RefFiles = Get-ChildItem $SourceFolder -Recurse | Select-Object -Property *, @{name = 'Hash'; expression = { (Get-FileHash $_.FullName -Algorithm MD5).hash } }
$DiffFiles = Get-ChildItem $DestinationFolder -Recurse | Select-Object -Property *, @{name = 'Hash'; expression = { (Get-FileHash $_.FullName -Algorithm MD5).hash } }

Compare-Object -Ref $RefFiles -Dif $DiffFiles -Property Name, Hash |
    ForEach-Object {
        if ($_.SideIndicator -eq '<=') {
            Copy-Item $_.Name -Destination $ResultsFolder -Recurse -Container
        }
    }

希望这能帮助你解决问题。

英文:

I have 2 folders: SourceFolder and DestinationFolder with the same subfolders in them and with similar files in every subfolders. And I have a third folder ResultsFolder. I need to compare all files and:

  1. if there is a new file in the SourceFolder it needs to be copied to the ResultsFolder to the appropriate subfolder.
  2. if any of files content is changed it needs to be copied to the ResultsFolder to the appropriate subfolder it belongs to.

For example, both SourceFolder and DestinationFolder have 3 subfolders: sub1, sub2 and sub3.

SourceFolder\sub1 have file1sub1.txt, file2sub1.txt
SourceFolder\sub2 have file1sub2.txt
SourceFolder\sub3 have file1sub3.txt
DestinationFolder\sub1 have file1sub1.txt
DestinationFolder\sub2 have file1sub2.txt
DestinationFolder\sub3 have file1sub3.txt

Script needs to create subfolder sub1 in ResultsFolder and to copy file2sub1.txt to ResultsFolder\sub1.
Also, if file1sub2.txt is changed (added or removed some character), script needs to create sub2 in ResultsFolder and to copy file1sub2.txt to ResultsFolder\sub2.
And, if file1sub3.txt is not changed, it doesn't need to do anything.

I tried a lot of thing, and the latest I am playing with is this:

$SourceFolder = &#39;C:\Test\Source\&#39;
$DestinationFolder = &#39;C:\Test\Destination\&#39;
$ResultsFolder = &#39;C:\Test\Results\&#39;

$RefFiles = Get-ChildItem $SourceFolder -Recurse | Select-Object -Property *, @{name = &#39;Hash&#39;; expression = { (Get-FileHash $_.FullName -Algorithm MD5).hash } }
$DiffFiles = Get-ChildItem $DestinationFolder -Recurse | Select-Object -Property *, @{name = &#39;Hash&#39;; expression = { (Get-FileHash $_.FullName -Algorithm MD5).hash } }

Compare-Object -Ref $RefFiles -Dif $DiffFiles -Property Name, Hash |
    ForEach-Object {
        if ($_.SideIndicator -eq &#39;&lt;=&#39;) {
            Copy-Item $_.Name -Destination $ResultsFolder -Recurse - Container
        }
    }

答案1

得分: 0

代码有点复杂,但内联注释应该有助于理解逻辑。在这种情况下,理想的路线是使用散列表作为快速查找的参考。

$SourceFolder = 'C:\Test\Source\'
$DestinationFolder = 'C:\Test\Destination\'
$ResultsFolder = 'C:\Test\Results\'

# 参考实际上应该是目的地,而不是源
$ref = @{}
# 递归获取所有文件
Get-ChildItem $DestinationFolder -Recurse -File | ForEach-Object {
    # 构建参考哈希表:
    #   - 键   = 文件相对路径
    #   - 值   = FileInfo 参考
    $ref[$_.FullName.Remove(0, $DestinationFolder.Length)] = $_
}

# 获取源中的所有文件
Get-ChildItem $SourceFolder -Recurse -File | ForEach-Object {
    $relative = $_.FullName.Remove(0, $SourceFolder.Length)
    # 如果参考映射具有此相对路径,并且两个文件具有相同的`.Length`
    if($ref.ContainsKey($relative) -and $ref[$relative].Length -eq $_.Length) {
        # 获取参考文件的哈希值
        $refHash = ($ref[$relative] | Get-FileHash -Algorithm MD5).Hash
        # 如果参考文件的哈希值与此文件的哈希值相同
        if($refHash -eq ($_ | Get-FileHash -Algorithm MD5).Hash) {
            # 那么我们可以跳过这里,继续下一个
            return
        }
    }

    # 否则,我们可以假定此文件要么不存在,要么具有不同的哈希值
    # 因此,首先构建目标路径
    $destination = Join-Path $ResultsFolder ([System.IO.Path]::GetDirectoryName($relative))
    # 如果目标目录不存在
    if(-not [System.IO.Directory]::Exists($destination)) {
        # 创建它
        $null = [System.IO.Directory]::CreateDirectory($destination)
    }

    # 现在我们可以将此文件复制到新的目标文件夹
    $_ | Copy-Item -Destination $destination
}
英文:

Code is a bit extensive but the inline comments should help you understand the logic. The ideal route in this case is to use a hashtable as your reference for fast look-ups.

$SourceFolder = &#39;C:\Test\Source\&#39;
$DestinationFolder = &#39;C:\Test\Destination\&#39;
$ResultsFolder = &#39;C:\Test\Results\&#39;

# The reference should actually be the Destination, instead of the source
$ref = @{}
# Get all files recursively
Get-ChildItem $DestinationFolder -Recurse -File | ForEach-Object {
    # construct a ref hash:
    #   - Key   = File Relative path
    #   - Value = The FileInfo Reference
    $ref[$_.FullName.Remove(0, $DestinationFolder.Length)] = $_
}

# Get all files in the source
Get-ChildItem $SourceFolder -Recurse -File | ForEach-Object {
    $relative = $_.FullName.Remove(0, $SourceFolder.Length)
    # if the ref map has this relative path and both files have the same `.Length`
    if($ref.ContainsKey($relative) -and $ref[$relative].Length -eq $_.Length) {
        # get the hash of the ref file
        $refHash = ($ref[$relative] | Get-FileHash -Algorithm MD5).Hash
        # if hash of the ref file is the same as this file hash
        if($refHash -eq ($_ | Get-FileHash -Algorithm MD5).Hash) {
            # then we can skip here, go next
            return
        }
    }

    # else, we can assume this file either does not exist or has a different hash
    # so, build the destination path first
    $destination = Join-Path $ResultsFolder ([System.IO.Path]::GetDirectoryName($relative))
    # if the destination directory does not exist
    if(-not [System.IO.Directory]::Exists($destination)) {
        # create it
        $null = [System.IO.Directory]::CreateDirectory($destination)
    }

    # now we can copy this file to the new destination folder
    $_ | Copy-Item -Destination $destination
}

huangapple
  • 本文由 发表于 2023年5月29日 20:03:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76357202.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定