PowerShellスクリプトの署名方法(および効果的な実行方法)

スクリプトを誰もが元のままのまま変更せずに通過させないようにする必要がありますか?その場合は、PowerShellスクリプトに署名する方法を学ぶ必要があります。署名すると、ユーザーはスクリプトのソースを信頼するかどうかを決定できるように、発行者のアイデンティティがスクリプトに追加されます。

この記事では、PowerShellスクリプトに署名する方法を学ぶことで、環境で信頼されたスクリプトのみが実行されるようにする方法について説明します。

前提条件

この記事の例に従う場合は、次のものが必要です。

  • A computer running on a recent version of the Windows operating system. This article uses Windows 10 version 20H2.
  • Windows PowerShell 5.1またはPowerShell 6+。この記事の例では、PowerShell v7.1.3を使用します。
  • A sample PowerShell script for signing. Feel free to create a script with any name and in any folder you want. This article will use a sample script called C:\ATA\myscript.ps1 that contains the code below.
Write-Host "Script Execution - OK"

コード署名証明書の取得

PowerShellスクリプトに署名する方法を学ぶ前に、まずコード署名証明書を取得する必要があります。マイクロソフトの世界では、コード署名証明書はAuthenticode証明書とも呼ばれています。

A code signing certificate is one type of digital certificate whose purpose for signing files. Signing a file or code with a code signing certificate adds proof that the file came from the publisher who signed it.

署名されたスクリプトを展開または配布する場所に応じて、コード署名証明書を取得する場所が異なります。そして、いつものように、費用も大きな要因です。

  • グローバル/パブリック – 発行者がグローバルに信頼されている証明書(CA)が必要です。その例としては、GeoTrustDigiCert などのCAがあります。これらの証明書は無料ではありません。たとえば、この執筆時点での DigiCert Authenticode 証明書の価格は年間 $474 です。
  • 内部/ローカルイントラネット – 内部証明書機関(CA)サーバーがある場合、内部CAサーバーから署名証明書をリクエストしてダウンロードできます
  • 個人/開発 – 個人のテストや開発用途では、自己署名証明書が適しています。この種の署名証明書は、この記事で使用されるものです。

コードサイニング用の自己署名証明書の作成

前のセクションで、PowerShellスクリプトに署名する方法を学ぶには、まずコードサイニング証明書が必要です。このチュートリアルでは個人のテストしか行わないので、自己署名証明書が十分です。では、どこで取得できるのでしょうか?

その名の通り、自己署名とは、ローカルコンピューターが自分にコードサイニング証明書を発行することを意味します。自己署名証明書を生成するには、以下の手順に従ってください。

1. コンピューターで管理者として PowerShell を開きます

2. 以下のコマンドをコピーして PowerShell で実行します。このコマンドは New-SelfSignedCertificate コマンドレットを使用して新しいコード署名証明書を作成します。証明書の名前はローカルコンピューターのパーソナル証明書ストア内にATA Authenticodeという名前で保存されます。

New-SelfSignedCertificate コマンドレットは、現在のユーザーのパーソナル証明書ストア (cert:\CurrentUser\My) またはローカルマシンのパーソナル証明書ストア (cert:\LocalMachine\My) にのみ証明書を作成することができます。cert:\LocalMachine\My 内の証明書は、コンピュータ全体で使用できます。

このコマンドは、証明書オブジェクトを $authenticode 変数に保存し、次の手順で使用します。

# ローカルコンピューターのパーソナル証明書ストアに自己署名 Authenticode 証明書を生成します。
 $authenticode = New-SelfSignedCertificate -Subject "ATA Authenticode" -CertStoreLocation Cert:\LocalMachine\My -Type CodeSigningCert

3. 次に、新しく作成した証明書をコンピューターが信頼するようにするために、自己署名証明書をコンピューターの信頼されたルート証明機関信頼された発行者証明書ストアに追加します。これを行うには、以下のコードをコピーして PowerShell で実行します。

# 自己署名のAuthenticode証明書をコンピューターのルート証明書ストアに追加します。
## ローカルマシン\ルート証明書ストアを表すオブジェクトを作成します。
 $rootStore = [System.Security.Cryptography.X509Certificates.X509Store]::new("Root","LocalMachine")
## 読み取りと書き込みのためにルート証明書ストアを開きます。
 $rootStore.Open("ReadWrite")
## $authenticode変数に格納されている証明書を追加します。
 $rootStore.Add($authenticode)
## ルート証明書ストアを閉じます。
 $rootStore.Close()
 
# 自己署名のAuthenticode証明書をコンピューターの信頼された発行元証明書ストアに追加します。
## ローカルマシン\信頼された発行元証明書ストアを表すオブジェクトを作成します。
 $publisherStore = [System.Security.Cryptography.X509Certificates.X509Store]::new("TrustedPublisher","LocalMachine")
