Reminding Your Users To Reboot

How to use BurntToast to build custom reboot reminder notifications that use the native Windows 10 toast API.

Here's a method I came up with for gently nagging reminding your users to reboot on a regular basis.

The Problem

I'm too lazy to research any actual stats, but I can say from experience that a significant number of helpdesk tickets are resolved by a simple reboot. I'm sure there are some people out there that reboot regularly as a part of their normal workflow. But there are also those that wouldn't ever reboot if they didn't absolutely have to. (For the record, I'm more of the latter.) For those users, a gentle reminder to reboot every few days can go a long way towards keeping their PC running at peak performance. And we'll hopefully head off more than a few helpdesk tickets in the process.

But how can we tell which PCs aren't being rebooted regularly? And how do we gently, but persistently, get them back into compliance? In the modern, mobile workforce, we don't get maintenance windows on client machines. So, crude methods like forcing a reboot with a scheduled task aren't really an option. However, I have found that a well-designed and persistent notification can be extremely effective.

The Solution

I'm going to show you how to build a custom notification that uses the native Windows 10 toast notifications API. The notification will have these properties:

  • Persistent: Users must manually dismiss the notification to ensure that they see it.
  • Audible: It will include a subtle audio cue to draw attention.
  • Branded: It will be fully branded, which should add some weight to the message and set it apart from all the other junk that shows up in Action Center.
  • Informative: It will let the user know how long it's actually been since they last rebooted. This is important for the effectiveness of the alert. When they've been getting these reminders for a week and they start seeing double-digits, they'll feel increasing pressure to comply.

Here's what the finished product is going to look like for a ficticious company called CUBE. (Don't laugh at my attempt at designing a brand. I work in IT after all, not Marketing.)
RestartReminderExample

One other neat thing about this solution... Since we're leveraging the native notification API, our notifications will respect system-wide settings like "Quiet Hours". So, we don't run the risk of accidentally displaying some custom WPF reminder during the middle of a client presentation. That would certainly generate a nasty phone call to your boss.

What You'll Need

To make this work, you'll need to use one of my favorite PowerShell modules: BurntToast by Joshua King. You can install it from PowerShell Gallery, and you can view the source code and documentation on GitHub.

BurntToast handles all the dirty work of implementing the native API and interacting with the relevent .NET assemblies. You just write a few lines of PowerShell and you get beautiful, native notifications.

By default, the BurntToast module uses its own branding and iconography. You'll probably want to customize the module for use in your organization. That process is beyond the scope of this post, but here are a couple of links to get you started:

Time For Some Code

I'm going to assume that you know how to install PSModules and deploy them to your client workstations.

So, let's dive into the script. First, we need to determine how many days it's been since the user last rebooted. For that, we'll query the Win32_OperatingSystem WMI class, use regex matching to parse the string into a date object convert the string to a datetime (edit: updated with cleaner solution from commenter 'cnvsccm'), and then get the timespan since the last reboot.

$os = Get-WmiObject -Namespace 'root\cimv2' -Class 'win32_OperatingSystem'
$LastBoot = $os.converttodatetime($os.lastbootuptime)
$days = ((get-date)-$lastboot).Days

Now that we have our $days variable, we can use it to determine whether a reminder is needed. So, if we wanted to start prompting the users after 3 days of no reboots, we'd do something like this:

if ($days -ge 3) {
    ## Insert code here that will show the reminder notification
}

The only thing left is to implement the BurntToast module. While it's possible to generate a notification with a single cmdlet, I want more control over the look and behavior, so I'll need to build the notification using the various other cmdlets in the module. Joshua does a nice job of documenting each of these cmdlets over on Github, so I'll just provide the finished code here.

# create text objects for the message content
$text1 = New-BTText -Content 'Restart Recommended'
$text2 = New-BTText -Content "It has been $days days since your PC was last rebooted. CUBE IT recommends rebooting once a day for best system performance."

# reference the company logo that I prestaged in the module folder
$path = (Get-Module -Name BurntToast).ModuleBase
$image1 = New-BTImage -Source "$path\Images\CUBE-logo.png" -AppLogoOverride -Crop Circle

# select the audio tone that should be played when the notification displays
$audio1 = New-BTAudio -Path 'C:\Windows\media\Alarm03.wav'

# assemble the notification object
$binding1 = New-BTBinding -Children $text1, $text2 -AppLogoOverride $image1
$visual1 = New-BTVisual -BindingGeneric $binding1
$content1 = New-BTContent -Visual $visual1 -Audio $audio1 -Scenario IncomingCall

# submit the notification object to be displayed
Submit-BTNotification -Content $content1 -UniqueIdentifier "CUBERestart"

And that's it. When the script runs, if the PC has recently rebooted, then the script will take no action and will exit silently. Here's the complete script:

# import BurntToast module
if (Get-Module -ListAvailable -Name 'BurntToast') {
    Import-Module -Name 'BurntToast'
} else {
    return $false
}

# determine days since last reboot
$os = Get-WmiObject -Namespace 'root\cimv2' -Class 'win32_OperatingSystem'
$LastBoot = $os.converttodatetime($os.lastbootuptime)
$days = ((get-date)-$lastboot).Days

# display reminder if 3+ days since last reboot
if ($days -ge 3) {
    # create text objects for the message content
    $text1 = New-BTText -Content 'Restart Recommended'
    $text2 = New-BTText -Content "It has been $days days since your PC was last rebooted. CUBE IT recommends rebooting once a day for best system performance."

    # reference the company logo that I prestaged in the module folder
    $path = (Get-Module -Name BurntToast).ModuleBase
    $image1 = New-BTImage -Source "$path\Images\CUBE-logo.png" -AppLogoOverride -Crop Circle

    # select the audio tone that should be played when the notification displays
    $audio1 = New-BTAudio -Path 'C:\Windows\media\Alarm03.wav'

    # assemble the notification object
    $binding1 = New-BTBinding -Children $text1, $text2 -AppLogoOverride $image1
    $visual1 = New-BTVisual -BindingGeneric $binding1
    $content1 = New-BTContent -Visual $visual1 -Audio $audio1 -Scenario IncomingCall

    # submit the notification object to be displayed
    Submit-BTNotification -Content $content1 -UniqueIdentifier "CUBERestart"
}

return $true

Deploying The Script

At this point, you just need to run this script at a regular interval on each PC - maybe once or twice a day. I recommend not overdoing it. There are several ways that you could accomplish this:


I hope this was helpful. If you have any comments or questions, or if you have an idea about how to further improve this approach, you can connect with me via the comments below or via Twitter.