Windows PowerShellでハッシュ値を計算する方法|ファイル改ざんチェックに最適

Windows

「このファイル、本当に改ざんされていない?」
「ダウンロードしたファイルが公式と同じか確認したい」

そんなときに役立つのがハッシュ値のチェックです。

この記事では、Windows PowerShellを使って簡単にハッシュ値(SHA256やMD5など)を計算する方法を詳しく紹介します。セキュリティ対策やデータ管理の基本として、ぜひ覚えておきましょう。

スポンサーリンク

そもそもハッシュ値とは?

ハッシュ値の基本概念

ハッシュ値(ダイジェスト値、チェックサムとも呼ばれる)は、ファイルの内容から一定の計算で求められる「指紋」のようなものです。

主な特徴:

  • ファイルの内容が1ビットでも変われば、ハッシュ値も大きく変わる
  • 同じファイルなら必ず同じハッシュ値になる
  • ハッシュ値から元のファイルを復元することは不可能(一方向性)
  • 計算が高速で、どんなサイズのファイルでも固定長の値になる

具体的な例で理解する

文字列での例

# "Hello World" という文字列のハッシュ値
$text1 = "Hello World"
$bytes1 = [System.Text.Encoding]::UTF8.GetBytes($text1)
$hash1 = [System.Security.Cryptography.SHA256]::Create().ComputeHash($bytes1)
$hashString1 = [BitConverter]::ToString($hash1) -replace '-'
Write-Host $hashString1
# 結果: A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E

# "Hello world" (小文字のw) という文字列のハッシュ値  
$text2 = "Hello world"
$bytes2 = [System.Text.Encoding]::UTF8.GetBytes($text2)
$hash2 = [System.Security.Cryptography.SHA256]::Create().ComputeHash($bytes2)
$hashString2 = [BitConverter]::ToString($hash2) -replace '-'
Write-Host $hashString2
# 結果: 64EC88CA00B268E5BA1A35678A1B5316D212F4F366B2477232534A8AECA37F3C

たった1文字の違い(大文字W→小文字w)で、ハッシュ値が完全に異なることがわかります。

ハッシュ値の実用的な用途

ファイルの整合性確認

  • ダウンロードしたファイルが破損していないかチェック
  • ネットワーク転送後のデータ整合性確認
  • バックアップの正確性検証

セキュリティ用途

  • ファイルの改ざん検知
  • マルウェアの検出
  • デジタル署名の基盤技術

システム管理

  • 重複ファイルの検出
  • ファイルバージョンの管理
  • システムファイルの監視

PowerShellでハッシュ値を計算する基本方法

Get-FileHashコマンドレットの基本

PowerShellでは Get-FileHash というコマンドレットを使えば、簡単にハッシュ値を計算できます。

最もシンプルな使い方

Get-FileHash C:\path\to\file.txt

実行結果の例:

Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
SHA256          8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C92       C:\path\to\file.txt

結果の詳細説明

  • Algorithm: 使用されたハッシュアルゴリズム
  • Hash: 計算されたハッシュ値(16進数)
  • Path: 対象ファイルのフルパス

アルゴリズムの指定

SHA256以外のアルゴリズムを使いたい場合は、-Algorithm パラメータを使用します。

# MD5を使用
Get-FileHash C:\path\to\file.txt -Algorithm MD5

# SHA1を使用
Get-FileHash C:\path\to\file.txt -Algorithm SHA1

# SHA512を使用
Get-FileHash C:\path\to\file.txt -Algorithm SHA512

対応しているアルゴリズム一覧

アルゴリズムハッシュ長セキュリティレベル用途
SHA256256bit推奨(デフォルト)
SHA512512bit最高高セキュリティ要求
SHA384384bit中程度のセキュリティ
SHA1160bit低(非推奨)互換性のため
MD5128bit極低(非推奨)互換性のため

セキュリティ上の注意:

  • 推奨: SHA256, SHA512
  • 非推奨: SHA1, MD5(脆弱性のため)

パフォーマンスの比較

# 大きなファイルでのパフォーマンステスト
$file = "C:\LargeFile.iso"

# 実行時間を測定
Measure-Command { Get-FileHash $file -Algorithm MD5 }
Measure-Command { Get-FileHash $file -Algorithm SHA1 }
Measure-Command { Get-FileHash $file -Algorithm SHA256 }
Measure-Command { Get-FileHash $file -Algorithm SHA512 }

一般的に、MD5 > SHA1 > SHA256 > SHA512の順で処理時間が長くなりますが、セキュリティとのバランスを考慮してSHA256の使用が推奨されます。

実践的なハッシュ値の活用方法

