なぜ C# なのか?
PowerShell は、プログラミング言語としての側面と、手軽なシェルとしての側面を持っています。このバランスは奇跡的ともいえるくらい絶妙なものですが、やはり本業はシェルということで、C# や VisualBasic.NET、JScript.NET などの本格的プログラミング言語に比べると、いくらか省略された機能もあります。
それらの機能が欲しいときには、本格的プログラミング言語に頼るのが最も簡単です。中でも C# は、.NET Framework のために生まれた言語であり、PowerShell の使う .NET Framework と高い親和性を持っています。
なぜすべて C# でやらないのか?
単に C# ソースをコンパイルして実行ファイルを作り、それを実行したのでは、コンパイルの工程が増えます。また、そのプログラムとは文字列しかやり取りすることができません。
インタプリタのごとく、C# のソースを与えれば即座に動き、また、文字列以外のオブジェクトをもやり取りすることができる、そんなことが PowerShell では可能です。
ダウンロード
以下より、C# ソースを実行するスクリプトがダウンロードできます。
用例
用例1: Hello World
PS> Invoke-Cs -Source @"
>> class Program
>> {
>> static string Main()
>> {
>> return "Hello World!";
>> }
>> }
>> "@
>> Hello World!
用例2: 引数
PS> Get-Content Add.cs
class Program {
static int Main(int arg1, int arg2)
{
return arg1 + arg2;
}
}
PS> Invoke-CS Add.cs -Argument (5, 15)
20
メモリリークの問題
スクリプト中で他の言語を使うために、よく紹介されているのが、メモリ内に動的アセンブリを作る方法です。今回のスクリプトでも、その方法を使っています。
しかし、これにはひとつ問題があります。変数と違い、動的アセンブリは、ガベージコレクションされません。それどころか、一度作られた動的アセンブリは、PowerShell を終了するまで解放する手段がありません。つまり、そういうスクリプトは何度も呼び出すことによって、その度にメモリリークしていくのです。
以下のコマンドは、現在ロードされているアセンブリのリストを出力します。
PS> [AppDomain]::CurrentDomain.GetAssemblies()
これで調べてみると、 Invoke-Cs.ps1 を実行するたびに無名のアセンブリが追加されていることがわかります。もちろん、PowerShell を終了すれば解放されるので、通常の使い方では問題ないはずですが、常に例外と安全を考慮する、そして「使用上の注意」を減らすのが、正しい開発者の道でしょう。次回は、用途は多少制限されますが、メモリリークのないスクリプトをご紹介する予定です。