Summary: Use [DATETIME] variables and arrays to produce a countdown timer.

Honorary Scripting Guy, Sean Kearney, here filling in for our good friend, Ed. With the New Year coming up in a few days, I decided to present something silly and geeky. I want to use Windows PowerShell to produce a New Year’s countdown timer.

Figuring out the difference between two dates and times in Windows PowerShell is actually surprisingly easy. That is one of the reasons I love using and playing with Windows PowerShell…the difficult is usually very easy!

So first we need define the time to countdown to. We’re going to define the date and time with a simple string:

[datetime]$Countdown=”01/01/2014 00:00”

However, in my scenario, I decided I would have my script be reusable for each year, so I have a parameter called $CountdownYear:

param

(

$CountdownYear="2014"

)

So now I can substitute in the year automatically like this:

[datetime]$Countdown=”01/01/$CountdownYear 00:00”

With our final countdown time built, we can figure out the difference between our future date and now by using some simple math:

$data=($Countdown-(GET-DATE))

If we look at the $data object, we’ll see that it yields some very useful information that I don’t even have to dig for:

From this object, I immediately have all the information I want…the difference in days, hours, minutes, and seconds!

OK, that’s the easy part. Now I need a two-dimensional array to hold my numbers. I am literally going to build a large digital clock with Windows PowerShell. The first challenge is to build a function to draw numbers on the console. We’re going to accept two parameters: The Number we’d like to show and its column position on the screen.

Function Draw-Number($digit,$Column)

{

$Number=New-object 'object[,]' 11,8

$Number[0,0]="******* "

$Number[0,1]="* * "

$Number[0,2]="* * "

$Number[0,3]="* * "

$Number[0,4]="* * "

$Number[0,5]="* * "

$Number[0,6]="******* "

$Number[0,7]=" "

$Number[1,0]=" * "

$Number[1,1]=" * "

$Number[1,2]=" * "

$Number[1,3]=" * "

$Number[1,4]=" * "

$Number[1,5]=" * "

$Number[1,6]=" * "

$Number[1,7]=" "

Each member of the array will hold a simple 8x8 representation of a number. The pattern of the arrays will continue all the way until number 9, with an additional spot to hold the colon. I’ve done this as a function for two reasons. One, it is a repeated action that made sense at the time. Two, if you were to get creative with the WPK, PowerBoots, or even something with Windows Forms, you could (in theory) rewrite this script with some custom GUI output.

Now we’ll determine the physical starting column on screen from the position object passed from the $column object. Because each digit is a multiple of 8 in size, we’ll factor that into determining the starting column position:

$Adjust=($Column*10)+8

Now for the fun drawing stuff…

We’re going to remember where the cursor is now before we muck about:

$Remember=$host.ui.RawUI.CursorPosition

$Base=$Remember

Now we’ll build the new location for the cursor based on the adjusted value:

$base.X=$base.X+$adjust

$Y=$base.Y

Then we use a small loop to extract the values from the array and draw them onto the screen. They will draw an array member and reposition to exactly one row below where they drew it last. Just for fun, we’re going to make the numbers yellow and bright on the screen:

Can you see where this could now go? We can parse the individual numbers and draw them on the screen, so we just need a basic loop to track the differences, display the numbers, and wait until the New Year ends.

$starthere=$host.ui.RawUI.CursorPosition

do

{

$data=($Countdown-(GET-DATE))

$Days=$data.days

$host.ui.RawUI.CursorPosition=$starthere

$host.ui.RawUI.WindowTitle=(GET-DATE).tostring()

WRITE-HOST -ForegroundColor Cyan -Object "`n`n It is now $Days Day(s) until New Years Eve $CountdownYear and ...`n`n"

WRITE-HOST -ForegroundColor Green " HOURS MINUTES SECONDS`n`n"

We need to trap situations where this is a single digit in the numeric data. In all cases, I want to have two digits displayed. We can solve that by using the PadLeft method, which will allow us to literally pad left of the string with as many characters as we want. In this case, we want to pad 2 characters, always being the number 0.

When we have that, we simply use a substring to grab the individual digits: