PowerShellを利用したファイルの暗号化と復号化という問いには、小さな検証ファイルで暗号化と復号を往復させてから本番ファイルへ進み、証明書の拇印を作業記録へ残すという方法で答えます。Protect-CmsMessageは受信者の公開鍵でCMSメッセージを作り、Unprotect-CmsMessageには対応する秘密鍵が必要になる。パスワード暗号化とは鍵管理の考え方が異なる。この記事では拇印、Subject、有効期限、Enhanced Key Usageを見て、Document Encryption用途の受信者証明書を一意にするを判断軸にし、実行前の確認、記事固有のコード、合否判定、戻し方を一続きで示します。
EFSやBitLockerのようなボリューム保護ではなく、受信者を指定してファイル内容を渡す用途を対象にする。完了は「暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できる」と定義します。対象が取れない場合は「証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する」として切り分け、推測で成功扱いにしません。
CMSが守れる範囲を先に理解する
小さな検証ファイルで暗号化と復号を往復させてから本番ファイルへ進み、証明書の拇印を作業記録へ残す。CMSで行うファイル暗号化と復号ではこの進め方により、操作したという事実ではなく、期待する状態へ到達したかでタイトルの問いへ答えられます。EFSやBitLockerのようなボリューム保護ではなく、受信者を指定してファイル内容を渡す用途を対象にする。
CMSが守れる範囲を先に理解するの合格条件は、暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できることです。作業時刻、実行ユーザー、端末名を添え、判断に使った値が後から追える形にします。
Document Encryption証明書を選別する
Document Encryption証明書を選別するは変更前の基準点です。拇印、Subject、有効期限、Enhanced Key Usageを見て、Document Encryption用途の受信者証明書を一意にするを出力に含め、取得時刻と一緒に保存します。値だけを切り取ると別対象との比較になるため、識別列を省きません。
$expectedThumbprint = 'PUT_APPROVED_CERTIFICATE_THUMBPRINT_HERE'
$expectedIssuer = 'PUT_APPROVED_CERTIFICATE_ISSUER_HERE'
$normalizedThumbprint = $expectedThumbprint.Replace(' ','').ToUpperInvariant()
if ($normalizedThumbprint -notmatch '^[0-9A-F]{40,64}$' -or
$expectedIssuer -eq 'PUT_APPROVED_CERTIFICATE_ISSUER_HERE') {
throw '承認済み証明書の拇印へ置き換えてください。'
}
$now = Get-Date
$candidates = @(Get-ChildItem Cert:\CurrentUser\My -DocumentEncryptionCert | Where-Object {
$_.Thumbprint.Replace(' ','').ToUpperInvariant() -eq $normalizedThumbprint -and
$_.Issuer -eq $expectedIssuer -and
$_.NotBefore -le $now -and $_.NotAfter -gt $now
})
if ($candidates.Count -ne 1) { throw "証明書を一意にできません: $($candidates.Count)件" }
$recipient = $candidates[0]
$documentEncryptionOid = '1.3.6.1.4.1.311.80.1'
if ($recipient.EnhancedKeyUsageList.ObjectId.Value -notcontains $documentEncryptionOid) {
throw 'Document Encryption用途ではありません。'
}
if (-not $recipient.HasPrivateKey) { throw 'このアカウントで往復試験できる秘密鍵がありません。' }
$recipient | Select-Object Thumbprint, Subject, Issuer, NotBefore, NotAfter, HasPrivateKey,
@{n='EKU';e={$_.EnhancedKeyUsageList.FriendlyName -join ', '}}
Protect-CmsMessageは受信者の公開鍵でCMSメッセージを作り、Unprotect-CmsMessageには対応する秘密鍵が必要になる。パスワード暗号化とは鍵管理の考え方が異なる。出力が多い場合も最初から無理に一件へ絞らず、候補数と除外理由を残してから対象を決めます。
受信者を固定して暗号文を作る
受信者を固定して暗号文を作るでは、小さな検証ファイルで暗号化と復号を往復させてから本番ファイルへ進み、証明書の拇印を作業記録へ残す。CMSで行うファイル暗号化と復号の例中にある名前、パス、ID、時刻はサンプルなので、そのまま本番へ貼らず、直前の読み取り結果から承認値を入れます。
$inputPath = 'C:\Ops\report.txt'
$cmsPath = 'C:\Ops\report.txt.cms'
$roundTripPath = 'C:\Ops\report.roundtrip.txt'
foreach ($path in @($cmsPath, $roundTripPath)) {
if (Test-Path -LiteralPath $path) { throw "既存ファイルを上書きしません: $path" }
}
$sourceBytes = [System.IO.File]::ReadAllBytes($inputPath)
$sourceHash = (Get-FileHash -LiteralPath $inputPath -Algorithm SHA256).Hash.ToLowerInvariant()
$payload = [Convert]::ToBase64String($sourceBytes)
Protect-CmsMessage -To $recipient -Content $payload -OutFile $cmsPath -ErrorAction Stop
if (-not (Test-Path -LiteralPath $cmsPath -PathType Leaf)) { throw '暗号文が作成されませんでした。' }
秘密鍵を失った暗号文は復号できない。期限切れ前の更新、秘密鍵バックアップ、失効時の扱いを決めずに原本を消さない。CMSで行うファイル暗号化と復号でプレビュー対応コマンドを使える場合はWhatIfを先に実行し、非対応の操作は対象一覧と引数を画面へ出して人が承認してから一度だけ実行します。
復号テストで秘密鍵の有無を確かめる
復号テストで秘密鍵の有無を確かめるでは同じ対象を別経路でもう一度読みます。判定したいのは「コマンドが終了したか」ではなく、暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できるかどうかです。
$decodedPayload = (Unprotect-CmsMessage -Path $cmsPath -ErrorAction Stop | Out-String).Trim()
$roundTripBytes = [Convert]::FromBase64String($decodedPayload)
[System.IO.File]::WriteAllBytes($roundTripPath, $roundTripBytes)
$roundTripHash = (Get-FileHash -LiteralPath $roundTripPath -Algorithm SHA256).Hash.ToLowerInvariant()
if ($roundTripHash -ne $sourceHash) { throw '復号後のSHA256が原本と一致しません。' }
[pscustomobject]@{
CertificateThumbprint=$recipient.Thumbprint
SourceSha256=$sourceHash; RoundTripSha256=$roundTripHash
CmsPath=$cmsPath; RoundTripPath=$roundTripPath; ExactMatch=$true
}
証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する。CMSで行うファイル暗号化と復号の期待値と実測値が一致しないときは追加変更を重ねず、対象識別、権限、ポリシー、時間差の順で原因を分けます。
証明書が0件または複数件だった場合
秘密鍵を失った暗号文は復号できない。期限切れ前の更新、秘密鍵バックアップ、失効時の扱いを決めずに原本を消さない。証明書が0件または複数件だった場合に該当したら、警告を消して継続するのではなく、どの条件で止まったかを記録します。
証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する。CMSで行うファイル暗号化と復号ではエラー本文、FullyQualifiedErrorId、対象ID、直前に成功した段階を残すと、別担当者が安全な地点から調査できます。
平文と秘密鍵の保管を分ける
暗号化前の原本は承認された保管場所で保持し、復号試験とバックアップ確認が終わるまで置き換えない。復旧操作にも同じ識別条件を使い、名前が似た別対象へ戻し処理を適用しません。
- CMSで行うファイル暗号化と復号の変更前値と取得時刻
- 復旧対象: 拇印、Subject、有効期限、Enhanced Key Usageを見て、Document Encryption用途の受信者証明書を一意にする
- 復旧後の判定: 暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できる
- 再実行を止める条件: 秘密鍵を失った暗号文は復号できない。期限切れ前の更新、秘密鍵バックアップ、失効時の扱いを決めずに原本を消さない
証明書更新をまたぐ運用
定期処理では証明書の拇印を明示し、有効期限とHasPrivateKeyを事前検査する。先頭1件を無条件採用しない。CMSで行うファイル暗号化と復号を繰り返す場合は、正常、対象なし、要承認、失敗を異なる終了状態として記録し、前回値との比較だけで異常を決めません。
| 証明書更新をまたぐ運用の識別軸 | 拇印、Subject、有効期限、Enhanced Key Usageを見て、Document Encryption用途の受信者証明書を一意にする |
| 採用する実測 | 暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できる |
| 0件時の扱い | 証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する |
| 保留にする兆候 | 秘密鍵を失った暗号文は復号できない。期限切れ前の更新、秘密鍵バックアップ、失効時の扱いを決めずに原本を消さない |
よくある疑問:別PCで開ける条件
Q. CMSで行うファイル暗号化と復号は管理者PowerShellなら必ず成功しますか。A. いいえ。Protect-CmsMessageは受信者の公開鍵でCMSメッセージを作り、Unprotect-CmsMessageには対応する秘密鍵が必要になる。パスワード暗号化とは鍵管理の考え方が異なる。管理者権限は対象や製品仕様の不一致を解消しません。
Q. 0件を正常終了にできますか。A. 証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する。要件上0件が許される場合だけ正常とし、検出できなかった状態とは分けて報告します。
CMSで行うファイル暗号化と復号の実行記録には、開始前の対象候補、採用した識別値、実行したコード、終了後の実測、除外した候補と理由を同じ作業番号で残します。特に「拇印、Subject、有効期限、Enhanced Key Usageを見て、Document Encryption用途の受信者証明書を一意にする」を省くと、後日の再確認で別対象の値を比較するおそれがあります。画面コピーだけでなく、日時と端末名を含む構造化した出力も保存します。
PowerShellを利用したファイルの暗号化と復号化を定期手順へ組み込む場合も、初回は対話的に候補を確認します。正常時は「暗号文に平文が露出せず、許可された秘密鍵を持つアカウントだけが内容を復号でき、元内容との一致を確認できる」、判定不能時は「証明書が見つからないときは自己署名証明書を場当たり的に作らず、組織のPKIまたは受信者へ正しい証明書を依頼する」、中止時は「秘密鍵を失った暗号文は復号できない。期限切れ前の更新、秘密鍵バックアップ、失効時の扱いを決めずに原本を消さない」をそれぞれ別の結果として扱います。これにより、0件や例外を都合よく成功へ丸めず、次の担当者が同じ対象と条件で追試できます。
修正後コードの合格条件:ローカル往復試験では承認済み拇印と発行者が完全一致する有効なDocument Encryption証明書を一件に固定し、秘密鍵があることを必須にします。原本バイト列をBase64化して暗号化し、復号後に同じバイトへ戻してSHA256が一致するまで原本を削除しません。
公式情報・参考資料
CMSで行うファイル暗号化と復号で使うコマンド名、引数、対応環境は次のMicrosoft一次資料で確認しました。記事の確認日は2026年7月17日です。OSやモジュール更新後は、実行端末のGet-Helpと併せて再確認してください。

コメント