## 読み取りと書き込みのために信頼された発行元証明書ストアを開きます。
 $publisherStore.Open("ReadWrite")
## $authenticode変数に格納されている証明書を追加します。
 $publisherStore.Add($authenticode)
## 信頼された発行元証明書ストアを閉じます。
 $publisherStore.Close()

自己署名の証明書を3つの異なる証明書ストアにインストールする主な理由があります。

  • 個人証明書ストアに作成した証明書は、コード署名証明書として使用します。
  • 同じ証明書を信頼された発行元ストアにコピーすると、ローカルコンピューターがスクリプトに署名した発行元を信頼するようになります。PowerShellは、このストア内の証明書をチェックしてスクリプトの署名を検証します。
  • 最後に、自己署名証明書を 信頼されたルート証明機関 に追加することで、ローカルコンピュータが 個人信頼された発行元 ストア内の証明書を信頼するようになります。

4. 主題が ATA Authenticode の証明書が 個人ルート、および 信頼された発行元 証明書ストアに存在するかどうかを確認するには、PowerShell で以下のコマンドを実行します。

# 自己署名 Authenticode 証明書がコンピュータの個人証明書ストアに存在するかどうかを確認
 Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -eq "CN=ATA Authenticode"}
# 自己署名 Authenticode 証明書がコンピュータのルート証明書ストアに存在するかどうかを確認
 Get-ChildItem Cert:\LocalMachine\Root | Where-Object {$_.Subject -eq "CN=ATA Authenticode"}
# 自己署名 Authenticode 証明書がコンピュータの信頼された発行元証明書ストアに存在するかどうかを確認
 Get-ChildItem Cert:\LocalMachine\TrustedPublisher | Where-Object {$_.Subject -eq "CN=ATA Authenticode"}
Confirming the creation of the new self-signed certificate

5. GUI で 証明書 を表示するには、証明書スナップイン を開き、個人信頼されたルート証明機関、および 信頼された発行元 証明書ストア内の作成した証明書を探します。

Viewing certificates in the Microsoft Management Console (MMC)

PowerShell スクリプトにサインする方法

コード署名証明書を作成してインストールしたら、サンプルの PowerShell スクリプトに署名する準備が整いました。スクリプトに署名する必要がある場合は、Set-AuthenticodeSignature cmdlet が主役です。

PowerShell で PowerShell スクリプトに署名するには、以下のコードを実行します。最初のコマンドは、ローカルマシンの個人証明書ストアからコード署名証明書を取得します。2 番目のコマンドは、PowerShell スクリプトファイルにデジタル署名を追加します。

# ローカルコンピューターの証明書ストアから *ATA Authenticode* という名前のコード署名証明書を取得し、$codeCertificate 変数に格納します。
$codeCertificate = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -eq "CN=ATA Authenticode"}

# PowerShell スクリプトに署名
# パラメーター:
# FilePath - 署名する PowerShell スクリプトのファイルパスを指定します。例: C:\ATA\myscript.ps1。
# Certificate - スクリプトに署名する際に使用する証明書を指定します。
# TimeStampServer - スクリプトのデジタル署名にタイムスタンプを追加する信頼されたタイムスタンプサーバーを指定します。タイムスタンプを追加することで、署名証明書の有効期限が切れてもコードが有効であることを確認できます。
Set-AuthenticodeSignature -FilePath C:\ATA\myscript.ps1 -Certificate $codeCertificate -TimeStampServer *<http://timestamp.digicert.com>*

最も信頼されている証明書プロバイダーにはタイムスタンプサーバーがあり、それらはプロバイダーのウェブサイトから見つけることができます。例えば、DigiCertのタイムスタンプサーバーはhttp://timestamp.digicert.comであり、Comodoの場合はhttp://timestamp.comodoca.comです。

スクリプトに署名した後、以下のスクリーンショットと同様の出力が表示されるはずです。

How to Sign PowerShell Scripts

PowerShellスクリプトのデジタル署名を確認する

これまでに、作成した自己署名証明書を使用してPowerShellスクリプトに署名しました。しかし、スクリプトがデジタル署名を持っているかどうかをどのように知るのでしょうか?

コードを開く

スクリプトのデジタル署名を確認する方法の1つは、スクリプトを開いてコードをテキストエディターで表示することです。以下の例のように、署名されたスクリプトにはコードの最後に署名ブロックがあります。署名ブロックは# SIG # Begin signature blockで始まり、# SIG # End signature blockで終わります。

Viewing the digital signature in the script’s content

スクリプトのコードからデジタル署名ブロックを削除すると、スクリプトは非署名に戻ります。

