Update: Feb 22, 2011: Click here for my New and Improved Countdown timer
I often run Powershell scripts that run in a continuous loop to monitor some process or watch for some event to happen. The script could be reading a database, watching active processes, services or whatever but I don’t necessarily need to thrash the system or overburden a database with non-stop processing or database queries. The easy solution to this is to use the start-sleep cmdlet which works fine, but doesn’t provide any user feadback while in the “sleep” state.
I developed the following function for console feedback in instances where the sleep time is more than just a few seconds. By using the “`r” (carriage return) escape sequence in combination with the “write-host -nonewline”, I can keep the countdown timer display on a single console line with no scrolling. Also, by using foreground and background color highlighting, a nice visual cue is added, making the user interface very easy to read at a quick glance.
To achieve this, I use some simple date arithmetic and the time-span cmdlet. The Countdown function will sleep for one second at a time and wake up long enough to display an updated countdown timer in the form of “hours:minutes:seconds”. The trick is to clear the countdown timer line by overwriting with spaces and positioning the cursor back to the beginning of the line before writing the updated time-span data.
Here’s the basic steps that occur within the countdown timer.
1st: Define an end-time and time-span object based on your wait interval and the current system time:
$startTime = get-date $endTime = $startTime.addMinutes($waitMinutes) $timeSpan = new-timespan $startTime $endTime |
2nd: Clear the previous countdown timer data from the console (here I’m clearing 40 characters; adjust the “padright” method call to fit your script)
write-host "`r".padright(40," ") -nonewline |
3rd: Position the cursor back to the beginning of the console line and display the updated countdown timer
write-host $([string]::Format("`rTime Remaining: {0:d2}:{1:d2}:{2:d2}", ` $timeSpan.hours, ` $timeSpan.minutes, ` $timeSpan.seconds)) ` -nonewline -backgroundcolor black -foregroundcolor yellow |
Steps 2 and 3 could actually be combined but I’ve kept it separate here for easier readability. The result will look something like this:
Time Remaining: 00:01:00
Here’s a sample script that executes a continuous “while (-1) {}” loop with an embedded one-minute wait between each iteration:
function CountDown($waitMinutes) { $startTime = get-date $endTime = $startTime.addMinutes($waitMinutes) $timeSpan = new-timespan $startTime $endTime write-host "`nSleeping for $waitMinutes minutes..." -backgroundcolor black -foregroundcolor yellow while ($timeSpan -gt 0) { $timeSpan = new-timespan $(get-date) $endTime write-host "`r".padright(40," ") -nonewline write-host $([string]::Format("`rTime Remaining: {0:d2}:{1:d2}:{2:d2}", ` $timeSpan.hours, ` $timeSpan.minutes, ` $timeSpan.seconds)) ` -nonewline -backgroundcolor black -foregroundcolor yellow sleep 1 } write-host "" } while (-1) { write-host "doing some work....." Countdown 1 } |
Sample Output: (the countdown timer will overwrite the same line until Time Remaining equals zero)
Sleeping for 1 minutes... Time Remaining: 00:00:59
Demo:
As always, enjoy!
Wonderful. Thank you.