テスト環境で安全に使う!PowerShell自己署名証明書の作成とスクリプト署名手順

ポコぺん

「PowerShellで自動化スクリプトを作ったのに、実行ポリシーの制限に引っかかって動かない……」 そんな経験はありませんか?

セキュリティを高めるためにスクリプトの実行を制限することは大切ですが、開発やテストのたびにエラーが出るのはストレスが溜まりますよね。
だからといって、全体のセキュリティ設定を一番緩い状態(Bypassなど)にするのは、ウイルス感染などのリスクが高まり大変危険です。

そこで活用したいのが「自己署名証明書」です。 自分で作成したデジタル証明書をスクリプトに付与(署名)することで、Windowsの安全性を保ったまま、自作スクリプトをスムーズに実行できるようになります。

この記事では、PowerShellを使った自己署名証明書の作成方法から、スクリプトへの署名手順、さらには社内環境で一括配布・自動運用するテクニックまでを分かりやすく解説します。

この記事を読めば、セキュリティのエラーに悩まされることなく、安全で効率的なスクリプト開発環境が手に入りますよ!

この記事を読んでほしい人

  • PowerShellスクリプトの実行ポリシー制限(ExecutionPolicy)で困っている方
  • テスト環境や社内環境で、安全にスクリプトを実行したいシステム管理者
  • 自己署名証明書(オレオレ証明書)の具体的な作成・適用手順を知りたい開発者
はじめに

なぜPowerShellスクリプトに署名が必要なのか?

Windowsの強力な管理ツールであるPowerShellですが、自作したスクリプト(.ps1ファイル)をいざ実行しようとすると、エラーが表示されて動かないことがあります。
この現象の背景には、Windowsが標準で備えている「実行ポリシー(ExecutionPolicy)」というセキュリティ機能が関係しています。

Windowsでは、悪意のあるスクリプト(ウイルスやマルウェアなど)が勝手に実行されないよう、初期状態ではスクリプトの実行が厳しく制限されています。これが「実行ポリシーの壁」です。

このエラーを回避するために、ネット上の解説記事などでは「実行ポリシーを BypassUnrestricted(制限なし)に変更すれば動く」と紹介されているケースが多々あります。
しかし、実務においてこの設定変更を行うのは非常に危険です。

なぜなら、実行ポリシーを完全に緩めてしまうと、自分が作った安全なスクリプトだけでなく、メールの添付ファイルや不正なサイトからダウンロードされた「悪意のあるスクリプト」までシステム上で自由に動かせる状態になってしまうからです。

セキュリティの安全性を最高レベルに保ったまま、自作スクリプトだけを例外として実行させるための仕組みが「デジタル署名(コード署名)」です。

テスト環境や社内環境においては、認証機関から高額な証明書を購入しなくても、自分で作成した「自己署名証明書」を利用することで安全な環境を構築できます。

自己署名証明書を使ってスクリプトに署名を行うことには、以下のような大きなメリットがあります。

  • 実行ポリシーを「AllSigned」に設定できる
    「信頼された署名があるスクリプトのみ実行を許可する」という非常に安全なポリシー(AllSigned)を適用したまま、自作スクリプトを動かせます。
  • スクリプトの改ざんを検知できる
    一度署名したスクリプトは、1文字でも内容が書き換えられると「署名が無効」と判断され、実行がブロックされます。
    これにより、意図しないコードの書き換えやマルウェアによる改ざんを即座に検知できます。
  • 「身元の確かなスクリプト」として扱える
    OSに対して「このスクリプトは自分が作成し、安全を保証したものだ」と認識させることができるため、実行時の警告ポップアップを減らし、スムーズな運用が可能になります。

利便性のためにセキュリティを犠牲にするのではなく、「安全に、かつ確実にスクリプトを動かす」ために、コード署名は欠かせないプロセスなのです。

ステップ1

PowerShellで自己署名証明書を作成する方法

それでは、実際にスクリプト署名に使う「自己署名証明書」を作っていきましょう。
Windowsに標準搭載されているPowerShellを使えば、専用のコマンドを入力するだけで簡単に作成できます。

まずは、管理者権限でPowerShellを起動します(スタートボタンを右クリックし、「ターミナル(管理者)」または「PowerShell(管理者)」を選択)。
起動したら、以下のコマンドをコピー&ペーストして実行してください。

PowerShell

