Creating Balloon Tips Safely

by Oct 23, 2017

Inspired by an article by fellow MVP Boe Prox, below you’ll find a sophisticated function that creates balloon tip dialogs. You can find background information about the concepts in Boe’s original article: https://mcpmag.com/articles/2017/09/07/creating-a-balloon-tip-notification-using-powershell.aspx.

You can find many tips showing how to display a balloon tip, but most of these approaches leave behind a non-functional tray icon.

The function below builds on top of Boe’s ideas, yet makes sure there is no need for global variables or anything else that would pollute your PowerShell environment. When you call Show-BalloonTip, a ballon tip slides into view in the lower right hand of your desktop. You can either click into the tooltip to close it again, or dismiss it. When you dismiss it, its icon stays in the tray area of your task bar. When you click the tray icon, the balloon tip is shown again.

function Show-BalloonTip
{
    param
    (
        [Parameter(Mandatory=$true)][string]$Text,
        [string]$Title = "Message from PowerShell",
        [ValidateSet('Info','Warning','Error','None')][string]$Icon = 'Info'
    )

    Add-Type -AssemblyName  System.Windows.Forms

    # we use private variables only. No need for global scope
    $balloon = New-Object System.Windows.Forms.NotifyIcon 
    $cleanup = 
    {    
        # this gets executed when the user clicks the balloon tip dialog

        # take the balloon from the event arguments, and dispose it
        $event.Sender.Dispose()
        # take the event handler names also from the event arguments,
        # and clean up
        Unregister-Event  -SourceIdentifier $event.SourceIdentifier
        Remove-Job -Name $event.SourceIdentifier
        $name2 = "M" + $event.SourceIdentifier
        Unregister-Event  -SourceIdentifier $name2
        Remove-Job -Name $name2
    }
    $showBalloon = 
    {
        # this gets executed when the user clicks the tray icon
        $event.Sender.ShowBalloonTip(5000) 
    }

    # use unique names for event handlers so you can open multiple balloon tips
    $name = [Guid]::NewGuid().Guid

    # subscribe to the balloon events
    $null = Register-ObjectEvent -InputObject $balloon -EventName BalloonTipClicked -Source $name -Action $cleanup
    $null = Register-ObjectEvent -InputObject $balloon -EventName MouseClick -Source "M$name" -Action $showBalloon

    # use the current application icon as tray icon
    $path = (Get-Process -id $pid).Path
    $balloon.Icon  = [System.Drawing.Icon]::ExtractAssociatedIcon($path) 

    # configure the balloon tip
    $balloon.BalloonTipIcon  = $Icon
    $balloon.BalloonTipText  = $Text
    $balloon.BalloonTipTitle  = $Title

    # make the tray icon visible
    $balloon.Visible  = $true 
    # show the balloon tip
    $balloon.ShowBalloonTip(5000) 
}

Twitter This Tip! ReTweet this Tip!