Поиск по сайту:

Как найти повторяющиеся файлы с помощью PowerShell


Для одного из проектов мне понадобился скрипт PowerShell для поиска дубликатов файлов в общей сетевой папке файлового сервера. Существует ряд сторонних инструментов для поиска и удаления дубликатов файлов в Windows, но большинство из них являются коммерческими или не подходят для автоматических сценариев.

Поскольку файлы могут иметь разные имена, но одинаковое содержимое, не следует сравнивать файлы только по имени. Лучше получить хеши всех файлов и найти среди них одинаковые.

Следующая однострочная команда PowerShell позволяет рекурсивно сканировать папку (включая ее подпапки) и находить повторяющиеся файлы. В этом примере были найдены два одинаковых файла с одинаковыми хэшами:

Get-ChildItem -path C:\Share\ -Recurse | Get-FileHash | Group-Object -property hash | Where-Object { $_.count -gt 1 } | ForEach-Object { $_.group | Select-Object Path, Hash }

Эту однострочную строку PowerShell легко использовать для поиска дубликатов, однако ее производительность довольно низкая. Если в папке много файлов, то вычисление их хэшей займет много времени. Проще сначала сравнить файлы по размеру (это готовый атрибут файла, который не нужно вычислять). Тогда мы получим хеши файлов только одинакового размера:

$file_dublicates = Get-ChildItem -path C:\Share\ -Recurse| Group-Object -property Length| Where-Object { $_.count -gt 1 }| Select-Object -Expand Group| Get-FileHash | Group-Object -property hash | Where-Object { $_.count -gt 1 }| ForEach-Object { $_.group | Select-Object Path, Hash }

Вы можете сравнить производительность обеих команд в тестовой папке с помощью командлета Measure-Command:

Measure-Command {your_powershell_command}

Для папки, содержащей 2000 файлов, вторая команда выполняется намного быстрее первой (10 минут против 3 секунд).

Вы можете предложить пользователю выбрать повторяющиеся файлы для удаления. Для этого передайте список дубликатов файлов командлету Out-GridView:

$file_dublicates | Out-GridView -Title "Select files to delete" -OutputMode Multiple -PassThru|Remove-Item -Verbose -WhatIf

Пользователь может выбрать файлы для удаления в таблице (чтобы выбрать несколько файлов, нажмите и удерживайте CTRL) и нажмите «ОК».

Вместо удаления вы можете переместить выбранные файлы в другой каталог с помощью Move-Item.

Также вы можете заменить дубликаты файлов жесткими ссылками. Такой подход позволяет сохранять файлы на месте и существенно экономит дисковое пространство.

param(
[Parameter(Mandatory=$True)]
[ValidateScript({Test-Path -Path $_ -PathType Container})]
[string]$dir1,
[Parameter(Mandatory=$True)]
[ValidateScript({(Test-Path -Path $_ -PathType Container) -and $_ -ne $dir1})]
[string]$dir2
)
Get-ChildItem -Recurse $dir1, $dir2 |
Group-Object Length | Where-Object {$_.Count -ge 2} |
Select-Object -Expand Group | Get-FileHash |
Group-Object hash | Where-Object {$_.Count -ge 2} |
Foreach-Object {
$f1 = $_.Group[0].Path
Remove-Item $f1
New-Item -ItemType HardLink -Path $f1 -Target $_.Group[1].Path | Out-Null
#fsutil hardlink create $f1 $_.Group[1].Path
}

Для запуска файла используйте следующий формат команды:

.\hardlinks.ps1 -dir1 d:\folder1 -dir2 d:\folder2

Скрипт можно использовать для поиска и замены дубликатов статических файлов (которые не изменяются!) символическими жесткими ссылками.

В Windows Server вы можете использовать встроенную функцию дедупликации данных роли файлового сервера для решения проблемы дублирования файлов. Однако при использовании дедупликации и инкрементального резервного копирования у вас возникнут некоторые проблемы при восстановлении из резервной копии.

Кроме того, вы можете использовать консольный инструмент dupemerge, чтобы заменить дублирующиеся файлы жесткими ссылками.

Статьи по данной тематике