# コード署名用の自己署名証明書を作成する
$cert = New-SelfSignedCertificate `
	-Type CodeSigningCert `
	-Subject "CN=PowerShellLocalSigning" `
	-CertStoreLocation "Cert:\CurrentUser\My" `
	-NotAfter (Get-Date).AddYears(5)

【コマンドの解説】

  • -Type CodeSigningCert
    これが最重要です。一般的なWebサイト用(SSL/TLS)ではなく、「プログラムやスクリプトに署名するための証明書」として作成します。
  • -Subject "CN=PowerShellLocalSigning"
    証明書の名前(発行先)です。分かりやすい名前を自由につけて構いません。
  • -CertStoreLocation "Cert:\CurrentUser\My"
    現在のユーザーの「個人」証明書ストアに保存します。
  • -NotAfter (Get-Date).AddYears(5)
    証明書の有効期限を「5年間」に設定しています(指定しない場合は通常1年になります)。

コマンドを実行すると、作成された証明書の「Thumbprint」や「Subject」が画面に表示されます。
これで証明書の「素」が完成しました。

証明書は作成しただけでは使えません。
なぜなら、自分で勝手に作った証明書(自己署名証明書)は、Windowsから見るとまだ「身元のわからない怪しい証明書」だからです。

この証明書をシステムに信頼させるために、以下の2つの場所(証明書ストア)へ登録(コピー)する必要があります。

  1. 「信頼されたルート証明機関」:この証明書自体が安全であることをOSに認めさせるため
  2. 「信頼された発行元」:この証明書で署名されたスクリプトの実行を自動で許可するため

こちらも、PowerShellコマンドを使えば一瞬で配置が完了します。
先ほど作成した $cert 変数(証明書データ)が残った状態で、続けて以下の2つのコマンドを実行してください。

PowerShell

# 1. 「信頼されたルート証明機関」にコピー
Copy-Item -Path $cert.PSPath -Destination "Cert:\CurrentUser\Root"

# 2. 「信頼された発行元」にコピー
Copy-Item -Path $cert.PSPath -Destination "Cert:\CurrentUser\TrustedPublisher"

💡 GUI(画面)で確認したい場合
キーボードの Win + R を押し、certmgr.msc と入力してエンターを押すと、Windowsの証明書管理画面が開きます。「個人」「信頼されたルート証明機関」「信頼された発行元」のそれぞれの中に、先ほど作った「PowerShellLocalSigning」という名前の証明書が入っていれば成功です。

これで、あなたのPCは「自分が作った証明書を完全に信頼する状態」になりました。次はいよいよ、この証明書を使ってスクリプトに署名を施していきます!

ステップ2

作成した証明書でスクリプトに署名する手順

証明書の準備ができたら、いよいよ自作のPowerShellスクリプト(.ps1)にデジタル署名を付与してみましょう。
ここでは、テスト用としてデスクトップに myscript.ps1 というスクリプトファイルがある前提で進めます。

スクリプトに署名をするには、まず先ほど作成した証明書をPowerShell上で呼び出し、変数に格納する必要があります。その後、Set-AuthenticodeSignature コマンドを使って署名を行います。
管理者権限のPowerShellで、以下のコマンドを順番に実行してください。

PowerShell

# 1. 署名に使用する証明書を取得して変数に格納する
$cert = Get-ChildItem -Path Cert:\CurrentUser\My '
        | Where-Object { $_.Subject -match "PowerShellLocalSigning" } '
        | Select-Object -First 1

# 2. スクリプトファイルに署名を付与する
Set-AuthenticodeSignature -FilePath "$HOME\Desktop\myscript.ps1" -Certificate $cert

コマンドを実行し、画面に Status「Valid(有効)」 と表示されれば署名は無事に成功です!

🔍 署名されたスクリプトの中身はどうなる?
署名が完了したスクリプトファイルをメモ帳などで開いてみてください。
あなたが書いたコードの末尾に、# SIG # Begin signature block から始まる、暗号化された大量のテキスト行が自動的に追加されているはずです。
これがデジタル署名の本体です。

本当に正しく署名されているか、またその署名がシステムに信頼されているかを検証するには、Get-AuthenticodeSignature コマンドを使用します。
以下のコマンドを実行してみましょう。

PowerShell

# スクリプトの署名状態を確認する
Get-AuthenticodeSignature -FilePath "$HOME\Desktop\myscript.ps1" | Format-List