ファイルダウンロード時の検証

多くのソフトウェア配布サイトでは、ダウンロードファイルのハッシュ値を公開しています。

実際の検証手順

# 1. ダウンロードしたファイルのハッシュ値を計算
$downloadedFile = "C:\Downloads\software.exe"
$calculatedHash = Get-FileHash $downloadedFile -Algorithm SHA256

# 2. 公式サイトで公開されているハッシュ値
$officialHash = "8D969EEF6ECAD3C29A3A629280E686CF0C3F5D5A86AFF3CA12020C923ADC6C92"

# 3. 比較して結果を表示
if ($calculatedHash.Hash -eq $officialHash) {
    Write-Host "✓ ファイルは正常です(改ざんなし)" -ForegroundColor Green
} else {
    Write-Host "✗ ファイルが改ざんされている可能性があります" -ForegroundColor Red
    Write-Host "計算値: $($calculatedHash.Hash)"
    Write-Host "公式値: $officialHash"
}

複数ファイルの一括処理

フォルダ内の全ファイルをチェック

# 基本的な一括処理
Get-ChildItem C:\ImportantData -File | ForEach-Object {
    Get-FileHash $_.FullName -Algorithm SHA256
}

より詳細な情報付きの処理

# ファイル情報も含めた詳細レポート
Get-ChildItem C:\ImportantData -File -Recurse | ForEach-Object {
    $hash = Get-FileHash $_.FullName -Algorithm SHA256
    [PSCustomObject]@{
        FileName = $_.Name
        Path = $_.FullName
        Size = $_.Length
        LastModified = $_.LastWriteTime
        SHA256 = $hash.Hash
    }
} | Format-Table -AutoSize

CSVファイルへの出力と管理

ハッシュ値データベースの作成

