Another PowerShell egg-timer (using events)
Recording a learning exercise for how PowerShell handles events, and how to communicate into event handlers
Note that every registered event must be unregistered (otherwise running the script leaves droppings in your PowerShell session in the form of those claims on events). The events that are handled -- the timer 250ms wake-ups -- are consumed by being handled; but the one that is merely waited on remains latched after triggering the wait to release and must be explicitly cleared.
Additional AV frills would be the same as any of the polling loop timer examples out there.
<# | |
.SYNOPSIS | |
This script provides simple egg-timer like functionality. | |
.DESCRIPTION | |
This script counts down a time interval then speaks some text | |
.NOTES | |
File Name : Run-Timer.ps1 | |
Requires : PowerShell Version 2.0 | |
.PARAMETER Minutes | |
Delay in minutes | |
.PARAMETER Seconds | |
Additional delay in seconds | |
.PARAMETER Text | |
What to say at the end of the time | |
.PARAMETER Help | |
Show this help text. | |
#> | |
param ( | |
[ValidateRange(0,59)] [int] $Minutes, | |
[ValidateRange(0,59)] [int] $Seconds, | |
[string] $Text="It is time", | |
[switch] $Help) | |
if ($help) | |
{ | |
Get-Help $MyInvocation.MyCommand.Definition | |
return | |
} | |
$delay = new-object "system.timespan" @(0, $Minutes, $Seconds) | |
$fireAt = [System.DateTime]::UtcNow + $delay | |
Write-Host "Requested alarm time = `t$fireAt" | |
# Do the heavy lifting up front | |
$Voice = new-object -com SAPI.SpVoice | |
$Voice.Rate = -5 | |
$timer = new-object "system.timers.timer" @(250.0) | |
$timer.autoreset = $true | |
$handler = { | |
# extract arguments (no closures here) | |
$fireAt = $Event.MessageData | |
$timer = $Sender | |
# round time to wait to integer seconds and display | |
$delta = $fireAt - [System.DateTime]::UtcNow | |
$delta = new-object "system.timespan" @(0, $delta.Minutes, [System.Math]::Round($delta.Seconds)) | |
[System.Console]::Write("$delta`r") | |
# After the time allotted, kill the timer | |
if ([System.DateTime]::UtcNow -gt $fireAt) { | |
$timer.enabled = $false | |
$timer.autoreset = $false | |
$timer.Dispose() | |
} | |
} | |
Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier "Timer.Elapsed" -Action $handler -MessageData $fireAt | Out-Null | |
Register-ObjectEvent -InputObject $timer -EventName Disposed -SourceIdentifier "Timer.Disposed" | |
$timer.Start() | |
# Wait until done | |
if (-not (Wait-Event "Timer.Disposed" -Timeout 3600 )) { | |
Write-Host "Timed out" | |
$timer.Stop() | |
$timer.Dispose() | |
} else { | |
Write-Host "Completed" | |
} | |
Write-Host "Actual alarm time = `t$([System.DateTime]::UtcNow)" | |
# Tidy event registrations and event queue | |
# The Elapsed events are spent in the handler | |
# but the one we wait on must be explicitly cleared | |
Remove-Event "Timer.Disposed" | |
Unregister-Event "Timer.Elapsed" | |
Unregister-Event "Timer.Disposed" | |
#audible alarm | |
$Voice.Speak($Text) | Out-Null | |
Write-Host "`r`nDone" |
No comments :
Post a Comment