実行結果の StatusStatusMessage を確認してください。

  • Status : Valid と表示されていれば、署名は正常で、かつシステムから信頼されています。
  • もし UnknownError などが表示される場合は、【ステップ1】の「信頼されたルート証明機関」や「信頼された発行元」への証明書のコピーが漏れている可能性があります。

署名の効果を実感するために、PCの実行ポリシーを一時的に最高レベルの「信頼された署名付きしか動かさない(AllSigned)」に変更して、スクリプトを動かしてみましょう。

PowerShell

# 1. 実行ポリシーを一時的に「AllSigned」に変更
Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope Process

# 2. 署名したスクリプトを実行
&$HOME\Desktop\myscript.ps1

実行ポリシーが AllSigned であるにもかかわらず、エラーが出ずにスクリプトが実行できれば、ここまでの設定はすべて完璧です!

署名付きスクリプトをグループポリシー(GPO)で一括配布・実行する方法

自分のPC(ローカル環境)だけでスクリプトを動かすなら、ここまでの手順で十分です。
しかし、社内の複数のサーバーや数百台のクライアントPCでスクリプトを実行したい場合、1台ずつ手作業で証明書を登録していくのは現実的ではありません。
Active Directory環境であれば、グループポリシー(GPO)を使って、作成した証明書と実行ポリシーの設定を一括で安全にデプロイ(配布)できます。

GPOで一括配布を行うためには、まず【ステップ1】で作った自己署名証明書を、他のPCに配布できる形式(.cer ファイル)としてエクスポート(書き出し)する必要があります。

1. 証明書のエクスポート(管理者PCでの作業)

PowerShellを開き、以下のコマンドで証明書ファイルを出力します。

PowerShell

