PowerShell モジュールで Application Insights を使用する
前提条件として、こちらの記事を読むことをおすすめします。
C# で開発した PowerShell モジュールに Application Insights を導入する場合、PowerShell はコンソールアプリと考えることができます。そのため、Application Insights については以下の記事の手順に従って導入できます。
コード例は次のとおりです。
[Cmdlet("Invoke", "SampleApplication")]
public class SampleApplicationCommand : PSCmdlet
{
private readonly ServiceProvider ServiceProvider = new ServiceCollection()
.AddApplicationInsightsTelemetryWorkerService("{{instrumentation-key}}")
.BuildServiceProvider();
protected override void ProcessRecord()
{
var telemetryClient = ServiceProvider.GetService<TelemetryClient>();
try
{
telemetryClient.TrackEvent(nameof(SampleApplicationCommand));
}
catch (Exception ex)
{
telemetryClient.TrackException(ex);
}
finally
{
telemetryClient.Flush();
}
}
}
ここで気になるのは Application Insights のバージョンです。最初の記事を読んでいただくとわかりますが、PowerShell モジュールが読み込む外部 DLL のバージョンは PowerShell 本体 (System.Management.Automation.dll) に依存します。PowerShell 7 以降では Application Insights を使ってテレメトリを送信する機能が組み込まれています。Application Insights の DLL も PowerShell 本体によって読み込み済みです。そのため、新しいバージョンの DLL を読み込もうとすると失敗します。特に公開情報はありませんが、リリース情報から調べると Application Insights のバージョンは 2.13.1 です。
PowerShell 6 については Application Insights を使っておらず、すでにサポートも終了しているため考慮しなくて問題ありません。したがって、2.13.1 を使えば解決できます。
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.13.1" />
</ItemGroup>
ここまでが .NET Core ベースの PowerShell の話です。なお、PowerShell には Windows にバンドルされた Windows PowerShell (5.1) もあります。Application Insights 2.13.1 で作成した PowerShell モジュールを Windows PowerShell で実行するとエラーになります。
Invoke-SampleApplication : ファイルまたはアセンブリ 'Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。
発生場所 行:1 文字:1
+ Invoke-SampleApplication
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], FileNotFoundException
+ FullyQualifiedErrorId : System.IO.FileNotFoundException
このため、Microsoft.ApplicationInsights.WorkerService のバージョンを下げていくしかありません。しかし、NuGet で公開されているもっとも古いバージョンでも解決できません。これは AddApplicationInsightsTelemetryWorkerService メソッドを使うことが問題のためです。したがって、Microsoft.ApplicationInsights.WorkerService そのものを利用しない方法を検討する必要があります。幸い、コードは GitHub に公開されているため、同じことを実装すれば問題ありません。
先ほどのコードを修正します。
[Cmdlet("Invoke", "SampleApplication")]
public class SampleApplicationCommand : PSCmdlet
{
private readonly ServiceProvider ServiceProvider = new ServiceCollection()
.AddSingleton(provider => new TelemetryConfiguration("{{instrumentation-key}}"))
.AddSingleton<ITelemetryChannel, InMemoryChannel>()
.AddSingleton<TelemetryClient>()
.BuildServiceProvider();
protected override void ProcessRecord()
{
var telemetryClient = ServiceProvider.GetService<TelemetryClient>();
try
{
telemetryClient.TrackEvent(nameof(SampleApplicationCommand));
}
catch (Exception ex)
{
telemetryClient.TrackException(ex);
}
finally
{
telemetryClient.Flush();
}
}
}
念のため、Microsoft.ApplicationInsights.WorkerService ではなく Microsoft.ApplicationInsights を参照するようにします。
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.13.1" />
</ItemGroup>
本来であれば PowerShell モジュールごとに任意のバージョンの DLL を呼び出せるのが理想ですが、.NET Core ではアプリケーションドメインの分離がサポートされていません。そのため、PowerShell のこの仕様はやむを得ない部分もありますが、正直なところ非常に大変です。
Discussion