ちょっと不便だと感じたので、PowerShell関数を任意のデリゲートにキャストするコマンドレットを作成しました。
【 0. 目次 】
1. Download
2. 解説
3. 使用例
【 1. Download 】
このコマンドレットは、YokoKen.PowerShell.Utilityというスナップインに含まれています。このスナップインは以下の記事にて公開しています。
YokoKen.PowerShell.Utility
【 2. 解説 】
[ 2.1 コマンド名 ]
このコマンドレットには、ConvertTo-Delegateという名前が付けられています。
[ 2.2 概要 ]
ConvertTo-Delegateコマンドレットは、指定したPowerShell関数 ( = ScriptBlockオブジェクト ) を、指定したデリゲートにキャストします。指定できるデリゲートに制限はありません。
[ 2.3 構文 ]
ConvertTo-Delegateコマンドレットの構文は以下のようになっています。
ConvertTo-Delegate [-Target] <System.Management.Automation.ScriptBlock> [-DelegateType] <System.Type> [[-ErrorNotifiedByDialog] <System.Boolean>]
[ パラメータ ]
・Target <System.Management.Automation.ScriptBlock>
デリゲートにキャストするPowerShell関数を指定します。Targetパラメータに指定できるPowerShell関数に制限はありません。PowerShell関数の戻り値が、DelegateTypeパラメータに指定したデリゲートに定義されている戻り値の型と異なる場合でも、問題なく実行できます。
必須 : true
位置 : 1
既定値 : -
パイプライン入力を許可する : true (ByValue)
ワイルドカード文字を許可する : false
Nullを許可する : false
・DelegateType <System.Type>
PowerShell関数をキャストするデリゲートを指定します。DelegateTypeパラメータには、デリゲート ( = MulticastDelegate派生型 ) を指定してください。それ以外では例外が発生します。
必須 : true
位置 : 2
既定値 : -
パイプライン入力を許可する : false
ワイルドカード文字を許可する : false
Nullを許可する : false
・ErrorNotifiedByDialog <System.Boolean>
デリゲートオブジェクトとして実行されたPowerShell関数が、実行中に例外をスローした時、例外の情報をダイアログで通知するかどうかを指定します。falseを指定した場合は、PowerShellのホストアプリケーションから、通常通りに通知されます。規定値はfalseです。
必須 : false
位置 : 3
既定値 : false
パイプライン入力を許可する : false
ワイルドカード文字を許可する : false
Nullを許可する : false
[ 2.4 詳細 ]
・デリゲートオブジェクトとして呼び出されたPowerShell関数の引数
デリゲートオブジェクトとして呼び出されたPowerShell関数で、引数を受け取ることができます。ただし、$Args変数から取得する以外の手段で引数を取得することはできません。例えば、以下の例では引数を取得できず、例外が発生します。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form1 = New-Object "System.Windows.Forms.Form";
function form1_Click([object] $sender, [EventArgs] $e)
{
# デリゲートオブジェクトとして呼び出されると、$senderにはNullが入っています。
([System.Windows.Forms.Form]$sender).Text = "Hoge";
}
$clickHandler = ConvertTo-Delegate $Function:form1_Click System.EventHandler;
$form1.Add_Click($clickHandler);
[System.Windows.Forms.Application]::Run($form1);
正しく動作させるには、以下のように記述します。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form1 = New-Object "System.Windows.Forms.Form";
function form1_Click
{
# デリゲートオブジェクトとして呼び出されても、$Argsの各要素には適切な値が入っています。
([System.Windows.Forms.Form]$Args[0]).Text = "Hoge";
}
$clickHandler = ConvertTo-Delegate $Function:form1_Click System.EventHandler;
$form1.Add_Click($clickHandler);
[System.Windows.Forms.Application]::Run($form1);
・デリゲートオブジェクトとして呼び出されたPowerShell関数の戻り値
デリゲートオブジェクトとして呼び出されたPowerShell関数は、以下の条件を満たすことで、戻り値を返すことができます。
条件 : PowerShell関数の戻り値が、キャストしたデリゲートに定義されている戻り値の型にキャストできること。
条件を満たさない場合でも問題なく実行できますが、戻り値はNullとなります。 ( キャストしたデリゲートに定義されている戻り値の型がVoid型の場合は、何も返しません。 )
例えば、以下の例では戻り値はNullとなります。 ( ResolveEventHandlerデリゲートの戻り値の型は、System.Reflection.Assemblyクラスです。 )
# ResolveEventHandlerにキャストして呼び出されたとき、戻り値はNullとなります。
$func1 = ConvertTo-Delegate {"test";} ResolveEventHandler;
$func1.Invoke($(), $());
以下の例のように、PowerShell関数の戻り値が、デリゲートに定義されている戻り値の型にキャストできる場合は、戻り値が返されます。
# ResolveEventHandlerにキャストして呼び出されたとき、戻り値は適切な値となります。
$func1 = ConvertTo-Delegate {[System.Reflection.Assembly]::GetExecutingAssembly();} ResolveEventHandler;
$func1.Invoke($(), $());
【 3. 使用例 】
・イベントハンドラ
以下のコードは、フォームが閉じられる際に、終了確認ダイアログを表示し、「いいえ」が選択された場合に終了をキャンセルさせる例です。 ( コード中で使用しているRun-Formコマンドレットについては、こちらの記事を参照してください。 )
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$form = New-Object "System.Windows.Forms.Form";
$formClosingHandlScript =
{
$sender = [System.Windows.Forms.Form]$Args[0];
$e = [System.Windows.Forms.FormClosingEventArgs]$Args[1];
$messageBoxButton = [System.Windows.Forms.MessageBoxButtons]::YesNo;
$messageBoxIcon = [System.Windows.Forms.MessageBoxIcon]::Question;
$dialogResult = [System.Windows.Forms.MessageBox]::Show($sender, "終了しますか?", "確認", $messageBoxButton, $messageBoxIcon);
if ($dialogResult -ne [System.Windows.Forms.DialogResult]::Yes)
{
$e.Cancel = $True;
}
};
$formClosingHandler = ConvertTo-Delegate $formClosingHandlScript System.Windows.Forms.FormClosingEventHandler;
$form.Add_FormClosing($formClosingHandler);
Run-Form $form;
・Threadクラスによるマルチスレッド
以下の例のように、Threadクラスを用いることで、ThreadStartデリゲートにキャストしたPowerShell関数を別スレッド上で実行させることができます。
ただし、別スレッドでの実行を目的にPowerShell関数をデリゲートにキャストする場合、ErrorNotifiedByDialogパラメータには必ず Trueを指定してください。Trueを指定しないと、別スレッド上でのPowerShell関数の実行中に例外が発生した場合に、例外が適切に処理されないため PowerShellが強制終了してしまいます。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$messageBoxClass = [System.Windows.Forms.MessageBox];
$process = ConvertTo-Delegate {[void] $messageBoxClass::Show("test");} System.Threading.ThreadStart $True;
$newThread = New-Object System.Threading.Thread $process;
$newThread.Start();
【 0. 目次 】
1. Download
2. 解説
3. 使用例
【 1. Download 】
このコマンドレットは、YokoKen.PowerShell.Utilityというスナップインに含まれています。このスナップインは以下の記事にて公開しています。
YokoKen.PowerShell.Utility
【 2. 解説 】
[ 2.1 コマンド名 ]
このコマンドレットには、Run-Formという名前が付けられています。
[ 2.2 概要 ]
Run-Formコマンドレットは、指定したフォームオブジェクトを、別スレッド上で表示します。別スレッド上で表示されるため、表示中もPowerShellからフォームを操作することができます。
[ 2.3 構文 ]
Run-Formコマンドレットの構文は以下のようになっています。
Run-Form [-Target] <System.Windows.Forms.Form>
[ パラメータ ]
・Target <System.Windows.Forms.Form>
対象となるフォームオブジェクトを指定します。
必須 : true
位置 : 1
既定値 : -
パイプライン入力を許可する : true (ByValue)
ワイルドカード文字を許可する : false
Nullを許可する : false
【 3. 使用例 】
以下の例のコマンドを実行すると、フォームが表示され、PowerShellが入力待機状態となります。
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms");
$sampleForm = New-Object "System.Windows.Forms.Form";
$helloButton = New-Object "System.Windows.Forms.Button";
$helloButton.Text = "Click";
$helloButton.Location = New-Object "System.Drawing.Point" (50, 50);
$helloButton.Add_Click({[System.Windows.Forms.MessageBox]::Show("Hello Hoge !")});
$sampleForm.Controls.Add($helloButton);
# コマンドレット実行
Run-Form $sampleForm;
フォーム表示後、以下の例のコマンドを実行すると、PowerShellからフォームを操作できることが確認できます。
# フォームを最前面に固定
$sampleForm.TopMost = $True;
# フォームのタイトルを設定
$sampleForm.Text = "Sample Form";
# フォームの不透明度を設定
$sampleForm.Opacity = 0.5;
# フォームの位置を設定
$sampleForm.Location = New-Object "System.Drawing.Point" (0, 0);
フォーム表示後のコントロールの追加は、以下のように、Invokeメソッドを使用して行います。
Invokeメソッドを使用しない場合、エラーとなってしまうので注意してください。
なお、以下の例では、同じスナップインに含まれているConvertTo-Delegateコマンドレットを使用して、PowerShell関数をMethodInvokerにキャストしています。ConvertTo-Delegateコマンドレットに関しては、こちらの記事を参照してください。
$exitButton = New-Object "System.Windows.Forms.Button";
$exitButton.Text = "Exit";
$exitButton.Location = New-Object "System.Drawing.Point" (100, 100);
$exitButton.Add_Click({$sampleForm.Close()});
$sampleForm.Invoke((ConvertTo-Delegate {$sampleForm.Controls.Add($exitButton)} System.Windows.Forms.MethodInvoker))
フォームを閉じる時は、フォームの閉じるボタンから閉じることも、PowerShellから以下のコマンドを実行して閉じることもできます。
# フォームの破棄
$sampleForm.Dispose();
自作のPowerShell ユーティリティ コマンドレットをまとめたスナップインです。新しいコマンドレットを作成するたびに、このスナップインに追加していきます。 ( 各コマンドレットの作成日は、コマンドレット一覧を参照してください。 )
【 0. 目次 】
1. Download
2. インストール方法
3. 使い方
4. コマンドレット一覧
5. アンインストール方法
【 1. Download 】
以下のリンクをクリックするとDownloadページへ移動するので、移動先からダウンロードしてください。
YokoKen.PowerShell.Utility.dll ( YKPSUtility.zip )
ソース ( YKPSUtility_src.zip )
【 2. インストール方法 】
[ 2.1 解凍 ]
ダウンロードしたファイル ( YKPSUtility.zip ) を、解凍します。
[ 2.2 配置 ]
PowerShell のインストールフォルダ ( 通常はC:\Windows\system32\windowspowershell ) に、SnapInというフォルダを作成 ( ※1 ) し、解凍されたYokoKen.PowerShell.Utility.dllを置きます。
[ 2.3 インストール ]
以下のコマンドをPowerShellで実行します。
&"$env:windir/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe" ($PSHome + "\SnapIn\YokoKen.PowerShell.Utility.dll");
※1 : 違うフォルダでも構いませんが、違うフォルダにする場合、 [ 2.3 インストール ] のコマンドで指定するパスもそれに合わせて変更してください。
【 3. 使い方 】
このスナップインを使うには、PowerShellの起動のたびに、以下のコマンドを実行してスナップイン登録する必要があります。
Add-PSSnapin "YokoKen.PowerShell.Utility";
【 4. コマンドレット一覧 】
このスナップインには以下のコマンドレットが含まれています。コマンドレット名をクリックすると、詳細記事に移動します。
Run-Form ( 作成日:2006/12/02 )
Run-Formコマンドレットは、指定したフォームオブジェクトを、別スレッド上で表示します。別スレッド上で表示されるため、PowerShellからフォームを操作することができます。
Convert-Delegate ( 作成日:2006/12/14 )
Convert-Delegateコマンドレットは、指定したPowerShell関数を、指定したデリゲート型にキャストします。指定できるデリゲート型に制限はありません。
【 5. アンインストール方法 】
以下のコマンド ( ※2 ) をPowerShellで実行します。
$deploymentPath = $PSHome + "\SnapIn\YokoKen.PowerShell.Utility.dll";
&"$env:windir/Microsoft.NET/Framework/v2.0.50727/InstallUtil.exe" -u $deploymentPath;
Remove-Item $deploymentPath;
※2 : [ 2.2 配置 ] ,[ 2.3 インストール ] で、違うフォルダにインストールした場合、コマンドで指定するパスをそれに合わせて変更してください。