Заметки · 03.04.2023

MD5 и PowerShell

Решил окончательно добить тему контрольных сумм в PowerShell. Предыдущий пост был здесь. Полноценная считалка лежит здесь.

Не так давно столкнулся с потоковым подсчётом контрольных сумм для кучи текстовых файлов. Важным условием было создание файла формата .md5, в котором должна храниться эталонная контрольная сумма и имя исследуемого файла. Само собой, применение каких-либо сторонних утилит я не рассматривал.

В файле .md5 хранится хэш и имя файла, с которого этот хэш и считался. Структура файла выглядит так: hash *filename.ext. Его можно открыть любым текстовым редактором и посмотреть, как саму контрольную сумму, так и целевой файл.

Для реализации поставленной задачи я написал вот такую функцию на базе командлета Get-FileHash:

function SaveMD5 ($path)
{
  if (Test-Path -Path $path)
  {
    try
    {
      $filename = (Get-Item $path).Name
      $dirname = (Get-Item $path).DirectoryName
      $woext = (Get-Item $path).BaseName
      $content = (Get-FileHash -Path $path -Algorithm MD5).Hash + " *" + $filename
      $content | Out-File $dirname\$woext".md5" -NoNewline -ErrorAction Stop
    }
    catch { $errorsave = "Ошибка сохранения файла!"; return $errorsave }
  }
  else { $errorfile = "Файл не найден!"; return $errorfile }
}

Функция проверяет наличие файла, считает его контрольную сумму и создает файл .md5. При возникновении ошибки возвращает переменные $errorsave или $errorfile.

Использовать функцию можно так:

SaveMD5 -path "P:\ATH\TO\FI.LE"

Для массовой обработки файлов запихнул функцию в цикл foreach:

$files = Get-ChildItem -Path D:\downloads\test
foreach ($file in $files) { SaveMD5 -path $file.FullName }

Разумеется, лучше избегать пробелов в именах файлов.

А теперь предположим, что имеется файл и документ .md5 с его контрольной суммой. Нужно проверить совпадает ли контрольная сумма из документа с контрольной суммой самого файла. Для этих целей я подготовил обратную функцию:

function CheckMD5 ($md5file)
{
  if (Test-Path -Path $md5file)
  {
    $dirname = (Get-Item $md5file).DirectoryName
    $content = (Get-Content -Path $md5file).Split(" *", [StringSplitOptions]::RemoveEmptyEntries)
    $md5hash = $content[0]
    $filename = $content[1]
    $pathtofile = $dirname + "\" + $filename
    $gethash = (Get-FileHash -Path $pathtofile -Algorithm MD5).Hash
    if ($md5hash -eq $gethash) { return $true } else { return $false }
  }
  else { $errorfile = "Файл не найден!"; return $errorfile }
}

Функция CheckMD5 парсит файл .md5 и создаёт массив из двух строк. Первая строка ($content[0]) содержит контрольную сумму, а вторая ($content[1]) имя файла. Далее идёт повторное вычисление контрольной суммы файла из $content[1] и сравнивание полученного хэша с $content[0].

Если всё совпадает возвращается True, а если нет — False.

Обращение к функции выглядит так:

CheckMD5 -md5file "P:\ATH\TO\FILE.MD5"

И последний штрих — это цикл:

$files = (Get-ChildItem -Path D:\downloads\test -Filter *.md5).FullName
foreach ($file in $files) { $func=CheckMD5 -md5file $file; Write-Host $file - $func }

Ну, и напоследок пример для экспресс-подсчёта контрольной суммы файла:

$filename = Get-Clipboard -Format FileDropList
(Get-FileHash -Path $filename -Algorithm MD5).Hash | Set-Clipboard

Помещаете файл в буфер обмена и запускаете эту конструкцию. По итогу в буфер вернётся контрольная сумма скопированного файла. Можно создать скрипт .ps1 и запускать его при необходимости.