見出し画像

PowerShell ISEでスクリプト実行するために、Set-ExecutionPolicyで実行ポリシーを変更したけど実行できない時の原因と対処

結論:32bit版と64bit版で参照しているレジストリが異なるから

実行ポリシーを変更したのにスクリプトが実行できない

WindowsはデフォルトでPowerShellのスクリプト実行が実行ポリシーによって制限されています。

PS D:> ./Test.ps1
./Test.ps1 : このシステムではスクリプトの実行が無効になっているため、ファイル D:\Test.ps1 を読み込むことができません。
詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:1
+ ./Test.ps1
+ ~~~~~~~~~~
    + CategoryInfo          : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

そのためスクリプトを実行するには、こちらの書籍にもあるように管理者権限でPowerShellを起動し「Set-ExecutionPolicy RemoteSigned」などで実行ポリシーを変更してあげる必要があります。

PS D:> Set-ExecutionPolicy RemoteSigned
実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies
のヘルプ トピック (https://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"): y

実行ポリシーの種類はMicrosoft公式の「実行ポリシーについて - PowerShell | Microsoft Learn」で確認してください。

実行ポリシーの変更は、管理者権限で起動されたコマンドプロンプトで「powershell Set-ExecutionPolicy RemoteSigned」とすることでも変更できます。変更出来たかどうかは「Get-ExecutionPolicy」で確認しましょう。

PS D:\> Get-ExecutionPolicy
RemoteSigned

PowerShellで実行ポリシーを変更し、そのままスクリプト実行をする場合は問題ないと思います。しかし、コマンドプロンプトで変更したり、変更後にPowerShell ISEでスクリプトを実行しようとすると、変更したはずなのに再びエラーが発生してしまう場合があるかもしれません。

問題が発生している場合は「Get-ExecutionPolicy -List」で実行ポリシーが偏向できているか確認してみましょう。PowerShell ISEの場合は、コンソールウインドウでコマンドレットを直接実行するか、スクリプトウインドウに記述して「F8(選択項目を実行)」を押下すれば実行できます。

「Get-ExecutionPolicy」を実行すると、恐らくUndefinedで実行ポリシーは変更されていないと思います。

PS D:\> Get-ExecutionPolicy
Undefined

その場合は実行ポリシーの変更を実行したPowerShellまたはコマンドプロンプトで「Get-ExecutionPolicy」を実行してみて下さい。コマンドプロンプトの場合は先頭に「powershell」を加えましょう。

PS D:\> Get-ExecutionPolicy
RemoteSigned

変更されているかと思います。次はどちらでも良いですが、実行ポリシーの変更を行った画面でCurrentUserの実行ポリシーを変更してみましょう。Scopeパラメーターに続いてCurrentUserと記述するだけです。

PS D:\> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシ
ーを変更すると、about_Execution_Policies のヘルプ トピック
(https://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシ
ーを変更しますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)
[S] 中断(S)[?] ヘルプ (既定値は "N"): y

CurrentUserの実行ポリシーが変更できたと思います。ここで「Get-ExecutionPolicy 」にListパラメーターを追加して確認しましょう。

PS D:\> Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser    RemoteSigned
 LocalMachine    RemoteSigned

CurrentUserの実行ポリシーの変更が確認出来たら、スクリプトが実行できなかったPowerShellでスクリプトを実行してみて下さい。実行できるようになっていると思います。

スクリプト実行できたことを確認したら、そちらでも「Get-ExecutionPolicy -List」で実行ポリシーを確認してみましょう。

PS D:\> Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser    RemoteSigned
 LocalMachine       Undefined

CurrentUserの実行ポリシーは変更されていますが、LocalMachineの実行ポリシーが変更されていないことが分かると思います。

というわけで、実行ポリシーの変更がCurrentUserでは別のPowerShellにも反映されているのに、LocalMachineでは反映されていないという結果になりました。これはPowerShellには32bit版と64bit版があるため発生します。

32bit版と64bit版のレジストリの違い

CurrentUserの実行ポリシーが保存されるレジストリは「¥HKEY_CURRENT_USER¥Software¥Microsoft¥PowerShell¥1¥ShellIds¥Microsoft.PowerShell」です。これは32bit版も64bit版も共有です。

一方、LocalMachineの実行ポリシーが保存されるレジストリは以下のように32bit版と64bit版で異なります。

・32bit版:「¥HKEY_LOCAL_MACHINE¥SOFTWARE¥WOW6432Node¥Microsoft¥PowerShell¥1¥ShellIds¥Microsoft.PowerShell」
・64bit版:「¥HKEY_LOCAL_MACHINE¥SOFTWARE¥Microsoft¥PowerShell¥1¥ShellIds¥Microsoft.PowerShell」

実際に「Get-Item」で参照先の値を確認してみましょう。

PS D:\> Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"


    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds


Name                           Property
----                           --------
Microsoft.PowerShell           Path            : C:\Windows\System32\WindowsP
                               owerShell\v1.0\powershell.exe
                               ExecutionPolicy : RemoteSigned

本記事の手順に従っている場合は32bit版のLocalMachineの実行ポリシーはUndefinedだと思います。その場合は値が設定されていないので表示されないと思います。

PS D:\> Get-Item -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"


    Hive: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\PowerShell\1\Shel
    lIds


Name                           Property
----                           --------
Microsoft.PowerShell           Path : C:\Windows\SysWOW64\WindowsPowerShell\v
                               1.0\powershell.exe

32bit版のPowerShellで実行ポリシーを設定してあげると64bit版とは異なる値が設定されているのが分かると思います。

コマンドプロンプトの場合は「reg query」で取得してみましょう。

C:\>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" /v "ExecutionPolicy"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
    ExecutionPolicy    REG_SZ    RemoteSigned

32bit版と64bit版でレジストリが異なるのはレジストリ リダイレクターによるものです。CurrentUserのように共有している場合もあるのでややこしいですね。

レジストリ リダイレクターは、WOW64 でレジストリの特定の部分の個別の論理ビューを提供することで、32 ビットと 64 ビットのアプリケーションを分離します。 レジストリ リダイレクターは、32 ビットと 64 ビットのレジストリ呼び出しをそれぞれの論理レジストリ ビューにインターセプトし、対応する物理レジストリの場所にマップします。

レジストリ リダイレクター - Win32 apps

先ほどの「Get-Item」の結果からも分かる通り、32bit版と64bit版で格納場所も異なります。ファイルシステムリダイレクターもあるわけですね。

「C:\Windows\SysWOW64\cmd.exe」にある32bit版のコマンドプロンプトを起動して「start poweshell」しましょう。起動されるPowerShellも32bit版となります。

PS D:\> [System.Environment]::Is64BitProcess
False

つまり、64bit版のLocalMachineの実行ポリシーを変更して、32bit版アプリからPowerShellスクリプトを実行しようとすると失敗するなんてことも起きそうですね。

対処方法

ここまで読んでいただければ分かると思いますが、実行ポリシーを変更したはずなのにスクリプトが実行できない場合の対処方法は以下の二つです。

一つは、レジストリを共有しているスコープを変更すること。例えばCurrentUserです。

PS D:\> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

もう一つは、64bit版のPowerShellまたはPowerShell ISEを使用することです。64bit版を使用する場合は32bit版の実行ポリシーを元に戻しておいた方が良いと思います。

x86でないものを使用する

出来ることが増えると記事に還元されます。コメント頂ければ参考にします。