# 証明書をデスクトップに「PowerShellLocalSigning.cer」として書き出す
$cert = Get-ChildItem -Path Cert:\CurrentUser\My `
        | Where-Object { $_.Subject -match "PowerShellLocalSigning" }

Export-Certificate -Cert $cert -FilePath "$HOME\Desktop\PowerShellLocalSigning.cer"

2. GPOでの証明書一括配布設定(ドメインコントローラーでの作業)

書き出した .cer ファイルをドメインコントローラーに持って行き、グループポリシー管理エディターを開きます。
対象のGPO(例:全社PC用ポリシーなど)を編集し、以下の2つの場所に先ほどの .cer ファイルをインポートします。

  • 「信頼されたルート証明機関」への配置 コンピューターの構成ポリシーWindows の設定セキュリティの設定公開キーのポリシー信頼されたルート証明機関 を右クリックし、「インポート」から .cer ファイルを選択します。
  • 「信頼された発行元」への配置 同じく 公開キーのポリシー の中にある 信頼された発行元 にも、全く同じ .cer ファイルをインポートします。

これで、ドメインに参加しているすべてのPCが、あなたの作った自己署名証明書を自動的に「安全なもの」として信頼するようになります。

証明書を配るのと同時に、クライアントPCのPowerShell実行ポリシーもGPOで一括制御しておきましょう。
これにより、ユーザーが勝手に設定を変更するのを防ぎ、社内全体のセキュリティを統一できます。

GPOで実行ポリシーを「AllSigned」に強制する手順

  1. グループポリシー管理エディターで以下を開きます。
    コンピューターの構成ポリシー管理用テンプレートWindows コンポーネントWindows PowerShell
  2. 「スクリプトの実行を有効にする」 をダブルクリックして「有効」にします。
  3. 実行ポリシーのドロップダウンリストから 「信頼されたスクリプトのみ許可(AllSigned)」 を選択して適用します。

この一連のGPO設定がクライアントPCに適用(gpupdate /force などで反映)されると、以下の状態が自動的に完成します。

  • クライアントPCは「署名がないスクリプト」を一切実行しない(安全確保)。
  • 管理者があなたの自己署名証明書で署名したスクリプト(.ps1)だけは、何のエラーも警告もなく、裏側でスッと実行される。

社内PCのメンテナンスや、ログオン時の自動化処理を安全に行いたいシステム管理者にとって、このGPO連携は必須のテクニックです。

管理者必見!署名運用を自動化するタスクスケジューラ活用術

スクリプト署名は非常に安全な仕組みですが、一つだけ運用上の弱点があります。
それは、「スクリプトを1文字でも修正したら、再署名(Set-AuthenticodeSignatureの再実行)が必要になる」という点です。

開発やメンテナンスのたびに、手動でコマンドを叩いて署名し直すのは面倒ですし、署名を忘れて「動かない!」と慌てる原因にもなります。
そこで、Windows標準のタスクスケジューラと「自動署名スクリプト」を組み合わせ、運用の手間を自動化してしまいましょう。

おすすめの方法は、「特定のフォルダ(例:共有フォルダや開発用フォルダ)の中にあるスクリプトを定期的にチェックし、未署名または更新されたファイルがあれば自動で署名する」という仕組みです。
まずは、自動署名を行うための「親スクリプト(AutoSigner.ps1)」を作成します。

PowerShell

# AutoSigner.ps1(自動署名スクリプトの例)
$targetFolder = "C:\ScriptManagement\Scripts" # 監視対象のフォルダ
$certName = "PowerShellLocalSigning"          # 使用する証明書名

# 署名に使用する証明書を取得
$cert = Get-ChildItem -Path Cert:\CurrentUser\My `
        | Where-Object { $_.Subject -match $certName } `
        | Select-Object -First 1

# フォルダ内のすべての.ps1ファイルを取得
$files = Get-ChildItem -Path $targetFolder -Filter "*.ps1" -Recurse

foreach ($file in $files) {
    # 自身の自動署名スクリプトはスキップ
    if ($file.Name -eq "AutoSigner.ps1") { continue }

    # 現在の署名状態を確認
    $sig = Get-AuthenticodeSignature -FilePath $file.FullName

    # 署名が無効(Validではない)場合のみ再署名を実行
    if ($sig.Status -ne "Valid") {
        Set-AuthenticodeSignature -FilePath $file.FullName -Certificate $cert
        Write-Output "【署名完了】: $($file.Name) に署名を付与しました。"
    }
}

この AutoSigner.ps1 をタスクスケジューラに登録し、「毎日夜間に実行」や「1時間ごとに実行」に設定しておきます。

タスクスケジューラへの登録ポイント

  • 実行するプログラムpowershell.exe
  • 引数の追加-ExecutionPolicy Bypass -File "C:\ScriptManagement\AutoSigner.ps1"
  • 実行アカウント:証明書が格納されているユーザー(今回はCurrentUserに作ったため)の権限で実行するように設定します。

これで、管理者は対象フォルダ内のスクリプトを自由に修正・追加するだけで、あとはシステムが勝手に裏で署名を済ませてくれるようになります。

自動運用を始めると、今度は「本当に正しく署名できているか」「実行時にエラーが起きていないか」をチェックする仕組みが必要になります。
タスクスケジューラで実行するPowerShellスクリプトのエラー検知とログ管理は、以下の2点を意識すると確実です。

1. トランスクリプト(Transcript)機能で丸ごとログに残す

スクリプトの先頭と末尾に Start-TranscriptStop-Transcript を仕込んでおきましょう。
画面に出力されるすべての内容(エラーメッセージ含む)が、そのままテキストファイルに保存されます。

PowerShell

# スクリプトの冒頭に記述(日付入りのログファイルを自動生成)
Start-Transcript `
     -Path "C:\ScriptManagement\Logs\SignLog_$(Get-Date -Format 'yyyyMMdd').log" `
     -Append

# 〜〜(ここにメインの処理)〜〜

# スクリプトの最後に記述
Stop-Transcript

2. try-catch構文によるエラーハンドリング

万が一、証明書の有効期限が切れていた場合や、ファイルがロックされていて署名に失敗した場合に備え、エラーをキャッチしてWindowsの「イベントログ」に書き出したり、管理者へ通知したりする設定を入れておくと万全です。

PowerShell

try {
    Set-AuthenticodeSignature -FilePath $file.FullName -Certificate $cert -ErrorAction Stop
} catch {
    # エラーが発生した場合はイベントログに記録(ソース名:Applicationなど)
    Write-EventLog -LogName "Application" -Source "SideShow" -EventID 999 `
            -EntryType Error -Message "スクリプト $($file.Name) の署名に失敗しました。理由: $_"
}

「手動の手間をなくす自動化」と「失敗にすぐ気づけるログ管理」をセットで導入することで、社内スクリプトの運用は劇的に楽になります!

