Creating a system tray application with PowerShell

One of the great benefits of PowerShell is the ability to very quickly retrieve system information and metrics. We have added three new packager engines to PowerShell Studio and PrimalScript to make it easier to present or log that information in a standard way. I have already discussed the new Windows Application engine here:

This time around I will show you how easy it is to create a Windows System Tray Application with PowerShell and the new packager engine.
Just like last time we start with a script I found on the internet:


Here is a shout out to Sravan Kumar for sharing his script to check website availability and response times. His script produces an HTML report that we will not use. We want a tray application that checks a list of web sites in intervals and alerts us if one is not available or slow with a tray message.
The list of sites the application checks must come from a text file that is loaded for each iteration, so that there is no need to stop and start the application to pick up new URLs.
The goal for this engine was to allow you to convert a simple script to a system tray application while only using Write-Host, Write-Output etc. You should not have to know much about how tray applications actually work.


Don’t worry, the source for this script is attached to this post.

The file containing the URLs to be checked has to be here: C:\ProgramData\URICheck\URLList.txt
and it contains one URL per line.

There are a few simple things you need to do when making a script into system tray application:
1. It needs to be a loop. As you can see, this script has a while($true) loop. If you do not do that, your tray app will do things just once and then sit there.

2. Sleep when you are not doing anything. The example sleeps a minute after checking the list. Realistically, it could check only every ten minutes and still be fine. If you omit that, you will be using up way more CPU cycles than you need.
Your script runs on its own thread, so exiting the tray application is not dependent on your script sleeping or not.

3. Set $progressPreference = ‘silentlyContinue’, unless you really, really need progress windows. Since the System Tray App engine is a Windows Application, it will display progress notifications as a popup window. Cmdlets like Invoke-WebRequest will display progress, no matter how quick. This can result in flashing progress popups from your applications. We did not generally disable progress display, because you may need to use it for some lengthy operation.

4. Limit your output. Every time a tray app uses any PowerShell output method, a notification in the lower right corner will pop up and the associated system sound will be played. So only produce output if there is something that requires the user’s attention.

5. Supply a meaningful icon. The icon of your application will be display in the system tray. You want to have a distinguishable icon in case you have more than one PowerShell based tray application.

6. Fill out your version resources. A tray application package has an automatic about box, which displays the information in your version resources.


Last but not least, here is how you do all that. It is pretty simple. After running and debugging your script just as you always would, package it using the new Windows Tray App engine:

That’s it.

You can download the script and the packaged executables from here:


As always, if you have any ideas, comments, feedback, please use our feedback forum and reference this post.