Adding custom menu items to PowerShell tray applications

A while ago we introduced a new packager engine which enables you to create System Tray applications with PowerShell. We have now extended that a little bit and added the ability to create custom menu entries in the tray application’s context menu.

image

I will take the same code we used for the last blog article and show you how to add the custom menu topic and the corresponding handler. The download link for the code is at the end of this article.

To enable you to do anything with the underlying engine which runs your script, we had to add an object which is available as $SAPIENHost. Since this particular object only exists in packaged engines, you need to make sure to check for its existence before using it.

So all custom menu code should be enclosed in if($SAPIENHost -ne $null) { …. }

image

Let’s look at the code. There are three parts:

  1. There is code to see if the registry has an entry pointing to our application to run on startup. If the items don’t match, we make sure to remove the entry—just in case you moved the application.
  2. The second part is the interaction with $SAPIENHost. As you can see, there are only two calls here:
    • First, $SAPIENHost.GetContextMenuStrip() retrieves the .NET object for the tray application’s context menu.
      The underlying .NET type is ContextMenuStrip if you want to look that up. The method GetContextMenuStrip exists in all hosts that have a $SAPIENHost object. It will just return $null if there is no context menu.
    • Second, there is a call to $SAPIENHost.SetMenuHandler. This connects a menu entry to a script block which gets called when a menu item is selected. More on that later.
  3. Last but not least, there is code to construct two objects, a ToolStripSeparator and a ToolStripMenuItem, which we add to the menu. We set the check mark on the menu item if the registry entry is there, otherwise, we make sure it’s off.

This is all normal .NET menu stuff, so nothing exciting.

The SetMenuHandler call has two parameters: The actual menu item object (ToolStripMenuItem), and the name of a script block which will handle that menu item—in our case $Handle_OnStartup.

image

This script block is called each time a user selects the menu item on the tray application’s context menu.

There are a few things to consider:

As you may remember, the main code of our tray application is a loop which sleeps between iterations. Your menu handler is called from a separate thread, which can be problematic. In our example, the menu handler does not interact with anything in the main loop so there is no problem.

If you want to interact with objects in your main script loop, make sure to consider or change the current state of your main operation before accessing and modifying any objects.

Download

You can download the script and the packaged executables here.

You will need PrimalScript 2019 7.4.122 or later to use this. PowerShell Studio 2019 should include the new engines with version 5.6.158 or after. Make sure to check the version log when in doubt.

Feedback

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