PowerShellのバイナリモジュールをF#で書こう!

この記事はPowerShell Advent Calendar 2014の5日めの記事です。 F#の文法は非常に簡潔で、短いタイプ量でコードを記述できるようになっています。このため、いったんF#のコーディングになれてしまうとC#でのコーディングが少し億劫になってしまいがちです(異論は認めません)。PowerShell用にバイナリーモジュールを書くときも同様です。できればF#で書きたい! バイナリモジュールをF#で書くことそのもはそれほどむつかしくありません。C#で書くときと同じようにPSCmdletを継承したクラスを定義してアセンブリを生成するだけです(C#によるバイナリモジュールの生成の詳細については、ぎたぱそ先生の「PowerShell のモジュール詳解とモジュールへのコマンドレット配置手法を考える」をご覧ください)。 以下は、パイプラインを通じて与えられた整数の中から最大値を返すコマンドレットSelect-MaxをF#で定義した例です。 namespace sample open System.Management.Automation [<Cmdlet(“Select”, “Max”)>] type SelectMax() = inherit PSCmdlet() [<DefaultValue>] val mutable private result : int [<DefaultValue>] val mutable private _InputValue : int [<Parameter(Mandatory=false,ValueFromPipeline=true)>] member public this.InputValue with get() = this._InputValue and set value = this._InputValue <- value override this.BeginProcessing() = do this.result <- 0…

0

パイプラインのオブジェクトをのぞき見する

まずはスクリプトそのものから。 function Watch-PipeLine { param ( [Parameter(Mandatory=$true)] [ScriptBlock] $ScriptBlock, [Parameter(Mandatory=$true,ValueFromPipeLine=$true)] [PSObject] $Object ) process { $Object | Foreach $ScriptBlock $Object }}New-Alias Watch Watch-PipeLine  これを使うと、パイプラインを流れるオブジェクトを簡単にのぞき見できます。たとえば以下のようなファイル名の一覧を取得している処理があったとしましょう。 $logFiles = dir -Recurse Logs | Where PSIsContainer -eq $false | Foreach Name | Sort-Object ここでファイルサイズを合計もとりたいという要望があったので、以下のように書き換えたとします。 $total = 0$logFiles = dir -Recurse Logs | Where PSIsContainer -eq $false | Foreach {…

0

New-Module を用いてカスタムオブジェクトを生成する

PowerShell でカスタムオブジェクトを定義する一番ストレートな方法はハッシュテーブルと Add-Member を組み合わせるパターンでしょう。 $custom = [pscustomobject] @{ Message = ‘Hello, world!’ } |  Add-Member -PassThru -MemberType ScriptMethod -Name Hello -Value {    Write-Host -Foreground Green $this.Message  } この例は、Message というプロパティと、その値をホストに緑色で表示する Hello というメソッドをもったカスタムオブジェクトを定義しています。少し複雑な処理をするときなどは、このようなカスタムオブジェクトを積極的に活用する機会が多くなりますが、いかんせん記述が煩雑なことに加えて、メンバーのスコープを制御できないという欠点があります。 そんな場合は、動的モジュールを利用してカスタムオブジェクトを定義するといいですよ、というのが今回のネタです。 動的モジュールとは、その名のとおり、メモリ空間内に動的に生成されるモジュールのことで、New-Module を用いて生成します。試しに、動的モジュールをひとつ定義してみましょう。 New-Module {  $Message = ‘Hello, world!’  function Hello { Write-Host -Foreground Green $Message }} これを実行するとモジュールが動的に生成され、モジュール内で定義したメンバーがセッションにインポートされ、利用可能になります。 これだけだと動的にモジュールを定義できました、というだけの話であまり面白くありません。興味深くなるのは New-Module に -AsCustomObject オプションを指定してからです。 $custom = New-Module …

0

XDocument を用いて XML を処理する

スクリプトを書いていると、たびたび XML のファイルを作成したり、あるいは変更したりする機会があります。例えば、XML 形式の設定ファイルを自動生成したり、その設定ファイルを更新するようなケースです。 PowerShell で標準で用意されている XML のサポートは、DOM をベースにした XmlDocument クラスを用いるものです。当然ながら、この仕組みを用いてスクリプトを書くことに全然問題はありません。 しかし、シンプルかつよりスマートな System.XML.Linq が使える現在、PowerShell ベースとはいえ今更 DOM ベースの XmlDocument を使うのは、少し心理的に抵抗がある人もいるでしょう(例えば筆者)。XmlDocument と XDocument で、機能的に大きな違いはないのですが、XML 標準の DOM という考え方には幾分クセがあり、XmlDocument のその独特の使用方法に馴染むまで少しムズムズする可能性があります(ちなみに私は10年来ずっとムズムズしたままです)。 そういうわけで、XDocument を手軽に扱うための PowerShell モジュールを作ってみました(最後にソースを貼り付けてあります)、というのが今回のお題です。基本的にはコンストラクターをラップしたコマンドレットが中心で、以下のような形で使うことを想定しています。 $doc = New-XDocument ( `   New-XElement users `     (New-XElement user (New-XAttribute name ichiro)) `     (New-XElement user (New-XAttribute name andrej)) ` ) これは新規に以下のような…

0