Windows Server で共有フォルダー上の ps1 ファイルを実行できなかった話

クロスワープの大鷲です。

この記事は PowerShell Advent Calendar 2017 の 7 日目です。

何が起きたの

社内の PC を管理するための PowerShell スクリプトを作成してファイル サーバーに置き、グループ ポリシーを通じてタスク スケジューラーで実行させるように仕込んだところ、一部のマシンで以下のようなエラーが発生していました。*1

f:id:cw_owashi:20171204162227p:plain

なぜ実行できないのか

実行ポリシーに問題があるようなので、Get-ExecutionPolicy を叩いて見ましたが、RemoteSigned です。
RemoteSigned というのは、インターネットからダウンロードしてきたスクリプトは、署名されていないと実行できないというポリシーです。
つまり、このファイルがインターネット由来だと判断されたということです。

ZoneID ではない

この問題が起こった場合、最初にチェックすべきは ZoneID です。
Windows では、インターネットからダウンロードしてきたファイルには ZoneID という情報が付加されます。*2
インターネットの ZoneID がついているファイルは、プロパティを見ると、以下のようになっています。

f:id:cw_owashi:20171204164332p:plain

この表示が出ているということは、インターネット由来のファイルであるということです。
ここで「許可する」にチェックをする、あるいは、Unblock-File コマンドを使うことで、ファイルから ZoneID が削除され、RemoteSigned でも実行できるようになります。*3

しかし、今回問題になったスクリプト ファイルは社内で作成して共有ファイル サーバーに配置したものであって、インターネットからダウンロードしてきたものではありません。
プロパティを見ても、上記のような表示はありませんでした。

一時的な回避もできない

原因はともかく、一時的に実行ポリシーを緩めてやれば実行できるだろうと思い、Set-ExecutionPolicy を試したり、powershell.exe 実行時のオプションに -ExecutionPolicy Bypass をつけて試したりしてみましたが、やはり実行できませんでした。
グループ ポリシーで ExecutionPolicy を RemoteSigned に設定していたため、この設定が強制され、一時的な上書きも出来なくなっていたのです。
さすがにそこから変えるのはまずいので、ちゃんと原因を調べることにしました。

Windows 10 では起きない

そもそも、この問題は、社内の一部のマシンでしか起きていませんでした。
そのマシンの共通点を調べたところ、OS が Windows Server でした。Windows 10 などのクライアント OS では実行できていたのです。
ということは、ファイル自体に問題があるのではなく、ファイルを実行する OS によって、このファイルを配置してある共有ファイル サーバーが、リモートだと判断されたり、されなかったりするということになります。

犯人は「Internet Explorer セキュリティ強化」

サーバー OS でのみ起きるということでピンと来たのが、サーバー OS で既定で有効になっている「Internet Explorer セキュリティ強化の構成(IE ESC)」でした。
PowerShell はファイルのゾーンを判定する際に IE の設定を見ており、IE ESC がそれに影響を与えているのではないかと思ったのです。

そこで、問題のサーバーで IE ESC をオフにしてみたところ、スクリプトが動くようになりました。

f:id:cw_owashi:20171204170623p:plain

なお、IE ESC は、Windows Server 2016 を Server Core インストールしている場合は有効になっていないので、この問題は発生しません。*4

IE ESC をオフにしない方法は?

PowerShell は、スクリプト ファイルの場所が「マイ コンピューター」「ローカル イントラネット」「信頼済みサイト」のいずれかにある場合はローカル、いずれにも無い場合はリモートであると判断します。*5*6

共有ファイル サーバーであれば「ローカル イントラネット」が適切だと思います。
「サイト」ボタンを押して、「この Web サイトをゾーンに追加する」のところに「file://<ファイルサーバー名>」と入力して「追加」を押します。
f:id:cw_owashi:20171204195257p:plain

ファイル サーバーを追加する場合の注意事項

ファイル サーバーとローカル マシンが同じネットワーク上にある場合、サーバー名だけでも、ドメインまで含めた FQDN*7 でもアクセスできますが、ゾーンを判定する際には、これらは区別されます。
そのため、実際にファイルを実行する時のパスの指定方法とあわせる必要があります。
ドメイン内の全マシンを対象にする場合、「file://*.ドメイン名」のようにワイルドカードを使うことが可能ですが、このように指定した場合、実行時にもスクリプト ファイルの場所を FQDN で指定しなければなりません。
そのため、サーバー名のみでのアクセスを許可する場合、面倒ですが、すべてのサーバー名を登録しなければなりません。

FQDN で指定する場合はゾーンの設定が必須

IE ESC をオフにした場合でも、あるいは、Windows 10 などの IE ESC がない OS であっても、FQDN でアクセスするとリモートだと判断されてしまいます。
FQDN でアクセスさせたい場合は、IE ESC が有効か無効かに関わらず、ファイル サーバーの FQDN を「ローカル イントラネット」ゾーンに設定する必要があります。

IE ESC がオフの場合、「ローカル イントラネット」の「サイト」ボタンを押したときに、URL を設定するダイアログが出ません。
この場合は「詳細設定」ボタンを押すと表示されます。

f:id:cw_owashi:20171204195737p:plain

グループ ポリシーでの設定

!!グループ ポリシーを用いた設定の変更はドメイン全体に影響を及ぼしますので、慎重に行ってください!!

そもそも問題が起きていたのは、グループ ポリシーで設定したタスク スケジューラー経由での実行であり、ポリシーを RemoteSigned にするのもグループ ポリシーで強制しているのですから、ファイル サーバーのゾーンを設定するのもグループ ポリシーで行えるとよいのではないかと思いました。
グループ ポリシー エディタを開き、

コンピューターの構成 > ポリシー > 管理用テンプレート > Windows コンポーネント > Internet Explorer > インターネット コントロール パネル > セキュリティ ページ

内にある「サイトとゾーンの割り当て一覧」で設定することができます。
詳細は同項目のヘルプを参照してください。

f:id:cw_owashi:20171206125010p:plain

ただし、この設定を行うと、ユーザーが個別に他のサイトを追加することができなくなるという問題があるため、当社では実施していません。

また、IE ESC をグループ ポリシーで無効化するための項目は、一見すると用意されていないようでした。
レジストリで設定することができるようなので、グループ ポリシーでレジストリの設定を行うことで可能だと思われます。

f:id:cw_owashi:20171206125737p:plain

以下の記事などを参考にするとよいと思います。
4sysops.com

マニアックな話

この問題を調査している時に、何故か私の Windows 10 のマシンで「インターネット オプション」の「サイト」ボタンが押せなくなっていることに気づきました。
なぜそのような状態になったのかはわからないのですが、どうやら、レジストリの設定によるということがわかりました。

インターネット オプションのゾーンの設定は、レジストリの

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones

に格納されています。*8
ここにある "1" というキーが、ローカル イントラネットの設定を表します。この中にある "Flags" という値を書き換えることで、ボタンが押せるようになりました。

f:id:cw_owashi:20171204202142p:plain

このレジストリの設定については、以下のドキュメントが参考になります。興味があったら読んでみてください。
セキュリティ ゾーンのレジストリ エントリについて
上級ユーザー向けの Internet Explorer セキュリティ ゾーン関連のレジストリ エントリ

*1:タスク スケジューラー経由なので、実際にはコンソール ウィンドウは出ません。

*2:インターネットからダウンロードした zip ファイルを展開した場合にも付加される場合があります

*3:これは、このファイルを信頼するということですので、セキュリティ的な問題が無いことを確認してから行いましょう。

*4:Semi-Annual Channel の Windows Server 1709 も、Server Core しかありませんので、この問題は発生しません。

*5:「マイ コンピューター」は文字通り、ファイルが PC のローカル ディスク上にあることを意味します。このゾーンは「インターネット オプション」のダイアログには表示されません(レジストリをいじると表示させることができます)。

*6:https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/security/SecurityManager.cs#L411

*7:Fully Qualified Domain Name

*8:同じ階層にある ZoneMap キー以下には、ゾーンとサイトの URL の関連付けの設定が格納されています。