スクリプトのファイルプロパティを開く

スクリプトのデジタル署名を確認する別の方法は、Windowsエクスプローラーでスクリプトのファイルプロパティを開くことです。以下の手順で行います:

  1. Windows Explorer で、PowerShell スクリプトの場所に移動します。この例では、スクリプトは C:\ATA\myscript.ps1 にあります。
  2. スクリプトを右クリックし、プロパティ をクリックします。
  3. ファイルのプロパティウィンドウで、デジタル署名 タブをクリックし、署名リスト の下にデジタル署名が表示されます。
Viewing the digital signature in the script’s file properties

Get-AuthenticodeSignature を使用する

PowerShell 内でもスクリプトの署名を確認できることに驚かれるでしょうか?おそらく驚かないでしょう。ファイルの署名を取得するために呼び出せる cmdlet は、Get-AuthenticodeSignature です。

スクリプトのデジタル署名を取得するには、以下のコマンドを実行します。このコマンドは、C:\ATA\myscript.ps1 ファイルの署名を取得します。 Select-Object -Property * cmdlet は、署名のすべての詳細を表示します。

Get-AuthenticodeSignature -FilePath C:\\ATA\\myscript.ps1 | Select-Object -Property *

コマンドを実行した後、スクリーンショットのような類似の結果が表示されます。 SignerCertificate プロパティには、署名証明書の詳細が表示されます。一方、TimerStamperCertificate プロパティには、タイムスタンプサーバーの証明書が表示されます。

Viewing the digital signature in PowerShell

署名された PowerShell スクリプトを実行する

この時点で、PowerShell スクリプトに署名し、デジタル署名が存在することを確認しました。しかし、すべての手順を正しく実行したかの最終テストは、スクリプトを実行して正常に動作することを確認することです。

PowerShellには、ユーザーがスクリプトを誤って実行することを防ぐ安全機能があります。この安全機能は実行ポリシーと呼ばれます。 実行ポリシーに応じて、PowerShellはスクリプトの実行を防止したり許可したりする場合があります。

異なる実行ポリシーとそれらがスクリプトの実行に与える影響について学ぶには、PowerShell Execution Policies: Understanding and Managingを参照してください。

署名されたPowerShellスクリプトを実行するには、次の手順に従ってください。

まず、実行ポリシーをAllSignedに変更して、署名されたスクリプトのみが実行されるようにします。この手順を実行しないと、署名されたスクリプトが正しく動作するかどうかを正確にテストすることができません。そのため、管理者としてPowerShellで以下のコマンドを実行して、Set-ExecutionPolicy cmdletを呼び出します。

Set-ExecutionPolicy AllSigned

次に、署名されたPowerShellスクリプトを実行します。

C:\ATA\myscript.ps1

スクリプトはエラーや警告なしに実行されるはずです。その結果は以下に示されています。

Running the signed script without errors

しかし、スクリプトが正しく署名されていないか、まったく署名されていない場合は、以下の画像のようなエラーが発生します。その場合は、手順を再確認してスクリプトに署名し直してみてください。

Running a script with errors regarding the digital signature

では、スクリプトを最終的に更新した場合はどうなりますか?デジタル署名は有効のままでしょうか?答えはいいえです。署名されたスクリプトに対する任意の変更は、スクリプトのデジタル署名を無効にします。変更されたスクリプトを実行すると、エラーが発生し失敗します。

変更された署名済みスクリプトをテストするには、以下の手順に従ってください。

1. コードまたはテキストエディターで署名されたmyscript.ps1スクリプトを開きます。

2. この例のように、コードにアンダースコアなどの文字を追加します。それ以外の部分は変更しないでください。

Editing the signed script

3. コードを変更した後、スクリプトを保存します。

4. 最後に、以下のコマンドを実行してPowerShellで変更されたスクリプトを実行します。

C:\ATA\myscript.ps1

スクリプトを変更したので、実行すると以下のエラーが表示されます。スクリプトを更新してデジタル署名を修正するには、スクリプトに再度署名する必要があります。

Running a signed script with a broken digital signature

A digital signature does not guarantee that nobody modified the script from its original version. Any PowerShell script with malicious code may be digitally signed, too. Always practice caution when running scripts from sources you do not fully trust.

結論

この記事では、PowerShellスクリプトに署名する理由と、実行ポリシーに応じてそれが必要な場合がある理由について学びました。また、署名されたスクリプトと非署名スクリプトの区別方法についても学びました。最後に、PowerShellスクリプトにデジタル署名する方法と、それらをテストして実行する方法についても学びました。

PowerShellスクリプトに署名する方法を知った今、スクリプトを配布または展開する前に署名を開始しますか?

Source:
https://adamtheautomator.com/how-to-sign-powershell-script/