Friday, November 18, 2011

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"
view raw gistfile1.ps1 hosted with ❤ by GitHub


No comments :