12215

Timer

In this post I showed how to set a count down timer

http://msmvps.com/blogs/richardsiddaway/archive/2011/08/02/a-count-down-timer.aspx

but what if you want to go the other way i.e. see how long something takes

The count down function can be modified

Import-Module ShowUI                        
            
function timegone {            
 $ts = (Get-Date) - $start            
 $time = $ts.ToString() -split "\."            
 if ($ts.Hours -eq 0) {            
   $time[0].Substring(3,5)            
 }            
 else {            
   $time             
 }              
}            
            
            
$start = Get-Date            
            
$windowAttributes = @{            
    WindowStartupLocation = "CenterScreen"            
    SizeToContent = "WidthAndHeight"            
    WindowStyle = "None"            
    Background = "Transparent "                        
            
    On_MouseRightButtonDown = { Close-Control}            
    On_MouseLeftButtonDown  = { $_.Handled = $true;$window.DragMove() }            
    On_Loaded = {            
        Register-PowerShellCommand -ScriptBlock {            
            $window.Content.Content = timegone            
        } -Run -In "0:0:0.5"            
    }            
}                        
            
$labelAttributes = @{            
    Content = timegone            
    FontFamily = "Impact, Arial"            
    FontWeight = 800            
    FontSize = 30            
}                        
            
New-Window @windowAttributes -AllowsTransparency -Show  {            
    Label @labelAttributes -Name Clock -Foreground (            
        LinearGradientBrush $(            
            GradientStop -Color Red    -Offset 1            
            GradientStop -Color Orange -Offset 0.85            
            GradientStop -Color Yellow -Offset 0.7            
            GradientStop -Color Green  -Offset 0.55            
            GradientStop -Color Blue   -Offset 0.4            
            GradientStop -Color Indigo -Offset 0.2            
            GradientStop -Color Violet -Offset 0            
        )            
    )            
}


The main change is that our starting point is now. We then get the current time, subtract our starting point and we have the elapsed time.



Display as before

A count down timer

Last month I started playing with WPF to show how a multi-coloured clock could  be displayed on screen. This was picked up and an easier version was created by Doug Finke using the ShowUI module from codeplex  http://showui.codeplex.com/.

Other links are here

http://msmvps.com/blogs/richardsiddaway/archive/2011/07/08/an-easier-clock.aspx

 

As well as wanting to know the time I often want to set a count down timer.  I did a version of this ages ago using PowerGadgets but  if you don’t have that then we can do something with show UI

Import-Module ShowUI                        
            
function timeleft {            
 $ts = $close - (Get-Date)            
 $time = $ts.ToString() -split "\."            
 $time[0].Substring(3,5)            
}            
            
            
$close = (Get-Date).AddMinutes(35)            
            
$windowAttributes = @{            
    WindowStartupLocation = "CenterScreen"            
    SizeToContent = "WidthAndHeight"            
    WindowStyle = "None"            
    Background = "Transparent "                        
            
    On_MouseRightButtonDown = { Close-Control}            
    On_MouseLeftButtonDown  = { $_.Handled = $true;$window.DragMove() }            
    On_Loaded = {            
        Register-PowerShellCommand -ScriptBlock {            
            $window.Content.Content = timeleft            
        } -Run -In "0:0:0.5"            
    }            
}                        
            
$labelAttributes = @{            
    Content = timeleft            
    FontFamily = "Impact, Arial"            
    FontWeight = 800            
    FontSize = 90            
}                        
            
New-Window @windowAttributes -AllowsTransparency -Show  {            
    Label @labelAttributes -Name Clock -Foreground (            
        LinearGradientBrush $(            
            GradientStop -Color Red    -Offset 1            
            GradientStop -Color Orange -Offset 0.85            
            GradientStop -Color Yellow -Offset 0.7            
            GradientStop -Color Green  -Offset 0.55            
            GradientStop -Color Blue   -Offset 0.4            
            GradientStop -Color Indigo -Offset 0.2            
            GradientStop -Color Violet -Offset 0            
        )            
    )            
}


All I changed was to point the Content to the timeleft function instead of get-date. The function takes the closing time – in this case 35 minute from starting and subtracts the current datetime (from get-date). The resultant timespan is converted to a string and split at the millisecond point. The minutes and seconds are extracted as  a substring to display



By the way – anyone noticed the deliberate(?) mistake with the colours

Reminders

If I am working on my home machine I don’t necessarily have Outlook or any other application that gives me calendaring capability open. There are times when I need a simple reminder to do something. For some reason I always seem to have PowerShell open so I thought of using the eventing system to give me a reminder.  I could also do this via the task scheduler functions in the PowerShellPack  (Windows 7 Resource kit) which I’ll look at another day.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
function Set-Alarm {
param (
        [datetime]$time,
       
        [string]$msg = "Alert Issued"
      )     

    $now = Get-Date 
    if ($time -gt $now) {$ts = $time - $now}
    else {throw "Time has to be in future"}
       
    $timer = New-Object -TypeName System.Timers.Timer
    $timer.Interval = $ts.TotalMilliseconds
    $timer.AutoReset = $false
    $timer.Enabled = $true
   
    $global:act = "Start-Process powershell -ArgumentList ""-Sta -WindowStyle Hidden -File C:\Scripts\WPF\show-alert.ps1 """"$msg"""" "" "
   
    Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier TimeAlert  -Action {Invoke-Expression -Command $act }
}

 

My function accepts a time and a message

Set-Alarm "18:47" "Test1"

It then gets the current time, compares the two times and assuming the alert is to be issued in the future creates a Timespan object be subtracting the times as shown.

We can then create  .NET timer object and set the interval to the total number of milliseconds in our timespan. We only want it to fire once so we set autoReset to false and then enable the timer.

I then create a global variable containing the powershell start up commands.  In this case I want it to start in Single Thread mode so I can use the WPF classes.  I call a script when PowerShell starts and pass the script the message.  Note the number of quotes around the $msg variable – this is to make sure the string passed to invoke-expression is correct.  This is messy but needed.

The $act variable has to be global because the action scriptblock for Register-objectevent isn’t evaluated until the event fires.  If $act is in the script scope it won’t be found and the event won’t fire correctly.

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
param (
[string]$msg = "Testing",
[string]$title = "Alert"
)
## load WPF assemblies
Add-Type –assemblyName PresentationFramework
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName WindowsBase

## create a window
$window = New-Object -TypeName System.Windows.Window
$window.Title = $title
$window.Content = $msg
$window.FontSize = 36
$window.SizeToContent = "WidthAndHeight"

## display window
$null = $window.ShowDialog()

 

The script loads the WPF assemblies I need and then creates a window and writes out the message thats been passed in.

This is a bit messy with having to create a global variable but I can’t think of a simpler way to access the variable in the scriptblock for Register-objectevent. The other issue is that I can only have a single event of this type defined because of the variable.  I would need to create the variable with a random name and create another string of the Register-objectevent  invocation.

Technorati Tags: ,,