PowerShell や IronPython などで ネットワーク共有フォルダに置かれている .NET アセンブリを読み込むと、このアセンブリのパスが実行ファイルの起動パスと異なるため、部分信頼での実行となってしまい、ファイルの読み書きなどの多くのコードが実行できない。
参考: MSDN | イントラネット アプリケーションの完全信頼での実行
一旦バイナリファイルをメモリに読み込んでから、アセンブリとしてロードするなどと言う方法もあるが、アセンブリからの相対パスなどが利用できなくなったりと、若干使い勝手が悪くなってしまう。
その回避方法として、Vista 以降限定ながら、アセンブリのフォルダをローカルにシンボリックリンクを貼って、そのシンボリックリンクを経由してアセンブリにアクセスすれば、完全信頼として実行することができる。
例えば、複数の PC で同じスクリプトを実行する様な場合、バージョンアップするときに全部の PC をもれなく更新するなど環境をそろえるが面倒だ。
このようなとき、イントラネットの共有ディレクトリにスクリプト置いて、ローカルからシンボリックリンクを通して実行すれば、更新するときはネットワーク共有のスクリプトを書き換えるだけで済み、コードも完全信頼で実行されるので、なかなか便利になる。
サンプルコード
実際に nasne の共有ディレクトリに、ファイルの読み込みを行えるコードを持ったアセンブリを作成して、読み込んでみよう。
C# のコンパイルから、アセンブリの読み込みまでを、PowerShell で以下のようなコマンドで実行してみる。
# C# コードをコンパイルして、アセンブリに保存
$src = @'
using System.IO;
namespace MyNs {
public static class C1 {
public static string F1() { return "Hello World!"; }
public static string F2(string path) { return File.ReadAllText(path); }
}
}
'@
Add-Type -Language CSharpVersion3 -TypeDefinition $src -OutputType Library -OutputAssembly \\NASNE-XXXXXX\share1\PHOTO\mytest.dll
# 保存したアセンブリの読み込み
Add-Type -Path \\NASNE-XXXXXX\share1\PHOTO\mytest.dll
[MyNs.C1]::F1()
[MyNs.C1]::F2("test.txt")
PowerShell のバージョンにも依るが、読み込みの Add-Type コマンドレットや、最後の行でのテキストの読み込み時に、以下の様なエラーが表示されてしまうだろう。
PowerShell v2
out-lineoutput : "formatValueList" の取得中に例外が発生しました: "Microsoft.PowerShell.Commands.Internal.Format.FreeFormatEntry.formatValueList" + CategoryInfo : NotSpecified: (:) [out-lineoutput]、GetValueInvocationException + FullyQualifiedErrorId : CatchFromBaseAdapterGetValue,Microsoft.PowerShell.Commands.OutLineOutputCommand
PowerShell v3
Add-Type : ファイルまたはアセンブリ 'file://\\NASNE-XXXXXX\share1\PHOTO\mytest.dll'、またはその依存関係の 1 つが読み込めませんでした。操作はサポートされません。 (HRESULT からの例外: 0x80131515) 発生場所 行:1 文字:1 + Add-Type -Path \\NASNE-XXXXXX\share1\PHOTO\mytest.dll + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Add-Type], FileLoadException + FullyQualifiedErrorId : System.IO.FileLoadException,Microsoft.PowerShell.Commands.AddTypeCommand
では、ネットワークディレクトリへのシンボリックリンクを、適当なローカルフォルダに貼ってみよう。
コマンドプロンプトを開いて、以下のコマンドを実行する。
mklink /d C:\temp\nasnephotosymlink \\NASNE-XXXXXX\share1\PHOTO
先ほどの PowerShell インスタンスには、すでに 部分信頼が確定したアセンブリが読み込まれてしまっているので、新たに別の PowerShell インスタンスを立ち上げて、以下の様に実行してみる。
Add-Type -Path C:\temp\nasnephotosymlink\mytest.dll
[MyNs.C1]::F1()
[MyNs.C1]::F2("test.txt")
すると、なんと言うことだろう。アセンブリファイルの実態はネットワーク共有上にあるにもかかわらず、問題なく実行できてしまうではないか。
これはもちろん PowerShell に限らず、ネットワーク共有上で実行アセンブリと読み込みアセンブリのパスが異なってエラーとなる場合なら、同じように使える。
ピンバック: PowerShell の組織の中で使えそうで使えないニッチな Tips | Aqua Ware つぶやきブログ