PowerShellのExecutionPolicyのスコープとかについて詳しく

*※変数のスコープの話じゃないです。*

PowerShellは、デフォルトではPowerShellスクリプトを実行できないポリシーに設定されていることは有名です。
PowerShellはコンソール上のみの操作でも有益とは言え、スクリプトを使用できないのでは大変不便です。
ですからPowerShellを頻用するユーザーは、新しいWindows環境を作る際はまず Set-ExecutionPolicyコマンドレットで実行ポリシーをRemoteSignedに設定しておくのが常識と言えるでしょう。

```ps1:PowerShell
Set-ExecutionPolicy RemoteSigned
```
……いや、そうなのでしょうか。
スクリプトが実行できない様になっているのは、安全性を考慮した上での仕様です。そう簡単にそのタガを緩めてしまって良いのでしょうか。
まあそれは良しとしても、他所の環境、実行ポリシーがRestrictedで設定されている環境を使わなければならない場合、自分の中の常識がRemoteSigned環境で固められているのは問題が無いでしょうか。

という疑問から、私は基本的に、**システムの**PowerShell実行ポリシーはデフォルトの状態で使用するようにしています。
ではPowerShellスクリプトは使わないのかと言えば、そんな事は全くありません。
そこはある程度コントロールできるようになっているのですが、一般に今ひとつ言及されない情報のため、少しまとめておきたいと思った次第です。

#実行ポリシーの設定値について
基本的な事ですが、ヘルプから引用しておさらいとします。
ぶっちゃけ今回の記事ではあまり重要なポイントではありません。
要するにデフォルトはRestrictedでスクリプトを実行できないので、RemoteSignedで使える感じにしたいということです。

|ポリシー|内容|
|:-:|:--|
|Restricted|構成ファイルの読み込みやスクリプトの実行を行いません。既定値は "Restricted" です。|
|AllSigned|すべてのスクリプトと構成ファイルが信頼された発行元によって署名されていることを要求します (ユーザーがローカル コンピューターに書き込むスクリプトを含む)。|
|RemoteSigned|インターネットからダウンロードされたすべてのスクリプトおよび構成ファイルが、信頼された発行元によって署名されていることを要求します。|
|Unrestricted|すべての構成ファイルを読み込み、すべてのスクリプトを実行します。インターネットからダウンロードされた署名されていないスクリプトを実行する場合、スクリプトを実行する前に確認を求められます。|
|Bypass|何もブロックされず、警告もメッセージも表示されません。|
|Undefined|現在のスコープから現在割り当てられている実行ポリシーを削除します。このパラメーターは、グループ ポリシー スコープ内で設定された実行ポリシーは削除しません。|


#スコープについて
実行ポリシーのあまり周知されていない重要な概念に、スコープというものがあります。
Set-ExecutionPolicyではScopeオプションで指定します。
Set-ExecutionPolicyのヘルプからScopeオプションについて、以下に引用します。
> 実行ポリシーのスコープを指定します。既定値は LocalMachine です。
> 
> 有効な値は次のとおりです。
> -- Process: 実行ポリシーは現在の Windows PowerShell プロセスにのみ影響します。
> -- CurrentUser: 実行ポリシーは現在のユーザーにのみ影響します。
> -- LocalMachine: 実行ポリシーはコンピューターのすべてのユーザーに影響します。

#Processスコープについて
文字通り、プロセスレベルのスコープです。
Set-ExecutionPolicyはデフォルト実行でLocalMachineスコープになりますが、オプションを指定すればプロセス限定の設定に留めることができます。
**Processスコープの設定では、管理者権限も不要ですし、永続性もありません。**
実行ポリシーがデフォルトのWindows環境でも、PowerShellコンソールで都度以下のコマンドを実行することで、

```ps1:PowerShellコンソール
Set-ExecutionPolicy RemoteSigned -Scope Process
```
システムの設定に影響を与えずにスクリプトを実行する事ができるわけです。

```ps1:PowerShellコンソール
.\hello.ps1
```

#実行ポリシーの設定値はどこに保存されるのか
実行ポリシーの保存先は、設定のスコープによって変わります。
明言された情報ばかりではないので公式の仕様とは言えませんが、実行ポリシーの影響を理解する上でポイントとなる情報です。

|スコープ|保存場所|
|:-:|:--|
|Process|環境変数 PSExecutionPolicyPreference (プロセス起動時にシステムが付与する環境変数設定ではなく、プロセス内部で処理されるもの)|
|CurrentUser|レジストリ HEKY_CURRENT_USER:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell の ExecutionPolicy|
|LocalMachine|レジストリ HKEY_LOCAL_MACHINE:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell の ExecutionPolicy|

