スクリプト言語などから、共有フォルダにある .NET アセンブリを完全信頼で読み込む

Pocket

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 に限らず、ネットワーク共有上で実行アセンブリと読み込みアセンブリのパスが異なってエラーとなる場合なら、同じように使える。

1 thought on “スクリプト言語などから、共有フォルダにある .NET アセンブリを完全信頼で読み込む

  1. ピンバック: PowerShell の組織の中で使えそうで使えないニッチな Tips | Aqua Ware つぶやきブログ

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください