PowerShellでAdd-Type -Path
等でdllを読み込む際、「新しすぎて読み込みません」というようなメッセージが出ることがある。
原因はPowerShellが使用している.NET Framework。たとえPC(サーバー)に最新の.NET Frameworkが入っていても、PowerShellが使用するのは旧態依然の2.0なのだ。
このため、新しいフレームワークで追加されたクラス、ビルドされたdllを読み込もうとすると上記のエラーが発生する。
互換性のための措置と思われるが、正直有難迷惑なので動作する.NET Frameworkのバージョンを変更することにする。
PowerShellのインストールディレクトリ(powershellを起動し、$pshomeで確認可能)に、下記のようなconfigファイルを配置する。
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.5.51209"/>
<supportedRuntime version="v4.0.30319"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
<runtime>
<loadfromremotesources enabled="true"/>
</runtime>
</configuration>
supportedRuntimeを加えることで、動作する.NET Frameworkを調整できる。
なお、デフォルトの開発環境であるPowerShell ISE上で動かす場合には、別途同じ内容をpowershell_ise.exe.config
で保存しておく必要がある。
また、configファイルを参照するようなdllの場合は、以下のようにする(下記例では、mylib.dll.configに設定された"dllparam"が表示されればOK)。
$root = "C:\my_assembly\"
$assembly_path = $root + "mylib.dll"
$assembly_config = $assembly_path + ".config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $assembly_config)
Add-Type -AssemblyName System.Configuration
Add-Type -Path $assembly_path
write-host ([Configuration.ConfigurationManager]::AppSettings["dllparam"])
なお、ISEを使っている場合configへのパスがキャッシュされるようでうまく動かない。
その場合、キャッシュを初期化する下記の呪文を入れることで対処可能.
[Configuration.ConfigurationManager].GetField("s_initState", "NonPublic, Static").SetValue($null, 0)
[Configuration.ConfigurationManager].GetField("s_configSystem", "NonPublic, Static").SetValue($null, $null)
([Configuration.ConfigurationManager].Assembly.GetTypes() | where {$_.FullName -eq "System.Configuration.ClientConfigPaths"}).GetField("s_current", "NonPublic, Static").SetValue($null, $null)
<参考>
Enable .NET 4 Runtime for PowerShell and Other Applications
Using CurrentDomain.SetData(“APP_CONFIG_FILE”) doesn't work in PowerShell ISE