LocalMachineスコープの設定で管理者権限が必要なのは、設定の書き込み先に必要な権限と整合しています。
CurrentUserスコープの設定先はユーザー毎のレジストリのため当然他のユーザーには影響しない、という訳です。
レジストリの場合、32bit/64bitプロセスでアクセス先が異なる事を意識する場面があるかもしれません。

「Set-ExecutionPolicyを実行するためにPowerShellを管理者権限で立ち上げよ」という説明がよくありますが、Scopeを変更する方が妥当なケースが多いと思われます。

#ProcessスコープについてⅡ
Processスコープの設定は環境変数に設定されるため、その副作用的な挙動を把握しておきましょう。
##1. 環境変数を引き継ぐ子プロセスに実行ポリシーが継承される
実行ポリシーを変更し、子プロセスとして立ち上げたPowerShellでもその設定が継承されています。

```bat:PowerShellコンソール実行結果
PS C:\> Get-ExecutionPolicy                                  ## 現在の実行ポリシー ##
Restricted
PS C:\> Set-ExecutionPolicy RemoteSigned -Scope Process      ## 実行ポリシーの設定 ##

実行ポリシーの変更
実行ポリシーは、信頼されていないスクリプトからの保護に役立ちます。実行ポリシーを変更すると、about_Execution_Policies
のヘルプ トピック (http://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります。実行ポリシーを変更しますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"):
PS C:\> Get-ExecutionPolicy                                  ## 設定後の実行ポリシー ##
RemoteSigned
PS C:\> powershell.exe
Windows PowerShell
Copyright (C) 2014 Microsoft Corporation. All rights reserved.

PS C:\> Get-ExecutionPolicy                                  ## 子プロセスの実行ポリシー ##
RemoteSigned
```

##2. Set-ExecutionPolicy以外の操作でも実行ポリシーを変更できる
コマンドプロンプトからsetコマンド等で環境変数を設定しておいても、PowerShellスクリプトを実行できるようになっています。
ですから、下記のようなバッチファイルで、ユーザー環境の実行ポリシーに依存せずPowerShellスクリプトを実行する事も可能です。

```bat:hello.bat
set PSExecutionPolicyPreference=RemoteSigned
powershell .\hello.ps1
```
ちょっとびっくりですね。

これはこのようにしても実行できるという例で、純粋にPowerShellスクリプトを起動する目的であればもっと適切な方法があります。

#powershell.exe の ExecutionPolicy オプション
実行ポリシーは、powershell.exe の起動オプションで指定することができます。
この時の指定は、Processスコープの設定になります。
この設定は即時反映され、同時にスクリプトファイルの指定も可能です。
したがって、実行ポリシーがデフォルトの環境でも、起動オプションを適切に指定すればPowerShellスクリプトの実行は可能というわけです。

```:指定例
powershell -ExecutionPolicy RemoteSigned -File .\hello.ps1
```

Fileオプション等を指定しなければ、ProcessスコープのRemoteSignedでPowerShellコンソールが立ち上がります。

#まとめ
* Set-ExecutionPolicyはそのプロセスのみ限定のスコープがあり、管理者権限は不要
* powershell.exeの起動オプションでExecutionPolicyを指定することも可能で、適切に起動オプションを指定すればデフォルト環境でもスクリプトは実行できる

スクリプト配布や、他のプログラムからPowerShellスクリプトを起動する際、ユーザーに予め実行ポリシーの変更を求めておく必要は通常ありません。
タスクスケジューラでも安心。

PowerShellのパワーユーザーでも、LocalMachineに実行ポリシーを設定するのではなく、RemoteSignedを指定したpowershell.exeの起動ショートカットを用意しておくだけでも問題ないケースが多いと思います。基本的に子プロセスにも設定が引き継がれるので支障は少ないでしょう。

ワンクリックで使いたいスクリプトは、ショートカットかバッチファイルを予め作っておくと良いと思います。
スタートメニュー配下に登録しておけば、検索にもヒットするようになります。

普段の使用があまりRemoteSignedに寄り過ぎると、実行ポリシーAllSignedの意義が薄れてしまいます(まあ私もAllSignedは最近全然使いませんが…)。
普段の環境をRemoteSingedありきとしない事はそれなりに意味があるのではないか、と信じて、LocalMachineの実行ポリシーはデフォルトから変更しない事を私は勧めたいと思っています。