tech.guitarrapc.cóm

Technical updates

Active Directory の GPO で ExecutionPolicy が設定されているとVS2015 RTM と VS2013 Update 5 において Package Manager Consoleでエラーが出る場合の対処

VS2015 RTMとVS2013 Update 5がリリースされました。

さて、これらをActiveDirectoryに参加したWindowsで起動するとPackageManagerConsoleの起動に失敗する場合があります。今回はこの対処。

Package Manager Consoleがここで停止するので、一切Install-Packageなどが触れないのでツライですね。

追記(2015/7/25)

NuGetチームが問題に対処したVS Extensionを配布します。これにより問題は修正されます。

週明けには、VS galleryに配布が予定されています。が、緊急で必要な場合は、以下のGitHub上のリリースからどうぞ。

https://visualstudiogallery.msdn.microsoft.com/4ec1526c-4a8c-4a84-b702-b21a8f5293ca

https://visualstudiogallery.msdn.microsoft.com/5d345edc-2e2d-4a9c-b73b-d53956dc458d

GitHub Release リンク

2.8.7 for VS 2013: https://github.com/NuGet/Home/releases/download/2.8.7/NuGet.Tools.vsix

3.1.1 for VS 2015: https://github.com/NuGet/Home/releases/download/3.1.1/NuGet.Tools.vsix

バグ報告と対処

NuGetのGitHub Issueでやり取りされています。Issueを見るといろんな報告があり...さて。

https://github.com/NuGet/Home/issues/974

発生するマシン

この問題は、以下の条件がすべて満たされた時に発生します。

  • Active Directoryに参加している

  • Group Policyの「コンピュータの構成 > ポリシー > 管理用テンプレート > Windowsコンポーネント > Windows PowerShell > スクリプトの実行を有効にする > 有効/無効のいずれかになっている」(未構成なら問題ありません)

GPOの何が問題なのか

「コンピュータの構成 > ポリシー > 管理用テンプレート > Windows コンポーネント > Windows PowerShell > スクリプトの実行を有効にする > 有効/無効 のいずれかになっている」

これが設定されていることが面倒な理由です。

このGPOを設定すると、Set-ExecutionPolicyの実行がPowerShell Consoleからは拒否されます。*1

具体的には、「GPOによってExecutionPolicy の ComputerPolicy / UserPolicyが設定される」のですが、ComputerPolicy が設定されているとSet-ExecutionPolicyで設定可能なSet-ExecutionPolicyポリシーの設定が拒否されます。

さらに、AD環境に置いては通常はローカルマシンの管理者権限 (Administrators) を許可していないことも多いのも原因です。(Set-ExecutionPolicyはAdministrators権限が必要です)

原因

NuGet 2.8.6 (VS2013 Update 5) / 3.0 (VS2015 RTM) でのバグ修正の副作用によるものと説明されています。

https://blog.nuget.org/20150720/nuget-3.0.0.html

https://github.com/NuGet/Home/issues/974#issuecomment-123814008

実際に、Package Manager ConsoleでSet-ExecutionPolicyが実行されていることがわかります。

ようは、Set-ExecutionPolicyが実行されても問題ないようにすればいいのです。

対処

いくつかあります。

LocalMachine Policy のレジストリを削除する

先ほど説明した通り、LocalMachinePolicyの設定がSet-ExecutionPolicyを拒否する原因なので、これを一時的に解除する方法もあります。

GPOでは、実質的にレジストリが設定されるだけなので、以下のレジストリを削除すればokです。

Remove-Item registry::HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell

しかしこれも管理者に昇格 して実行が必要なので、GPOによっては難しいでしょう。

GPO で 「スクリプト実行を有効にする」を未構成にする

LocalMachinePolity が設定されていなければ、NuGetがSet-ExeuctionPolicyをやろうとしても影響ありません。

ただしこの場合、ユーザー自身がSet-ExecutionPolicyを実行できる必要があります。

CurrentUserの権限なら、PowerShellを管理者に昇格しなくてもいいのでいけるかも?

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

とはいえ、Package Manager ConsoleはLocalMachineのPolicyをを昇格しているので、AD環境で管理者に昇格できない場合はツライでしょう。

Set-ExecutionPolicy -Scope LocalMachine RemoteSigned

他にも、GPOのポリシー的にここを無効にするのはちょっとというところも多いでしょう。

GPO で「スクリプト実行を有効にする」を未構成にする + レジストリでLocalMachineポリシーを設定する

管理者にも昇格できない。GPOで制御は維持したい。そこで、「MachinePolicy / UserPolicyを設定するのではなく、LocalMachineポリシーのデフォルトを設定する」という考えです。

LocalMachineのポリシーも、レジストリで設定されているので、ここをGPOで設定すれば維持可能でしょう。かつ、ユーザーやPackageManagerConsoleでの変更も受け入れる柔軟な状態です。*2

  • キーパス
HKEY_LOCAL_MACHINE\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell

PowerShell x86用に以下のキーにも同様にやりましょう。

HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell
  • キー名
ExeuctionPolicy
  • 値のタイプ
REG_SZ
  • 値 (ここに設定したいExecutionpolicyを直接いれます)
RemoteSigned

ExecutionPolicy を回避して設定する

ハックに近いですが。ここに紹介されています。

https://www.nivot.org/blog/post/2012/02/10/Bypassing-Restricted-Execution-Policy-in-Code-or-in-Script

InitialSessionState initial = InitialSessionState.CreateDefault();

// Replace PSAuthorizationManager with a null manager
// which ignores execution policy
initial.AuthorizationManager = new
      System.Management.Automation.AuthorizationManager("NuGet");

// Extract psm1 from resource, save locally
// ...

// load my extracted module with my commands
initial.ImportPSModule(new[] { <path_to_psm1> });

// open runspace
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();

RunspaceInvoke invoker = new RunspaceInvoke(runspace);

// execute a command from my module
Collection<PSObject> results = invoker.Invoke("my-command");

// or run a ps1 script
Collection<PSObject> results = invoker.Invoke(@"c:\program files\myapp\my.ps1");

これを利用して、こんなコードでExecutionPolicyを回避できます。管理者権限も回避可能です。

https://gist.github.com/guitarrapc/a20ba670095e09929fc1

ExecutionPolicyにnullを突っ込む手法ですね。管理者権限もいらないので、この手法が許されるならいいかもしれません。*3

まとめ

緊急度は上がりそうなので、修正がリリースされるの待ちましょう。

そして、リリースが発表されました! やったね。

*1:例外の方法もあります

*2:時間がたつとGPOで再度上書きれて維持されます。

*3:もう一個抜け道がありますがここでは触れません