Сценарии нахождят на основании MD5-хэша и удаляют файлы с одинаковым содержимым
function Find-EqualFile
{
<#
.SYNOPSIS
Командлет предназначен для поиска одинаковых файлов
.DESCRIPTION
Командлет находит в указанных папках файлы с одинаковым
размером и на основании MD5-хэша отбирает из них файлы с
одинаковым содержимым
.PARAMETER Folders
Папки, в которых необходимо найти одинаковые файлы
.PARAMETER OutputCSV
Путь к CSV-файлу со списком одинаковых файлов
.INPUTS
-
.OUTPUTS
-
.NOTES
Версия 1.3
(c) 2019 Александр Галков, [email protected]
.EXAMPLE
Find-EqualFile -Folders "c:\folder1","c:\folder2" -OutputCSV "c:\output.csv"
.LINK
www.galkov.pro/powershell_script_for_finding_equal_files
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][string[]]$Folders,
[Parameter(Mandatory=$true)][string]$OutputCSV
)
$format = "yyyy-MM-dd HH:mm:ss"
#составляем список всех файлов
Write-Host ("{0} Составляем список всех файлов..." -f ([DateTime]::Now).ToString($format))
$all_files = @()
foreach ($folder in $Folders)
{
$all_files += Get-ChildItem -LiteralPath $folder -File -Recurse -Force
}
Write-Host ("{0} Обнаружено файлов: {1}" -f ([DateTime]::Now).ToString($format), $all_files.Length)
#составляем список файлов с одинаковым размером
Write-Host ("{0} Составляем список файлов с одинаковым размером..." -f ([DateTime]::Now).ToString($format))
$eq_size_groups = @{}
for ($i=0; $i -lt $all_files.Length; $i++)
{
$size = $all_files[$i].Length
if (!$eq_size_groups.ContainsKey($size))
{
$eq_size_groups.Add($size,@())
}
$eq_size_groups[$size] += $all_files[$i]
}
$eq_size_file_count = 0
$eq_size_group_count = 0
foreach ($eq_size_files in $eq_size_groups.Values)
{
if ($eq_size_files.Length -gt 1)
{
$eq_size_file_count += $eq_size_files.Length
$eq_size_group_count++
}
}
Write-Host ("{0} Обнаружено групп файлов с одинаковым размером: {1}, в них файлов: {2}" -f
([DateTime]::Now).ToString($format), $eq_size_group_count, $eq_size_file_count)
#вычисляем хэш
Write-Host ("{0} Вычисляем хэш..." -f ([DateTime]::Now).ToString($format))
$eq_hash_groups = @{}
$proc_file_count = 0
foreach ($eq_size_files in $eq_size_groups.Values)
{
if ($eq_size_files.Length -gt 1)
{
for ($i=0; $i -lt $eq_size_files.Length; $i++)
{
$hash = Get-FileHash -LiteralPath $eq_size_files[$i].FullName -Algorithm MD5
if (!$eq_hash_groups.ContainsKey($hash.Hash))
{
$eq_hash_groups.Add($hash.Hash,@())
}
$eq_hash_groups[$hash.Hash] += $eq_size_files[$i]
if ($proc_file_count%[Math]::Ceiling($eq_size_file_count/10) -eq 0 -or $proc_file_count -eq $eq_size_file_count-1)
{
write-host ("{0} Обработано: {1} %" -f ([DateTime]::Now).ToString($format),
[Math]::Round(($proc_file_count+1)/$eq_size_file_count*100))
}
$proc_file_count++
}
}
}
$eq_hash_file_count = 0
$eq_hash_group_count = 0
foreach ($eq_hash_files in $eq_hash_groups.Values)
{
if ($eq_hash_files.Length -gt 1)
{
$eq_hash_file_count += $eq_hash_files.Length
$eq_hash_group_count++
}
}
Write-Host ("{0} Обнаружено групп файлов с одинаковым хэшем: {1}, в них файлов: {2}" -f
([DateTime]::Now).ToString($format), $eq_hash_group_count, $eq_hash_file_count)
#сохраняем результат
Write-Host ("{0} Сохраняем результат в файл {1}" -f ([DateTime]::Now).ToString($format), $OutputCSV)
$file_instances = @()
foreach ($hash in $eq_hash_groups.Keys)
{
$eq_hash_files = $eq_hash_groups[$hash]
if ($eq_hash_files.Length -gt 1)
{
$eq_hash_files = $eq_hash_files | Sort -Property Fullname
for ($i=0; $i -lt $eq_hash_files.Length; $i++)
{
$file_instance = New-Object -TypeName PSObject
Add-Member -InputObject $file_instance -MemberType NoteProperty -Name ID -Value 0
Add-Member -InputObject $file_instance -MemberType NoteProperty -Name Fullname -Value $eq_hash_files[$i].Fullname
Add-Member -InputObject $file_instance -MemberType NoteProperty -Name Instance -Value ($i+1)
Add-Member -InputObject $file_instance -MemberType NoteProperty -Name Hash -Value $hash
$file_instances += $file_instance
}
}
}
$file_instances = $file_instances | Sort -Property Instance,Fullname
for ($i=0; $i -lt $file_instances.Length; $i++)
{
$file_instances[$i].ID = $i
}
$file_instances | Export-Csv -LiteralPath $OutputCSV -Encoding UTF8 -NoTypeInformation
}
function Remove-ExcessFile
{
<#
.SYNOPSIS
Командлет предназначен для удаления лишних экземпляров файлов
.DESCRIPTION
-
.PARAMETER InputCSV
CSV-файл, полученный в результате выполнения командлета Find-EqualFile
.PARAMETER IDs
ID файлов, которые нужно удалить
.INPUTS
-
.OUTPUTS
-
.NOTES
Версия 1.0
(c) 2019 Александр Галков, [email protected]
.EXAMPLE
Remove-ExcessFile -InputCSV "с:\input.csv" -IDs "5-25,30,50-75,100"
.LINK
www.galkov.pro/powershell_script_for_finding_equal_files
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][string]$InputCSV,
[Parameter(Mandatory=$true)][string]$IDs
)
$all_files = Import-Csv -LiteralPath $InputCSV -Encoding UTF8
$intervals = @()
while ($IDs -ne "")
{
if ($IDs -match "(.*),(.*)")
{
$IDs = $Matches[1]
$id = $Matches[2]
}
else
{
$id = $IDs
$IDs = ""
}
$interval = New-Object -TypeName PSObject
Add-Member -InputObject $interval -MemberType NoteProperty -Name Left -Value 0
Add-Member -InputObject $interval -MemberType NoteProperty -Name Right -Value 0
if ($id -match "(.*)-(.*)")
{
$interval.Left = [Convert]::ToInt32($Matches[1])
$interval.Right = [Convert]::ToInt32($Matches[2])
}
else
{
$interval.Left = $interval.Right = [Convert]::ToInt32($id)
}
$intervals += $interval
}
$removed_files = @()
foreach ($file in $all_files)
{
foreach ($interval in $intervals)
{
if ([Convert]::ToInt32($file.ID) -ge $interval.Left -and [Convert]::ToInt32($file.ID) -le $interval.Right)
{
$removed_files += $file
break
}
}
}
$removed_files | Format-Table -AutoSize
$answer = ""
while ($answer.ToLower() -ne "y" -and $answer.ToLower() -ne "n")
{
$answer = Read-Host -Prompt $("Удалить указанные файлы в количестве {0} шт (y/n)?" -f $removed_files.Length)
}
if ($answer.ToLower() -eq "y")
{
foreach ($removed_file in $removed_files)
{
Remove-Item -LiteralPath $removed_file.Fullname -Force
}
}
}