Windows PowerShell Tip of the Week

Here’s a quick tip on working with Windows PowerShell. These are published every week for as long as we can come up with new tips. If you have a tip you’d like us to share or a question about how to do something, let us know.

Find more tips in the Windows PowerShell Tip of the Week archive.

Displaying a Message in the Notification Area

To be honest, script writers have often been short-changed when it comes to working with the graphical user elements that make up the Windows interface. Admittedly, VBScripters have done some very cool things using HTAs (HTML Applications); however, HTAs are limited to the controls and the user interface elements that can be used on a Web page. As cool as HTAs might be, these applications (and the scripters who write them) don’t have access to some of the really cool user interface elements available to full-fledged programming languages.

For example, the Scripting Guys are often asked how VBScripters can display a notice in the notification area, the little spot in the lower right-hand corner of the screen where application and operating system messages are wont to appear. And each time we’re asked that question we have the same answer: Sorry, no can do.

Oh, if only Windows PowerShell scripters would ask us that same question ….

What’s that? Why do we wish that Windows PowerShell scripters would ask us that question? That’s easy: because, in that case, we’d have a much better answer for them. As it turns out, you can use the .NET Framework to display messages in the notification area. And because Windows PowerShell has full access to the .NET Framework, that means that you can use Windows PowerShell to display messages in the notification area.

And no, for once we’re not kidding; you really can use Windows PowerShell to display messages in the notification area. If you couldn’t, then we’d have had no reason to put together a script like this one:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon

$objNotifyIcon.Icon = "C:\Scripts\Forms\Folder.ico"
$objNotifyIcon.BalloonTipIcon = "Error"
$objNotifyIcon.BalloonTipText = "A file needed to complete the operation could not be found."
$objNotifyIcon.BalloonTipTitle = "File Not Found"

$objNotifyIcon.Visible = $True
$objNotifyIcon.ShowBalloonTip(10000)

Let’s see if we can figure out how this works, and how you can start employing code like this in your own scripts. We start out by using the following line of code to load an instance of the .NET Framework class System.Windows.Forms:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

In case you’re wondering, the [void] at the beginning on this line of code simply keeps status messages from appearing on the screen when we load the System.Windows.Form class. Without [void] we’d see the following message appear on screen each time we ran our script:

GAC Version Location--- ------- --------True v2.0.50727 C:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e089\System.Windows.For...

Not that this doesn’t make for absolutely fascinating reading, mind you. It’s just that we don’t really need see to it each time the script runs.

After loading the System.Windows.Forms class we use the New-Object cmdlet to create an instance of the System.Windows.Forms.NotifyIcon class; as you might expect, this is the .NET class that actually lets us configure and display a notification in the notification area:

$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon

Following that we need to define several properties of our notice. In particular, we need to assign values to the following items:

Property

Description

Icon

This is the icon that appears in the notification area. The icon must be 16 pixels high by 16 pixels wide. If you have icon-editing software you can create your own icon; if not, try searching your computer (or the Internet) for .ICO files. Just make sure you specify the full path to the icon file when assigning a value to the Icon property: $objNotifyIcon.Icon = "C:\Scripts\Forms\Folder.ico".

BalloonTipIcon

This is the icon that appears inside your notice (see the illustration below). You can choose between the following operating system-supplied icons: Info; Warning; and Error. In our example, we’ve set the BalloonTipIcon to Error.

BalloonTipText

The actual message to be displayed. For this particular script we’ve set the BalloonTipText to “A file needed to complete the operation could not be found.”

BalloonTipTitle

The title of your notice. For our example, that’s File Not Found.

Or, to put it this all a little more visually:

Believe it or not, we’re almost done. After setting the Visible property to True ($True), all we have to do now is call the ShowBalloonTip method and display the notice:

$objNotifyIcon.ShowBalloonTip(10000)

A couple notes about the ShowBalloonTip method. For one thing, did you notice the parameter 10000 that we passed to ShowBalloonTip? Well, in theory, that indicates the number of milliseconds that we want our notice to stay on screen before automatically disappearing. Because there are 1000 milliseconds in every second, a value of 10000 means that, theoretically, we want the message to stay onscreen for 10 seconds, and then bid everyone a hasty goodbye.

That seems simple enough. So then why do we keep saying things like “in theory” and “theoretically”? That’s because there are some outside factors that come into play here. For example, the operating system imposes minimum and maximum values when it comes to displaying items in the notification area; typically a notice must remain onscreen for at least 10 seconds but no more than 30 seconds. What does that mean? Let’s put it this way: suppose you passed ShowBalloonTip the value 300000, thinking that would keep the notice displayed for 5 minutes (300,000 milliseconds). In reality, though, it’s highly unlikely that the notice will stay onscreen that long; instead, the operating system will probably dismiss it long before then. Likewise, suppose you set the parameter value to 1, thinking that you’ll show the notice for just 1 millisecond and then take it away. That’s not going to work, either: Windows will make sure that the notice is displayed for the minimum-allowed time before disposing of it.

On top of that, these times also depend on the amount of activity taking place on the computer. If the system appears to be idle then the countdown won’t begin until the computer actually does something. In that case, the notice could end up being displayed for hours.

Note. Of course, you can always dismiss a notice simply by clicking on it. Speaking of which, we should point out that any time a notification times-out the message will disappear, but the icon will remain in the notification area, at least until you pass the mouse through that area. However, if you dismiss a notice by clicking on it the icon will also disappear.

Regardless of how long it actually stays on screen, your notification will look something like this:

Not bad, eh?

Another thing to keep in mind here is that your script will continue to run while the notice is displayed; the script won’t automatically pause and wait for the notice to disappear. That shouldn’t cause any problems; it’s just something you should be aware of.

And here’s a cool tip: you can change the notice at any time. For example, here’s a script that displays a notice indicating that files are being retrieved from the folder C:\Windows. As soon as the Get-ChildItem cmdlet finishes collecting those files, the BalloonTipText and BalloonTipTitle properties are updated to indicate that the files have been retrieved. When the Visible property is set to True and the ShowBalloonTip method is called, this “new” notice will replace the previous notification.

Here’s the code:

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon

$objNotifyIcon.Icon = "C:\Scripts\Forms\Folder.ico"
$objNotifyIcon.BalloonTipIcon = "Info"
$objNotifyIcon.BalloonTipText = "Retrieving files from C:\Windows."
$objNotifyIcon.BalloonTipTitle = "Retrieving Files"

$objNotifyIcon.Visible = $True
$objNotifyIcon.ShowBalloonTip(10000)

Get-ChildItem C:\Windows

$objNotifyIcon.BalloonTipText = "The script has finished running."
$objNotifyIcon.BalloonTipTitle = "Files retrieved."

$objNotifyIcon.Visible = $True
$objNotifyIcon.ShowBalloonTip(10000)

That’s something that system administration scripters dreamt about doing for years.

That also marks the end of this week’s column; the Scripting Editor is already tapping her feet, checking her watch, and wondering when we’re going to hand this off for editing. Don’t worry, Scripting Editor; we were just about to do that.

See you all next week.