我正在尝试运行这示例:
Clear-Host
$timer = [Timers.Timer]::new()
$timer.Interval = 200
$action = {
if($complete -eq 8){
write-host "completed $complete" -ForegroundColor Red
write-host "Timer stopped" -ForegroundColor Red
$timer.stop()
Unregister-Event thetimer
}
}
Register-ObjectEvent -InputObject $timer -EventName elapsed `
–SourceIdentifier thetimer -Action $action
$complete = 0
$timer.Start()
while($true){
Write-Host "Script working: $complete" -ForegroundColor Green
Start-Sleep -m 400
$complete++
}但是当计时器停止时,脚本就瘫痪了。
我做错了什么,怎么解决?
发布于 2021-09-25 17:19:14
- The reason is that **a script block passed to** [**`Register-ObjectEvent`**](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/register-objectevent)**'s** **`-Action`** **parameter runs inside a** _**dynamic module**_**, which sees only the** _**global**_ **scope's variables, not that of any other caller**, such as a script's.-Action 挂起是由在脚本块中调用 注销-事件 引起的。- **Call it from the** _**caller's scope**_ **instead** (i.e. from the same scope where `Register-ObjectEvent` was called).- That the code _hangs_ when called from inside the `-Action` script block (happens up to at least PowerShell 7.1, the version current as of this writing) should be considered a _bug_; it seems to occur when _more events are pending_ at the time `Unregister-Event` is called; the problem has been reported in [GitHub issue #16154](https://github.com/PowerShell/PowerShell/issues/16154)下面是一个自包含的工作示例,您也可以从脚本中调用该示例:
$timer = [Timers.Timer]::new()
$timer.Interval = 200
$action = {
# Note: This script block generally does NOT see the caller's variables.
# Refer to the originating timer object with $Event.Sender or $args[0]
$timer = $Event.Sender
# Get the variable object passed to -MessageData, via $Event.MessageData
$counter = $Event.MessageData.Value
# Note: Since you're only *getting* an *integer* value, you needn't worry
# about thread synchronization.
if ($timer.Enabled -and $counter -ge 8) {
write-host "completed $counter" -ForegroundColor Red
write-host "Timer stopped" -ForegroundColor Red
$timer.stop()
# Do NOT try to call Unregister-Event here - it'll cause a hang.
}
}
# Initialize the counter variable.
$complete = 0
# Get the variable as a variable *object* that can be passed to the -Action
# script block with -MessageData.
$counterVarObject = Get-Variable complete
# Register the event and pass the variable object with -MessageData.
$evtJob = Register-ObjectEvent -InputObject $timer -EventName elapsed `
–SourceIdentifier thetimer `
-Action $action -MessageData $counterVarObject
$timer.Start()
try {
while ($timer.Enabled) { # Loop until the timer stops.
Write-Host "Script working: $complete" -ForegroundColor Green
Start-Sleep -MilliSeconds 400
$complete++
}
}
finally { # This is called even if the loop is aborted with Ctrl-C.
# Remove the event job, which also unregisters the event.
$evtJob | Remove-Job -Force
}https://stackoverflow.com/questions/69327313
复制相似问题