# ハッシュ値をCSVで保存
$hashData = Get-ChildItem C:\ImportantData -File -Recurse | ForEach-Object {
    $hash = Get-FileHash $_.FullName -Algorithm SHA256
    [PSCustomObject]@{
        RelativePath = $_.FullName.Replace("C:\ImportantData\", "")
        FileName = $_.Name
        FileSize = $_.Length
        LastModified = $_.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
        SHA256Hash = $hash.Hash
        CheckDate = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
    }
}

# CSVに保存
$hashData | Export-Csv "C:\HashDatabase.csv" -NoTypeInformation -Encoding UTF8

Write-Host "$($hashData.Count) 件のファイルのハッシュ値を保存しました"

保存したハッシュ値との比較

# 以前に保存したハッシュ値と現在の値を比較
$previousHashes = Import-Csv "C:\HashDatabase.csv"
$changedFiles = @()

foreach ($record in $previousHashes) {
    $currentPath = "C:\ImportantData\$($record.RelativePath)"
    
    if (Test-Path $currentPath) {
        $currentHash = Get-FileHash $currentPath -Algorithm SHA256
        
        if ($currentHash.Hash -ne $record.SHA256Hash) {
            $changedFiles += [PSCustomObject]@{
                Path = $currentPath
                FileName = $record.FileName
                PreviousHash = $record.SHA256Hash
                CurrentHash = $currentHash.Hash
                LastModified = $record.LastModified
            }
        }
    } else {
        Write-Host "ファイルが削除されています: $currentPath" -ForegroundColor Yellow
    }
}

if ($changedFiles.Count -gt 0) {
    Write-Host "$($changedFiles.Count) 件のファイルが変更されています:" -ForegroundColor Red
    $changedFiles | Format-Table -AutoSize
} else {
    Write-Host "すべてのファイルに変更はありません" -ForegroundColor Green
}

高度なハッシュ値処理

ストリーミング処理による大容量ファイル対応

# 大容量ファイルのストリーミングハッシュ計算
function Get-StreamingFileHash {
    param(
        [string]$FilePath,
        [string]$Algorithm = "SHA256"
    )
    
    try {
        $hashAlgorithm = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
        $fileStream = [System.IO.File]::OpenRead($FilePath)
        
        $buffer = New-Object byte[] 4096
        $totalBytes = 0
        $fileLength = $fileStream.Length
        
        while (($bytesRead = $fileStream.Read($buffer, 0, $buffer.Length)) -gt 0) {
            $hashAlgorithm.TransformBlock($buffer, 0, $bytesRead, $null, 0) | Out-Null
            $totalBytes += $bytesRead
            
            # 進行状況を表示
            $progress = [math]::Round(($totalBytes / $fileLength) * 100, 1)
            Write-Progress -Activity "ハッシュ計算中" -Status "$progress% 完了" -PercentComplete $progress
        }
        
        $hashAlgorithm.TransformFinalBlock(@(), 0, 0) | Out-Null
        $hash = [BitConverter]::ToString($hashAlgorithm.Hash) -replace '-'
        
        return $hash
    }
    finally {
        if ($fileStream) { $fileStream.Close() }
        if ($hashAlgorithm) { $hashAlgorithm.Dispose() }
        Write-Progress -Activity "ハッシュ計算中" -Completed
    }
}

# 使用例
$hash = Get-StreamingFileHash "C:\VeryLargeFile.zip"
Write-Host "計算されたハッシュ値: $hash"

複数アルゴリズムの同時計算

# 複数のハッシュアルゴリズムで同時に計算
function Get-MultipleFileHash {
    param([string]$FilePath)
    
    $algorithms = @("MD5", "SHA1", "SHA256", "SHA512")
    $results = @{}
    
    foreach ($algorithm in $algorithms) {
        try {
            $hash = Get-FileHash $FilePath -Algorithm $algorithm
            $results[$algorithm] = $hash.Hash
        }
        catch {
            $results[$algorithm] = "エラー: $($_.Exception.Message)"
        }
    }
    
    return [PSCustomObject]$results
}

# 使用例
$multiHash = Get-MultipleFileHash "C:\sample.txt"
$multiHash | Format-List

ネットワーク上のファイルのハッシュ計算

# ネットワーク共有上のファイルのハッシュ計算
function Get-NetworkFileHash {
    param(
        [string]$NetworkPath,
        [string]$Algorithm = "SHA256",
        [System.Management.Automation.PSCredential]$Credential
    )
    
    if ($Credential) {
        # 認証情報を使用してネットワークドライブをマウント
        $tempDrive = "Z:"
        New-PSDrive -Name "Z" -PSProvider FileSystem -Root $NetworkPath -Credential $Credential
    }
    
    try {
        $files = Get-ChildItem $NetworkPath -File
        $results = @()
        
        foreach ($file in $files) {
            $hash = Get-FileHash $file.FullName -Algorithm $Algorithm
            $results += [PSCustomObject]@{
                FileName = $file.Name
                Path = $file.FullName
                Hash = $hash.Hash
                Size = $file.Length
            }
        }
        
        return $results
    }
    finally {
        if ($Credential) {
            Remove-PSDrive -Name "Z" -Force
        }
    }
}

セキュリティとベストプラクティス

ハッシュ値の保存と管理

セキュアな保存方法

# ハッシュ値をデジタル署名付きで保存
function Save-SecureHashDatabase {
    param(
        [string]$DataPath,
        [string]$OutputPath,
        [string]$CertificateThumbprint
    )
    
    # ハッシュ値を計算
    $hashData = Get-ChildItem $DataPath -File -Recurse | ForEach-Object {
        $hash = Get-FileHash $_.FullName -Algorithm SHA256
        [PSCustomObject]@{
            Path = $_.FullName
            Hash = $hash.Hash
            Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
        }
    }
    
    # JSONとして保存
    $jsonData = $hashData | ConvertTo-Json -Depth 3
    $jsonData | Out-File $OutputPath -Encoding UTF8
    
    # デジタル署名を追加(証明書が利用可能な場合)
    if ($CertificateThumbprint) {
        Set-AuthenticodeSignature -FilePath $OutputPath -Certificate (Get-Item "Cert:\CurrentUser\My\$CertificateThumbprint")
    }
}

ログ記録と監査

# ハッシュ値の変更をログに記録
function Start-FileIntegrityMonitoring {
    param(
        [string]$MonitorPath,
        [string]$LogPath = "C:\FileIntegrityLog.txt"
    )
    
    # 初期ハッシュ値を記録
    $baselineHashes = @{}
    Get-ChildItem $MonitorPath -File -Recurse | ForEach-Object {
        $hash = Get-FileHash $_.FullName -Algorithm SHA256
        $baselineHashes[$_.FullName] = $hash.Hash
    }
    
    # 定期的なチェック(例:1時間ごと)
    while ($true) {
        Start-Sleep -Seconds 3600  # 1時間待機
        
        $currentTime = Get-Date
        Get-ChildItem $MonitorPath -File -Recurse | ForEach-Object {
            $currentHash = Get-FileHash $_.FullName -Algorithm SHA256
            
            if ($baselineHashes.ContainsKey($_.FullName)) {
                if ($baselineHashes[$_.FullName] -ne $currentHash.Hash) {
                    $logEntry = "$currentTime : CHANGED - $($_.FullName)"
                    Add-Content -Path $LogPath -Value $logEntry
                    Write-Host "ファイル変更検出: $($_.FullName)" -ForegroundColor Yellow
                    
                    # ベースラインを更新
                    $baselineHashes[$_.FullName] = $currentHash.Hash
                }
            } else {
                # 新しいファイル
                $logEntry = "$currentTime : NEW FILE - $($_.FullName)"
                Add-Content -Path $LogPath -Value $logEntry
                $baselineHashes[$_.FullName] = $currentHash.Hash
            }
        }
    }
}

トラブルシューティングとエラー処理

よくあるエラーとその対処法

ファイルアクセス権限のエラー

# 安全なハッシュ計算(エラーハンドリング付き)
function Get-SafeFileHash {
    param(
        [string]$FilePath,
        [string]$Algorithm = "SHA256"
    )
    
    try {
        # ファイルの存在確認
        if (-not (Test-Path $FilePath)) {
            throw "ファイルが見つかりません: $FilePath"
        }
        
        # アクセス権限の確認
        $acl = Get-Acl $FilePath
        if (-not $acl) {
            throw "ファイルにアクセスできません: $FilePath"
        }
        
        # ハッシュ値を計算
        $hash = Get-FileHash $FilePath -Algorithm $Algorithm -ErrorAction Stop
        
        return [PSCustomObject]@{
            Path = $FilePath
            Algorithm = $Algorithm
            Hash = $hash.Hash
            Status = "成功"
            Error = $null
        }
    }
    catch {
        return [PSCustomObject]@{
            Path = $FilePath
            Algorithm = $Algorithm
            Hash = $null
            Status = "エラー"
            Error = $_.Exception.Message
        }
    }
}

# 使用例
$result = Get-SafeFileHash "C:\ProtectedFile.txt"
if ($result.Status -eq "成功") {
    Write-Host "ハッシュ値: $($result.Hash)"
} else {
    Write-Host "エラー: $($result.Error)" -ForegroundColor Red
}

大容量ファイルでのメモリ不足

# メモリ効率を考慮したハッシュ計算
function Get-MemoryEfficientHash {
    param(
        [string]$FilePath,
        [string]$Algorithm = "SHA256",
        [int]$BufferSize = 1MB
    )
    
    try {
        $hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
        $stream = [System.IO.File]::OpenRead($FilePath)
        $buffer = New-Object byte[] $BufferSize
        
        $totalRead = 0
        $fileSize = $stream.Length
        
        while (($bytesRead = $stream.Read($buffer, 0, $buffer.Length)) -gt 0) {
            $hasher.TransformBlock($buffer, 0, $bytesRead, $null, 0) | Out-Null
            $totalRead += $bytesRead
            
            # 進行状況の表示とメモリ管理
            if ($totalRead % (10 * $BufferSize) -eq 0) {
                $percent = [math]::Round(($totalRead / $fileSize) * 100, 1)
                Write-Progress -Activity "ハッシュ計算" -PercentComplete $percent
                [System.GC]::Collect()  # ガベージコレクションを強制実行
            }
        }
        
        $hasher.TransformFinalBlock(@(), 0, 0) | Out-Null
        $hashBytes = $hasher.Hash
        $hashString = [BitConverter]::ToString($hashBytes) -replace '-'
        
        return $hashString
    }
    finally {
        if ($stream) { $stream.Close() }
        if ($hasher) { $hasher.Dispose() }
        Write-Progress -Activity "ハッシュ計算" -Completed
        [System.GC]::Collect()
    }
}

まとめ

Windows PowerShellを使ったハッシュ値の計算と活用について、包括的に解説しました。

主要なポイント

基本操作:

  • Get-FileHash で簡単にハッシュ値を計算
  • SHA256, SHA512, MD5 など用途に応じてアルゴリズムを選択
  • フォルダ単位での一括計算やCSV出力も可能

実用的な活用:

  • ファイルダウンロード時の整合性確認
  • 改ざん検知とセキュリティ監視
  • データバックアップの検証
  • 重複ファイルの検出

高度な機能:

  • 大容量ファイルのストリーミング処理
  • 複数アルゴリズムでの同時計算
  • ネットワークファイルのハッシュ計算
  • セキュアな保存と監査ログ

セキュリティの観点

推奨事項:

  • SHA256以上のアルゴリズムを使用
  • ハッシュ値の定期的な確認
  • 変更の記録と追跡
  • セキュアな保存方法の採用

注意事項:

  • MD5やSHA1は脆弱性があるため避ける
  • ハッシュ値自体の改ざんにも注意
  • 重要なデータは複数の手法で検証

コメント

タイトルとURLをコピーしました