読者です 読者をやめる 読者になる 読者になる

qshinoの日記

Powershell関係と徒然なこと

Start-Process by PowerShell

Start-Process使用法

全体フロー

  1. $proc Start-process -passThru
  2. $ejob = Register-ObjectEvent -action $action -MessageData $job
  3. action: unregister-event
  4. 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個の自動変数が使える。

  1. $Sender
  2. $Event
  3. $EventArgs
  4. $Args
  5. $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

参考

https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/start-process