Поиск дубликатов файлов с помощью 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 минут vs 3 секунды).

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

$file_dublicates | Out-GridView -Title "Выберите файлы для удаления" -OutputMode Multiple –PassThru|Remove-Item –Verbose –WhatIf

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

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

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

Приведу полный код скрипта с его сайта здесь (https://www.outsidethebox.ms/20953/):

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:fldr1 -dir2 d:fldr2

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

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

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


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *