在PowerShell中,我试图启动一个进程,并等待直到该进程退出,或者脚本从命名管道中获得信号。尽管命名管道组件可以正常工作,但是当脚本被阻止时,代码无法处理事件。这只是事件相关代码的示例:
$ErroractionPreference = "Stop"
# launch process with the appropriate args.
$p = [System.Diagnostics.Process]::new()
$p.StartInfo.FileName = "notepad.exe"
$p.StartInfo.Arguments = $null
$p.EnableRaisingEvents = $true $p.Start()
# create a task completion source
$tcs = [System.Threading.Tasks.TaskCompletionSource[Boolean]]::new()
Register-ObjectEvent -InputObject $p -EventName Exited `
-MessageData $tcs `
-action {
$Event.MessageData.SetResult($true)
}
# wait for the program to exit
$processTask = $tcs.Task
# this deadlocks
$processTask.Wait()
是否存在通过PowerShell的作业系统解决该问题的正确方法,还是通过手动启动另一个等待该过程退出的C#任务来解决该问题,从而使脚本能够在发生任何一个事件后恢复运行?
作为参考,这是更完整的脚本(包括对流程事件或命名管道的等待):
$ErroractionPreference = "Stop"
#inbound pipe
$pipelistener = [System.IO.Pipes.NamedPipeServerStream]::new("testPipe",1)
# launch process with the appropriate args.
$p = [System.Diagnostics.Process]::new()
$p.StartInfo.FileName = "notepad.exe"
$p.StartInfo.Arguments = $null
$p.EnableRaisingEvents = $true
$p.Start()
# I would normally solve this using a TaskCompletionSource
# in C#,and have it fire off the process's exited event.
# create a task completion source
$tcs = [System.Threading.Tasks.TaskCompletionSource[Boolean]]::new()
Register-ObjectEvent -InputObject $p -EventName Exited `
-MessageData $tcs `
-action {
$Event.MessageData.SetResult($true)
}
# wait for the program to exit,or for pipe signal
try {
$pipetask = $pipelistener.WaitForConnectionAsync()
$processTask = $tcs.Task
while ($true)
{
echo "Launched Process,waiting for sequence to complete..."
# this works,but not instantly - the timeout appears to allow the
# event to process.
#$res = [System.Threading.Tasks.Task]::WaitAny(@($processTask,$pipetask),10000)
# this does not.
$res = [System.Threading.Tasks.Task]::WaitAny(@($processTask,$pipetask))
echo "Got wait result: $res"
if ($pipetask.IsCompleted) {
echo "Got pipe connection"
$sr = [System.IO.StreamReader]::new($pipelistener)
$msg = $sr.ReadToEnd()
echo "Pipe sent: $msg"
break
}
if ($processTask.IsCompleted) {
echo "Process completed."
break
}
}
}
finally {
$pipelistener.Dispose()
}