実務で導入する際の注意点とトラブルシューティング

自己署名証明書とスクリプト署名は、コストをかけずにセキュリティを高められる非常に便利な仕組みですが、実務で運用するにあたってはいくつか押さえておくべき重要な注意点があります。
いざというときに慌てないよう、トラブルシューティングと適切な使い分けについて知っておきましょう。

この記事の【ステップ1】では、証明書の有効期限を5年間に設定しましたが、自己署名証明書には必ず有効期限が訪れます。

もし証明書の期限が切れると、その証明書で署名されたスクリプトはすべて 「無効な署名」 とみなされ、実行ポリシー(AllSignedなど)によって突然実行できなくなってしまいます。

対処法1:タイムスタンプサーバーを利用して署名する(推奨)

署名を行う際(Set-AuthenticodeSignatureを実行する時)に、外部の「タイムスタンプサーバー」のURLを指定しておくと、証明書の期限が切れた後もスクリプトをそのまま実行させることができます。

PowerShell

# タイムスタンプを付与して署名する例(DigiCertなどの無料タイムスタンプサーバーを利用)
Set-AuthenticodeSignature `
        -FilePath "$HOME\Desktop\myscript.ps1" `
        -Certificate $cert `
        -TimeStampServer "http://timestamp.digicert.com"

タイムスタンプが付いていると、Windowsは「このスクリプトは、証明書が有効だった時代に正しく署名されたものである」と判断してくれるため、期限切れによる実行ストップを防げます。

対処法2:新しい証明書を再発行して差し替える

タイムスタンプを使っていなかった場合は、新しく自己署名証明書を作り直し、再度スクリプトに署名を付与する必要があります。
また、GPOで配布している場合は新しい .cer ファイルの再配布も必要になります。

今回解説した「自己署名証明書(通称:オレオレ証明書)」は、あくまで自分が管理しているPCや、GPOが届く社内ネットワーク(ドメイン環境)の中だけで通用する技術です。

以下のようなケースでは、自己署名証明書は使えません。

  • 取引先や顧客など、社外のPCでスクリプトを実行してもらう場合
  • インターネット上で不特定多数に向けてスクリプトを公開・配布する場合
  • 厳格なセキュリティ監査(コンプライアンス)が求められる本番サーバー環境

社外のPCには、あなたが作った自己署名証明書(信頼されたルート証明機関の設定)が入っていないため、スクリプトを実行しようとすると「信頼できない発行元」として真っ赤な警告画面が表示されるか、実行が完全にブロックされてしまいます。

不特定多数に配るなら「コード署名証明書」の購入を 不特定多数の環境やビジネスの本番環境でスクリプトを配布する場合は、DigiCertやGlobalSignといった公的な認証機関(CA)から、有料の「コード署名証明書(Code Signing Certificate)」を購入して署名する必要があります。
公的証明書であれば、世界中のWindowsが最初からその身元を信頼しているため、事前の設定なしでスムーズに実行可能です。

まとめ

安全と効率を両立したPowerShell運用を!

最後に、今回ご紹介した手順をおさらいしましょう。

  1. New-SelfSignedCertificate でコード署名用の自己署名証明書を作成する。
  2. 作成した証明書をシステムの「信頼されたルート証明機関」「信頼された発行元」に登録する。
  3. Set-AuthenticodeSignature でスクリプトにデジタル署名を施す。
  4. 社内展開時は GPO を、運用の手間を省くなら タスクスケジューラ による自動署名を活用する。

「実行ポリシーをBypassにする」という目先の利便性に逃げてしまうと、システムは常に危険にさらされることになります。

少し手間に感じるかもしれませんが、自己署名証明書を使った正しい署名プロセスを一度構築してしまえば、「強固なセキュリティ」と「ストレスのない自動化環境」を完璧に両立させることができます。

ぜひこの記事を参考に、安全でスマートなPowerShell運用を始めてみてください!

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトは reCAPTCHA によって保護されており、Google のプライバシーポリシー および 利用規約 に適用されます。

reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

ABOUT ME
ポコぺん
ポコぺん
ぷぅ
北海道在住のITエンジニア。

システム構築および運用・保守を経験。
ESXi、Azure、Proxmox VEについて基礎的な理解あり。
C系言語、PowerShellスクリプト、Excelマクロなどを少々扱う。
記事URLをコピーしました