我在powershell中使用事件相关命令,当我注册一个对象事件并等待它时,我的脚本将被wait-event
调用暂停。
根据文档,
The Wait-Event cmdlet suspends execution of a script or
function until a particular event is raised. Execution
resumes when the event is detected.
To cancel the wait, press CTRL+C.
但是我发现的是,当我在powershell控制台按Ctrl-C时,整个脚本结束而不是wait-event
调用,我认为wait-event
调用可能返回$null值。
我不知道我的理解是否有问题,所以希望任何人都能分享更多的想法。
$port = New-Object System.IO.Ports.SerialPort COM5,115200,None,8,One
$port.Open()
$subscription = Register-ObjectEvent -InputObject $port -EventName DataReceived -SourceIdentifier "DataReceived"
while($true)
{
$event = Wait-Event -SourceIdentifier "DataReceived"
#
# So how can I check if user press the Control-C to cancel wait-event
#
[System.IO.Ports.SerialPort]$sp = $event.Sender;
$line = $sp.ReadExisting();
Write-Host $event.EventIdentifier;
Write-Host $line;
Remove-Event -EventIdentifier $event.EventIdentifier;
}
Unregister-Event -SourceIdentifier "DataReceived"
$port.Close()
——编辑——
谢谢你的回答,但我想指出一些我已经尝试过的已知解决方案。
[console]::TreatControlCAsInput = $true
if ([console]::KeyAvailable)
{
$key = [system.console]::readkey($true)
if (($key.modifiers -band [consolemodifiers]"control") -and ($key.key -eq "C"))
{
"Terminating..."
break
}
}
这是解决常见Control-C
场景的好方法,但问题是我的应用程序被wait-event
调用暂停,所以我没有更改来检查键输入。
特别是,当我通过[console]::TreatControlCAsInput = $true
为控制台启用Ctrl C时,Control-C将无法再取消Wait-Event
,这也是一个问题。
这是一个很好的例子,你可以尝试一下(我重写了一个可用的测试):
$timer = New-Object System.Timers.Timer
[Console]::TreatControlCAsInput = $true;
$subscription = Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier "TimeElapsed"
$event = Wait-Event -SourceIdentifier "DataReceived"
Write-Host "User Cancelled"
Unregister-Event -SubscriptionId $subscription.Id
您可以运行这个脚本,使用或不使用[Console]::....
进行测试。
您可能必须调用[console]::TreatControlCAsInput = $true
来告知(Ctrl+C)被视为普通输入,并使用类似循环中的语句:
if ([console]::KeyAvailable)
{
$key = [system.console]::readkey($true)
if (($key.modifiers -band [consolemodifiers]"control") -and ($key.key -eq "C"))
{
"Terminating..."
break
}
}
Wait-Event不处理Ctrl+C, PowerShell主机(控制台主机)通过停止脚本来处理Ctrl+C。
您可以使用Wait-Event指定超时时间,并在超时后检查是否有按键。试试以下命令:
$timer = New-Object System.Timers.Timer
$subscription = Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier TimeElapsed
try
{
$oldTreatControlCAsInput = [Console]::TreatControlCAsInput
[Console]::TreatControlCAsInput = $true
Write-Host -NoNewline "Waiting for event "
do
{
$event = Wait-Event -SourceIdentifier DataReceived -Timeout 2
if ($null -eq $event -and [Console]::KeyAvailable)
{
$key = [Console]::ReadKey($true)
if ($key.KeyChar -eq 3)
{
Write-Host "Cancelled"
break
}
}
Write-Host -NoNewline "."
} while ($null -eq $event)
}
finally
{
[Console]::TreatControlCAsInput = $oldTreatControlCAsInput
Unregister-Event -SourceIdentifier TimeElapsed
}
最小超时为1秒,因此您可能会看到Ctrl+C和循环停止之间的短暂延迟