この記事は「PowerShell Advent Calendar 2018」の参加記事です。
サンプルとして簡単な JSON を返すコマンドレットを持つモジュールを作成します。対象の PowerShell Core のバージョンは 6.1.0 です。
サンプル コード
SampleModule.csproj
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="System.Management.Automation" Version="6.1.0" /> </ItemGroup> <ItemGroup> <None Update="SampleModule.psd1"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup> </Project>
SampleModule.psd1
@{ RootModule = 'SampleModule.dll' ModuleVersion = '1.0.0' CmdletsToExport = "*" }
WriteHelloWorldCommand.cs
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Management.Automation; using System.Text; namespace SampleModule { [Cmdlet("Write", "HelloWorld")] public class WriteHelloWorldCommand : PSCmdlet { protected override void ProcessRecord() { this.WriteObject(JsonConvert.SerializeObject(new { Message = "Hello World" })); } } }
実行結果
dotnet publish してから Import-Module でモジュールを読み込んで実行してみますがエラーになります。
PS C:\SampleModule> dotnet publish PS C:\SampleModule> Import-Module "C:\SampleModule\bin\Debug\netcoreapp2.1\publish\SampleModule.psd1" PS C:\SampleModule> Write-HelloWorld Write-HelloWorld : Could not load file or assembly 'Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621) At line:1 char:2 + Write-HelloWorld + ~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-HelloWorld], FileLoadException + FullyQualifiedErrorId : System.IO.FileLoadException,SampleModule.WriteHelloWorldCommand
何が起こっているのか?
PowerShell Core は自身が Json.NET をライブラリとして使っています。PowerShell Core 6.1 系では Json.NET 11.0.2 が同梱されています。PowerShell Core を起動した時点で 11.0.2 がロードされてしまっているので、インポートしたモジュールで異なるバージョンのアセンブリを読もうとするとエラーになってしまいます。この問題を解決するには、モジュールが使う Json.NET のバージョンを常に PowerShell Core が使っている Json.NET のバージョンと合わせる必要があります。
根底としては PowerShell Core の問題ではなく .NET Core の問題 (AppDomain をサポートしていないことによる) なのですが、こんな時代になっても DLL 地獄に悩まされるのはどうなのかなあと思ってしまいます。
なお GitHub でもだいぶ前から Issue は上がっていますが Open のままとなっています。ちなみにこちらでは、異なるモジュールをインポートしたときにそれぞれが異なるバージョンのアセンブリを使っているとエラーになるよという内容ですが、どちらかというとこちらの問題のほうがエグいですね。