バッチファイルをPowerShellスクリプトから実行する方法

バッチファイルをPowerShellスクリプトから実行する方法という問いには、承認済みカタログで配置フォルダー全体をDetailed検証し、StatusとSignature.Statusの双方がValidのときだけcmd.exeから実行するという方法で答えます。cmdやbat自体はAuthenticode署名の一般的な対象ではない。Test-FileCatalogはカタログに記録されたファイルハッシュとカタログ署名を検証できる。この記事では承認フォルダー、CatalogFilePath、カタログ署名者、含まれる全ファイルの相対パスとハッシュを固定するを判断軸にし、実行前の確認、記事固有のコード、合否判定、戻し方を一続きで示します。

単にStart-Processする記事ではなく、署名カタログ不正時に必ず止める実行ゲートを実装する。完了は「カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られる」と定義します。対象が取れない場合は「カタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない」として切り分け、推測で成功扱いにしません。

目次

cmd本体だけの署名確認では不十分

承認済みカタログで配置フォルダー全体をDetailed検証し、StatusとSignature.Statusの双方がValidのときだけcmd.exeから実行する。検証済みバッチファイルの実行ではこの進め方により、操作したという事実ではなく、期待する状態へ到達したかでタイトルの問いへ答えられます。単にStart-Processする記事ではなく、署名カタログ不正時に必ず止める実行ゲートを実装する。

cmd本体だけの署名確認では不十分の合格条件は、カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られることです。作業時刻、実行ユーザー、端末名を添え、判断に使った値が後から追える形にします。

承認済みカタログと配置フォルダーを用意

承認済みカタログと配置フォルダーを用意は変更前の基準点です。承認フォルダー、CatalogFilePath、カタログ署名者、含まれる全ファイルの相対パスとハッシュを固定するを出力に含め、取得時刻と一緒に保存します。値だけを切り取ると別対象との比較になるため、識別列を省きません。

$folder = 'C:\Ops\ApprovedBatch'
$catalogPath = 'C:\Ops\ApprovedBatch.cat'
$batchPath = Join-Path $folder 'job.cmd'
$resultDirectory = 'C:\Ops\BatchResults'
$expectedLog = Join-Path $resultDirectory ("job-result-{0}.json" -f [guid]::NewGuid())
$expectedCatalogSha256 = 'PUT_APPROVED_CATALOG_SHA256_HERE'
$expectedSignerThumbprint = 'PUT_APPROVED_SIGNER_THUMBPRINT_HERE'
foreach ($path in @($folder, $catalogPath, $batchPath, $resultDirectory)) {
  if (-not (Test-Path -LiteralPath $path)) { throw "必要パスがありません: $path" }
}
if (Test-Path -LiteralPath $expectedLog) { throw "結果ログを上書きしません: $expectedLog" }
if ($expectedCatalogSha256 -notmatch '^[0-9A-Fa-f]{64}$' -or
  $expectedSignerThumbprint.Replace(' ','') -notmatch '^[0-9A-Fa-f]{40}$') {
  throw '承認済みカタログSHA256と署名者拇印へ置き換えてください。'
}

cmdやbat自体はAuthenticode署名の一般的な対象ではない。Test-FileCatalogはカタログに記録されたファイルハッシュとカタログ署名を検証できる。出力が多い場合も最初から無理に一件へ絞らず、候補数と除外理由を残してから対象を決めます。

Test-FileCatalogで全ファイルを検証

Test-FileCatalogで全ファイルを検証では、承認済みカタログで配置フォルダー全体をDetailed検証し、StatusとSignature.Statusの双方がValidのときだけcmd.exeから実行する。検証済みバッチファイルの実行の例中にある名前、パス、ID、時刻はサンプルなので、そのまま本番へ貼らず、直前の読み取り結果から承認値を入れます。

$actualCatalogHash = (Get-FileHash -LiteralPath $catalogPath -Algorithm SHA256).Hash
if ($actualCatalogHash -ne $expectedCatalogSha256.ToUpperInvariant()) {
  throw 'カタログファイルのSHA256が承認値と一致しません。'
}
$catalog = Test-FileCatalog -CatalogFilePath $catalogPath -Path $folder -Detailed
$signature = Get-AuthenticodeSignature -FilePath $catalogPath
$actualSigner = if ($null -ne $signature.SignerCertificate) {
  $signature.SignerCertificate.Thumbprint.Replace(' ','').ToUpperInvariant()
} else { $null }
if ($catalog.Status -ne 'Valid' -or $signature.Status -ne 'Valid' -or
  $null -eq $actualSigner -or
  $actualSigner -ne $expectedSignerThumbprint.Replace(' ','').ToUpperInvariant()) {
  throw '配置内容、カタログ署名、または承認署名者が一致しません。'
}
$approvalToken = "RUN job.cmd $($actualCatalogHash.Substring(0,12))"
if ((Read-Host "実行する場合は $approvalToken を入力") -ne $approvalToken) {
  throw 'バッチ実行は承認されませんでした。'
}
# job.cmdは第1引数(%~1)へ結果JSONを新規作成する契約とする。
$cmdLine = '""{0}" "{1}""' -f $batchPath, $expectedLog
$cmdArgument = @('/d','/s','/c',$cmdLine)
$process = Start-Process -FilePath 'cmd.exe' -ArgumentList $cmdArgument -Wait -PassThru -NoNewWindow
if ($process.ExitCode -ne 0) { throw "Batch failed: $($process.ExitCode)" }
if (-not (Test-Path -LiteralPath $expectedLog -PathType Leaf)) {
  throw "期待成果物がありません: $expectedLog"
}

ValidationFailed、UnknownError、SignatureがValid以外ならthrowして停止する。信頼できない場所から依存EXEを読み込ませない。検証済みバッチファイルの実行でプレビュー対応コマンドを使える場合はWhatIfを先に実行し、非対応の操作は対象一覧と引数を画面へ出して人が承認してから一度だけ実行します。

StatusとSignatureがValidでなければ停止

StatusとSignatureがValidでなければ停止では同じ対象を別経路でもう一度読みます。判定したいのは「コマンドが終了したか」ではなく、カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られるかどうかです。

$afterCatalog = Test-FileCatalog -CatalogFilePath $catalogPath -Path $folder -Detailed
$afterHash = (Get-FileHash -LiteralPath $catalogPath -Algorithm SHA256).Hash
if ($afterCatalog.Status -ne 'Valid' -or $afterHash -ne $actualCatalogHash) {
  throw '実行後にカタログ対象またはカタログ自身が変化しました。'
}
[pscustomobject]@{
  CatalogStatus=$afterCatalog.Status; CatalogSha256=$afterHash
  SignerThumbprint=$actualSigner; Batch=$batchPath
  ExitCode=$process.ExitCode; ResultLog=$expectedLog
  ResultLogSha256=(Get-FileHash -LiteralPath $expectedLog -Algorithm SHA256).Hash
}

カタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない。検証済みバッチファイルの実行の期待値と実測値が一致しないときは追加変更を重ねず、対象識別、権限、ポリシー、時間差の順で原因を分けます。

cmd.exe /d /cで一度だけ実行

ValidationFailed、UnknownError、SignatureがValid以外ならthrowして停止する。信頼できない場所から依存EXEを読み込ませない。cmd.exe /d /cで一度だけ実行に該当したら、警告を消して継続するのではなく、どの条件で止まったかを記録します。

カタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない。検証済みバッチファイルの実行ではエラー本文、FullyQualifiedErrorId、対象ID、直前に成功した段階を残すと、別担当者が安全な地点から調査できます。

ExitCodeと生成ログを確認

バッチが変更する内容は処理ごとの復旧手順が必要。実行前スナップショットとバックアップがない処理は起動しない。復旧操作にも同じ識別条件を使い、名前が似た別対象へ戻し処理を適用しません。

  • 検証済みバッチファイルの実行の変更前値と取得時刻
  • 復旧対象: 承認フォルダー、CatalogFilePath、カタログ署名者、含まれる全ファイルの相対パスとハッシュを固定する
  • 復旧後の判定: カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られる
  • 再実行を止める条件: ValidationFailed、UnknownError、SignatureがValid以外ならthrowして停止する。信頼できない場所から依存EXEを読み込ませない

カタログ不一致後に続行しない

カタログ、配置物、実行ログのハッシュを同じ変更記録へ保存し、実行後にフォルダーが改変されていないか再検証する。検証済みバッチファイルの実行を繰り返す場合は、正常、対象なし、要承認、失敗を異なる終了状態として記録し、前回値との比較だけで異常を決めません。

カタログ不一致後に続行しないの識別軸承認フォルダー、CatalogFilePath、カタログ署名者、含まれる全ファイルの相対パスとハッシュを固定する
採用する実測カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られる
0件時の扱いカタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない
保留にする兆候ValidationFailed、UnknownError、SignatureがValid以外ならthrowして停止する。信頼できない場所から依存EXEを読み込ませない

質問:単体ハッシュだけでよいか

Q. 検証済みバッチファイルの実行は管理者PowerShellなら必ず成功しますか。A. いいえ。cmdやbat自体はAuthenticode署名の一般的な対象ではない。Test-FileCatalogはカタログに記録されたファイルハッシュとカタログ署名を検証できる。管理者権限は対象や製品仕様の不一致を解消しません。

Q. 0件を正常終了にできますか。A. カタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない。要件上0件が許される場合だけ正常とし、検出できなかった状態とは分けて報告します。

検証済みバッチファイルの実行の実行記録には、開始前の対象候補、採用した識別値、実行したコード、終了後の実測、除外した候補と理由を同じ作業番号で残します。特に「承認フォルダー、CatalogFilePath、カタログ署名者、含まれる全ファイルの相対パスとハッシュを固定する」を省くと、後日の再確認で別対象の値を比較するおそれがあります。画面コピーだけでなく、日時と端末名を含む構造化した出力も保存します。

バッチファイルをPowerShellスクリプトから実行する方法を定期手順へ組み込む場合も、初回は対話的に候補を確認します。正常時は「カタログ検証が完全にValidで、バッチの終了コードが定義済み成功値となり、期待ログまたは成果物が得られる」、判定不能時は「カタログにないファイル、欠落ファイル、署名チェーン不明は実行不可とし、警告扱いで先へ進めない」、中止時は「ValidationFailed、UnknownError、SignatureがValid以外ならthrowして停止する。信頼できない場所から依存EXEを読み込ませない」をそれぞれ別の結果として扱います。これにより、0件や例外を都合よく成功へ丸めず、次の担当者が同じ対象と条件で追試できます。

修正後コードの合格条件:配置フォルダー全体のカタログ整合性に加え、カタログファイル自体の承認SHA256と署名者拇印を固定します。三条件が全て一致し、バッチ名とカタログハッシュを含むトークンを入力した場合だけcmd.exeを待機実行し、終了コードと期待ログを完了条件にします。

公式情報・参考資料

検証済みバッチファイルの実行で使うコマンド名、引数、対応環境は次のMicrosoft一次資料で確認しました。記事の確認日は2026年7月17日です。OSやモジュール更新後は、実行端末のGet-Helpと併せて再確認してください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次