Start-Process by PowerShell
Start-Process使用法
全体フロー
- $proc Start-process -passThru
- $ejob = Register-ObjectEvent -action $action -MessageData $job
- action: unregister-event
- remove-job $ejob
PowerShellからの外部コンソールアプリを非同期起動する際にStart-Processを使う方法。
まずは、パラメータから、
Start-Process起動パラメータ
Start-Process [-FilePath] <String> [[-ArgumentList] <String[]>] [-Credential <PSCredential>] [-WorkingDirectory <String>] [-LoadUserProfile] [-NoNewWindow] [-PassThru] [-RedirectStandardError <String>] [-RedirectStandardInput <String>] [-RedirectStandardOutput <String>] [-WindowStyle <ProcessWindowStyle>] [-Wait] [-UseNewEnvironment] [<CommonParameters>]
たくさんありすぎて迷うが、基本は下記。
$proc = Start-Process 起動プログラム(フルパス推奨) -ArgumentList $ag -WorkingDirectory $wd -PassThru
-PassThruがあると、Process型を返すが、ないと何も返さない。次のイベントハンドラ登録に戻り値$procを使うので忘れずに。
$ag は配列を渡せるが、配列を結合した文字列としてプロセスに渡しているので、文字列として渡すと変換処理に悩まされない。
-NoNewWindowを渡していないのでコンソールウインドウが表示される。
標準入出力を指定していないので、コンソールに出力される。
非同期なので終了イベント登録
非同期起動のため制御は直ぐに戻る。以後は起動側をメイン、起動されたアプリをサブ、イベント処理をハンドラと呼ぶ。
$exited = Register-ObjectEvent $proc -EventName -MessageData $data -action $action
イベント登録によりハンドラ$exitedがジョブとして登録される。登録されたハンドラは下記にて確認できる。
Get-EventSubscriber
ハンドラ$actionでは下記5個の自動変数が使える。
- $Sender
- $Event
- $EventArgs
- $Args
- $EventSubscriber
$EventはPSEventArgs型、$Senderはイベント発行元=$Event.Sender, $EventArgsは元イベントの引数=$Event.SourceEventArgs, $Argsはハンドラへの引数=$Event.SourceArgs=($Sender,$EventArgs), $EventSubscriberはイベントハンドラ。ユニークなのは、$Eventと$EventSubscriberの二つ。後は利便性のための写し?
イベント登録時の$dataは、$Event.MessageDataでアクセスできる。
整理すると、使えるのは下記の4点。
- $Sender
- $EventArgs ; イベントが定義
- $EventSubscriber
- $Event.MessageData ; ハンドラ登録時定義
$EventはPSEventArgsオブジェクト。下記がプロパティ一覧。
PSEventArgs
- ComputerName
- EventIdentifier
- RunSpaceId
- SourceIdentifier
- Sender
- SourceArgs
- SourceEventArgs
- MessageData
- TimeGenerated
イベントハンドラの$actionではイベントを削除する。
$action = {
Unregister-Event $EventSubscriber.name
[Diagnostics.Process]$proc = $Sender
$ec = $proc.ExitCode
$data = $Event.MessageData
Write-Host "Exit Code: $ec : $data"
}
イベントジョブの廃棄
処理完了or中断時に、$procとイベントジョブ$exitedをメインで廃棄する。ただし、ハンドラが呼ばれなかった場合(サブがストールした時など)を顧慮し、残っていればハンドラも削除する。
function dispose_procs( $proc, $exited){
if ( $exited -and ($exited -is [system.management.automation.PSEventJoB])){
Get-EventSubscriber| Where-Object { $_.SourceIdentifier -eq $exited.name } | Unregister-Event -force
Remove-Job $exited
}
if( $proc -and ($proc -is [Diagnostics.Process]])){
if( -not $proc.hasExited ){
$proc.kill()
}
$proc.dispose()
}
}
dispose_procs $proc $exited
Remove-Variable proc
Remove-Variable exited