>
Scripts

PowerShell scripts that finally ping you when done

I have written more PowerShell scripts than I can count, and for years every one of them ended the same way: the script finished, the prompt came back, and I had no idea it was done unless I happened to be staring at the terminal. The disconnect got worse as my scripts got longer. A backup job that took forty minutes would finish while I was in another window, and I would not know until I alt-tabbed back and saw the prompt sitting there waiting. The fix turned out to be a small open-source module called BurntToast (a PowerShell wrapper around the Windows toast notification system, the little pop-ups that appear in the bottom-right corner of the screen).

The setup that actually works

The install is the part I expected to fight, and it was the easiest piece. BurntToast ships on the PowerShell Gallery (a public repository of reusable PowerShell modules, the same way npm or PyPI works for JavaScript and Python), so the install is one line:

Install-Module -Name BurntToast -Scope CurrentUser

That is the whole install. The first time you run it, PowerShell will ask if you trust the repository, and you say yes. After that, the module is available to every script you run as the same user. There is no service to install, no scheduled task to set up, no API key to register.

The first notification is one line:

New-BurntToastNotification -Text "Backup complete", "All 412 files synced"

That command pops a Windows toast in the bottom-right corner with a title and a body. It works on Windows 10 and 11. It does not work on Windows Server Core editions that do not have the desktop shell, and it does not work over Remote Desktop sessions that are minimized. Those are real edge cases I hit on my own scripts. There is a workaround for the second one: a flag called -UniqueIdentifier plus a registry tweak, but it is not worth describing here unless your job is RDP automation. For everyone else, the one-liner above is the whole thing.

What changed for me

I started adding a New-BurntToastNotification call to the end of every long-running script I own. The first one was a backup job. The second was an image-processing pipeline that takes about twenty minutes per batch. The third was a script that polls an API every five minutes and writes results to a SQL table. The fourth was a folder-sync script that mirrors a directory to a network share. After the fourth, I had enough data to see the patterns.

Here is the pattern that has held up across all four:

  • Long-running jobs (over five minutes). Toast at the end with the success or failure status. The toast includes the script name and the elapsed time, so I can scan a stack of completed notifications and know which one took forty minutes and which one took six.
  • Scheduled tasks that fail silently. Toast on the failure path. The success path is silent because a toast every hour for a working job is the kind of thing you start ignoring in three days, and then the failure toast is just one more ignored pop-up.
  • Manual scripts I run interactively. Toast only on the error path. The success case is the prompt coming back, which I am already looking at.
  • Background watchers with no terminal at all. Toast for every state change, not just completion. A watcher that checks an API every thirty seconds should toast when the API starts returning errors, even if the watcher itself is still running fine.

The third pattern was the one I underestimated. If you toast on every successful interactive script run, you start to tune them out, and then when a toast actually means something, you miss it. Restricting the toast to errors keeps the signal-to-noise ratio high. The fourth pattern came in about six months later, when I wrote a service that polls a remote endpoint and silently rotates between healthy and degraded states. Toasts on every state change turned out to be the only practical signal that something needed my attention.

Where BurntToast does not fit

There are real cases where BurntToast is the wrong tool. Headless servers are the first one. A Windows Server Core install (a server edition of Windows with no desktop GUI, common in data centers and CI/CD runners) does not have the notification subsystem that BurntToast wraps. The toast just silently fails. The right tool on a headless server is the native PowerShell Write-EventLog or a third-party log shipper like Splunk or a syslog forwarder.

Interactive scripts that take under a minute are the second case. A toast for a script that runs in thirty seconds is noise. The user is already watching the terminal. Save the toast for jobs where the user has context-switched away. A toast that fires faster than the user can context-switch is a toast that nobody reads.

Cross-platform scenarios are the third case. BurntToast is Windows-only. If you are running the same script on Linux or macOS, you need a different module. On Linux, notify-send does the same thing through the libnotify API. On macOS, osascript can pop a notification through AppleScript. None of these are interchangeable with BurntToast, and the script has to branch on platform. The cleanest pattern I have found is a wrapper function that calls the right module for the host OS and falls back to writing a log line if no notification system is available.

The config that I do not bother with

The module has a New-BurntToastConfiguration cmdlet that lets you set defaults like the default app icon, the default sound, and the default expiration time. I tried it for about a week and went back to specifying everything inline. The reason is debugging. When a toast does not show up, the first question is “what was different about this run?” If the configuration is in a profile or a config file somewhere, the answer is buried. If every script specifies its own text and icon, the answer is on the line that called New-BurntToastNotification.

The module also supports custom images and progress toasts (a toast that updates its progress bar as the job runs). I tried the progress toasts once, on a long file-copy job, and the result was a stream of toasts that flickered as the progress updated. The right way to do progress on Windows is the new ProgressBar in PowerShell 7.4, not a toast. Save the toast for the completion notification.

A third knob I tried was the -ExpirationTime flag, which controls how long the toast stays on screen. The default is five seconds. For long-running job completions, I bumped it to thirty seconds so I had time to actually read it. For failure toasts, I left it at five seconds because if I am not at the keyboard in five seconds, I am doing something more important than reading the toast.

Trade-offs

BurntToast is not a heavy module, but it does pull a few dependencies. The module itself is about 200KB on disk, and it depends on the BurntToast runtime plus the Microsoft.Toolkit.Uwp.Notifications package. The first install takes a few seconds because of the dependency resolution. After that, it is fast.

The other trade-off is the Windows-version compatibility matrix. BurntToast works on Windows 10 and 11. It does not work on Windows 8.1 or earlier. If you are maintaining scripts that need to run on older Windows, you need a different notification mechanism, and the easiest fallback is the older MessageBox API which is a modal dialog, not a toast. That is a different UX and a different set of problems.

A subtle trade-off is the focus-stealing behavior. Toasts by default do not steal keyboard focus, which is what you want. But on a slow machine, a toast that fires while you are typing in another window can cause a brief lag as the notification system draws the pop-up. I have not measured this consistently, but it is a real effect. The fix is to throttle toasts: if your script is in a tight loop, batch the toasts.

For a single-user dev workstation on a modern Windows version, BurntToast is a free, fast, reliable way to make long-running scripts tell you when they are done. The install is one line, the basic call is one line, and the failure modes are limited. If your scripts are mostly under a minute, this is overkill. If your scripts run for tens of minutes or hours, this is the kind of small quality-of-life improvement that compounds over weeks.

Bottom line

If you write PowerShell scripts that take more than five minutes, install BurntToast. The install is one line. The basic notification is one line. The pattern that holds up is to toast on completion for long-running jobs, toast on failure for scheduled tasks, and stay silent for fast interactive scripts. The configuration rabbit hole is not worth going down. Specify the text inline. If you are on a headless server or on Linux or macOS, this module will not work and you need a different tool for the platform.

Leave a comment