⚙️
PowerShell Core で Binary Module (C#) を開発するときの注意点について
はじめに
この記事は 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 のままとなっています。ちなみにこちらでは、異なるモジュールをインポートしたときにそれぞれが異なるバージョンのアセンブリを使っているとエラーになるよという内容ですが、どちらかというとこちらの問題のほうがエグいですね。
Discussion