PowerShellからC#を実行する

PowerShell 構文を使って .NET のライブラリ使いながらスクリプト書と多少面倒な時があり C# で書けないかと思ったのでそのやり方の紹介です。PowerShell の中で C# のコードを書いてスクリプトを実行する方法の紹介です。

また別のところで作成した .NET の DLL 内のクラス、メソッドを呼び出してみたいと思います。

確認環境

  • Windows11
  • VisualStudio2022
  • .NET Core 3.1

PowerShellにC#のコードを書く

先ず PowerShell から C# のコードを実行する方法です。

以下のように指定すれば普通に C# のコードが PowerShell 上に記述できます。

# sample1.ps1

# コードをHere-String(ヒアストリング)という形式で記述する
$source =  @"
using System;

public static class SampleClass
{
    public static string Foo(string message, int count)
    {
        string[] result = new string[count];
        for (int i = 0; i < count; i++)
        {
            result[i] = message;
        }
        return string.Join(", ", result);
    }
}
"@
Add-Type -TypeDefinition $source
[SampleClass]::Foo("OK", 3);
#> OK, OK, OK

古いバージョンでは使えないらしいですが、まぁ今現在気にすることは無いでしょう。

自作のライブラリの処理を呼び出す

もう少し踏み込んで自作の .NET の DLL の中身を呼び出す方法です。

簡単な呼び出しなら直接 PowerShell でインスタンスを扱ってもいいですが、大抵の場合複数のメソッドを呼び出したりするため DLL 参照を追加して一連の処理を呼び出してみます。

// Sample1.dll
namespace Takap.Sample1
{
    public class SampleClass1
    {
        public string GetString(string message)
        {
            return $"{message}, {message}";
        }
    }
}

// Sample2.dll
namespace Takap.Sample2
{
    public class SampleClass2
    {
        public string GetString(string message, int count)
        {
            return $"[{count}] {message}";
        }
    }
}

上記DLLが以下に配置されているとします。

  • D:\Sample1.dll
  • D:\Sample2.dll

次に PowerShell は以下のように記述します。

# sample2.ps1

$asm = @("D:\Sample1.dll", `
         "D:\Sample2.dll")

Add-Type -Path $asm

$source =  @"
using System;
using Takap.Sample1;
using Takap.Sample2;

public static class Func
{
    public static string Bar(string message, int count)
    {
        var s1 = new SampleClass1();
        string str = s1.GetString(message);

        var s2 = new SampleClass2();
        return s2.GetString(str, count);
    }
}
"@
Add-Type -TypeDefinition $source -ReferencedAssemblies $asm
[Func]::Bar("OK", 3);
# > [3] OK, OK

これくらいならわざわざ C# で書くことは無いですが、参考までに。

大切なのは Add-Type で DLL のパスを指定すれば参照可能になる点ですが、Path と ReferencedAssemblies を両方同じ値で指定が必要です。どちらかが無いとエラーが発生します。

Lib の処理ではライブラリのメソッドを使用して処理を組み立てるだけにしています。Here-Stringで書いたコードはステップでデバッグができないので小さく使うのがポイントかと思います。

まぁ、、C# 書ける環境なら Windows向けの exe 作ったほうがいいんじゃないという話はさておきですね。