Worklet: Predictable Reboot Notifications for Windows

  • 25 September 2019
  • 34 replies
  • 1515 views

Userlevel 5
Badge

Hey Y’all!


Automox offers a fully customizable end-user notification feature that clearly indicates to users when Automox will be patching and potentially rebooting their systems. This feature also allows you to set custom deferral options empowering users to control when their device should be patched. This gives peace of mind to system admins that their environment will be patched without interfering with their users everyday use.


Although this is a great feature, Automox recognizes that it does not offer the predictability to users to when the actual reboot event will take place. We are currently working on improving our current notifications to give users better reboot predictability. Automox has gathered a lot of customer feedback aimed to make this feature enhancement as effective as possible. The great thing about this is it will be built into the product and be offered in the same fashion as the current end-user notifications.


So, what can you do until this feature is released? The majority of the feedback we received is that we are great about notifying the user to when patching begins, however, once patching is executed we do not let the user know exactly when the reboot will take place and allow them to defer the reboot.


This level of reboot predictability may not be a requirement for you. If it is? Worklets to the rescue!


The below Worklet will send end-user notifications to users through the form of Windows notifications. The notifications are fully customizable, these options include:



  • Custom notification messages for each notification

  • Frequency of notification messages sent

  • Custom reboot timing and notifying

  • Final reboot message forces user acknowledgement


Prerequisite:

The policy Reboot Notifications needs to be disabled. This is so the Worklet and policy end-user notifications do not conflict.


The Worklet remediation needs some customizing by the user. Each value needs to be set correctly in order for the notification messages to patch the timer values set, otherwise it may not reboot correctly.


There are a few values that you’ll need to set in the script. They are easily indicated with the “$” in front of each. Here is a list and what they do below. Pay attention to the naming, you’ll get a sense of how the Worklet will flow given each value you set. Also, if you need any assistance setting this up I would be happy to help, just reply to this post and I will be sure to help get this setup for you.


$rebootimer (ex: $rebootimer=5400) - This hardsets the time until the device reboots, in seconds.


$message1 (ex: $message1={your_message}) - Copy for the custom message in the first notification. Be sure to indicate the amount of time in minutes until the reboot. This was set previously in $rebootimer


$message2wait (ex: $message2wait=1800) - the amount of time elapsed until the second notification is sent, in seconds.


$message2 - Copy for the custom message in the second notification. Be sure to indicate the amount of time in minutes until the reboot. This was set previously in $rebootimer minus the time elapsed that was set in $message2wait. Indicate this in minutes (5400-1800=3600) which is 60 minutes.


$rebootimer2 (ex: $rebootimer=5400) - resets the reboot timer to the time indicated in the previous notification message ($message2). If you indicated 60 minutes, then set this time to 3600 seconds


And so on….


As you can see, you need to see the reboot time, the custom message, and the wait timer for the notification intervals. The logic needs to make sense when setting these so it flows with what the custom notification says and what the behavior of the reboot is. Below is the evaluation and remediation code for the Worklet. This will help you get a visual for one that is fully customized.


Evaluation:


#exit 0 if no reboot is needed
#exit 1 if reboot is needed

$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)
{
exit 1}
else
{
exit 0}

Remediation:


$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)
{
######################################################### Start Parameters - Editable #########################################################

#hardset the reboot countdown timer in seconds (e.g. 5400 for 90 minutes). After this time elapses reboot command is initiated. In this example it's 90 minutes
$rebootimer = 5400
#set the first notification message copy. Include the reboot time value set previously. In this example it's 90 minutes
$message1 = "Automox will automatically reboot your computer in 90 minutes. Please take time to save and close any open documents."
#Define the time to wait until the second notification message is sent in seconds (e.g. 1800 for 30 minutes).
$message2wait = 1800
#set the second notification message copy. In this example 60 minutes.
$message2 = "Automox will automatically reboot your computer in 60 minutes. Please take time to save and close any open documents."
#reset the reboot time to match the time indicated in the previous notification message copy (e.g. 3600 for 60 minutes)
$rebootimer2 = 3600
#Define the time to wait for the third notification message to launch in seconds (e.g. 1800 for 30 minutes). In this example it's 30 minutes
$message3wait = 1800
#set the third notification message copy. In this example 30 minutes.
$message3 = "Automox will automatically reboot your computer in 30 minutes. Please take time to save and close any open documents."
#reset the reboot time to match the time indicated in the previois notification message copy (e.g.1800 for 30 minutes)
$rebootimer3 = 1800
#Define the time to wait for the final notification message to launch in seconds (e.g. 900 for 15 minutes). This needs to be in sync with when the reboot is scheduled.
#In this example it will warn the users 15 minutes before the reboot, so we set it to 900 (15 minutes)
$message4wait = 900
#set the final notification copy. The time for reboot should match the amount of time until the reboot take place
$message4 = "Automox will automatically reboot your computer in 15 minutes. Please take time to save and close any open documents."
#reset the reboot time to match the time indicated in the previois notification message copy (e.g.300 for 15 minutes)
$rebootimer4 = 900

################################################################ End Parameters ################################################################


### Commands being run ###
shutdown /a
shutdown /r /t $rebootimer /d p:4:1 /c $message1
Start-Sleep -Seconds $message2wait
shutdown /a
shutdown /r /t $rebootimer2 /d p:4:1 /c $message2
Start-Sleep -Seconds $message3wait
shutdown /a
shutdown /r /t $rebootimer3 /d p:4:1 /c $message3
Start-Sleep -Seconds $message4wait
shutdown /a
shutdown /r /t $rebootimer4 /d p:4:1 /c $message4
}
{
exit 0}

In the above example, I am setting the reboot countdown at 90 minutes. It will then send 3 more notifications warning the user of the reboot within the 90 minute with.



  1. The first notification will be sent notifying the user that a reboot will occur in 90 minutes

    30 minutes elapses

  2. The second notification message is sent and notifies the user a reboot will occur in 60 minutes

    30 minutes elapses

  3. The third notification message is sent and notifies the user a reboot will occur in 30 minutes

    15 minutes elapses

  4. The forth notification message is sent and notifies the user a reboot will occur in 15 minutes


After that the user will get notified 2 more times automatically through Windows. This will force the user to confirm before they can keep using their desktop. This happens at 10 minutes and again at 5 minutes. Below is an example of what this looks like



After that, the system will reboot. This gives the user plenty of time to save off any work before the reboot occurs. Again, you can make this longer if you desire. I do recommend that is kept under 8 hours as the agent will remain scanning during this Worklet and will not run any further commands until the Worklet has finished.


Here is an example of what the normal windows notification looks like on the device in the Worklet example above:



That’s it! You are now all set the notify user before rebooting a device. If you need any assistance with setting this up please feel free to reach out to me!


34 replies

I can’t wait to give this a spin this afternoon - thanks Adam!

Userlevel 5
Badge

You’re welcome! Please reach out if you have questions or need any assistance with setting it up.

This looks great … will take for a spin today as well … users like to be informed.


Cheers!

Userlevel 5
Badge

Awesome! I agree, the more informed the better. Enjoy using this and let me know if you need any assistance!

We are a Mac heavy environment. While I love the concept of this (and it will certainly help our Windows devices), we are still needing options for our Mac users. Anything in the works?

Userlevel 5
Badge

Great question. I am currently looking into ways we could accomplish the same thing on Mac devices. Windows is straightforward since we just harness the built in Windows Notifications. I am not as rehearsed on what MacOS uses and how we could accomplish this.


I will update the community once I either have the Worklet created, or inform you that it’s not possible within the confines of a Worklet.


Thanks!

@awhitman


Adam,


Just finished my readthrough and am going to start testing. One thing that is not clear is whether this will work for both Windows 7 (which is EOL in January, yes, but there will still be devices that need to be patched up until the final patches) as well as Windows 10?

Userlevel 5
Badge

@ScottCooke


Hey Scott,


I did test this on a Windows 7 device and it worked the same as Windows 10, so it should work for all your Windows 7 devices. I would highly recommend running it on a single Windows 7 device first just to make sure it works as expected.


Thanks!

@awhitman If the user reboots before the timer is up. Does it clear the machines pending reboot status?

Userlevel 5
Badge

Yes, if the user reboots their device before the Worklet does, then it will clear the reboot value (RebootRequired: True to RebootRequired: False), this is on the system. If you reboot the device from Automox, then we will clear the reboot flag in the console. However, if a user reboots it directly from the device, we will not clear the reboot flag in Automox until the device is rescanned by the agent, we do not rescan the device unless we perform the reboot.


As far as the reboot notification Worklet goes, if a user reboots their device early it will clear the reboot flag on the system which is what the Worklet keys off of to determine if a reboot is needed, and if so, to send the notifications. When the user reboots their device and the Worklet hasn’t finished running, then it will start the remediation code over from the beginning. This is why I added code at the beginning of the remediation script to re-evaluate the device to see if the reboot flag is “True” or “False”. If RebootRequired is True, then it sends the notifications and sets the reboot timer. If RebootRequired is False, then it exits “0” and doesn’t send notifications. If this logic wasn’t included then it would keep running the remediation code without checking the Reboot status and the user would get into a notification loop.


Hope this helps!

Userlevel 7

For those of you who are using this worklet, is it working well in your environment? Let us know here or in this topic:
 

 


For those of you who are using this Worklet:


Is it working well for you as a workaround for reboot notification issues? We’re trying to determine how well this is working for people so that we can prioritize a complete fix for the problem.

 

 

 

 

I’ve had mixed results. It seems that having multiple updates that require reboots messes with it. I’ve had reports from users saying that they’ve seen the notification say 10 minutes until reboot and then another a couple minutes later pop-up saying 30 minutes until reboot, etc. I haven’t been able to replicate on my side to grab screenshots.


Also, some users have notifications disabled or set to quiet in Windows so they don’t see it.


Overall, it is working for the most part.

Userlevel 7

Thanks @bfrey! If you do get any any screen shots please send them on over to us.

I have also had mixed results with the reboot worklet. It seems to work the majority of the time, but our users don’t have the ability to say no or defer the reboot. I started looking into using this worklet with our environment because users would not get accurate time-of-reboot when their machine was to set to install and auto-reboot after patch (Some cases more than an hour after Automox message).


I don’t know if this is just a case of us having to change our patching policy around, and not give users the control. Would love to know if other Automox users have a similar case or how other people are doing it. I guess the big thing for us would be accurate alerting for reboot.

Hey Adam,

Have you seen these Apple Automator options?


https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/DisplayNotifications.html#//apple_ref/doc/uid/TP40016239-CH61-SW1


https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/DisplayDialogsandAlerts.html#//apple_ref/doc/uid/TP40016239-CH15-SW1


You can run simple apple scripts from the bash terminal using the following syntax(command to display a notification):


osascript -e 'display notification "hello world!"'

Just a theory but this could allow you to execute these commands through a worklet. Not sure which option would work best (notification, alert, dialog) but you can play around with each.

Badge

@aescolastico great find, our hesitation with using osascript is that new privacy controls require the end user to “approve” the command when it’s invoked in macOS Catalina.

Doh!

That is unfortunate.


Does running with sudo bypass that at all?

Userlevel 5
Badge

I never tried the bypass option before, so not sure if it will work or not. Here is the Worklet bash code that @molly and I wrote for predictable reboot notifications using Mac. It works great locally on the device, however, it will not work using a Worklet because it utilities osascript. You could give it a try with the bypass option you mentioned to see if it will display the notifications on the Mac desktop.


Evaluation:



softwareupdate -l > /tmp/output.txt & proccess_id=$!

wait $process_id

grep -w "Tool" /tmp/output.txt > /dev/null

if [[ $? -eq 0 ]]; then

#shutdown -h +5

message1="Automox will reboot your system in 2 hours. Please take time to save and close any open documents."
osascript -e 'display notification "'"$message1"'"'

sleep 10s

message2="Automox will reboot your system in 1 hour. Please take time to save and close any open documents."
osascript -e 'display notification "'"$message2"'"'

sleep 10s

message3="Automox will reboot your system in 30 minutes. Please take time to save and close any open documents."
osascript -e 'display alert "'"$message3"'"'

sleep 10s

message4="Automox will reboot your system in 10 minutes. Please take time to save and close any open documents."
osascript -e 'display alert "'"$message4"'"'


else
exit 1
fi

Is there a way to customize the font size? I have this deployed in my org and on newer machines with a 4K screen, the text is tiny - barely legible. Is there any option within the Worklet to set it at a specific size?

Userlevel 5
Badge

@bsilber


Unfortunately, there is no way to change the font that I am aware of. I will keep researching this more and let you know if I find anything.


Thanks

Userlevel 4
Badge

Hi Guys i tried to change the results in the audit log so it won’t state exit 1 or exit 0 but what do i need to change in the code to get the following;


{

Write-Output “Reboot pending, starting reboot process”

exit 1}

else

{

Write-Output “No pending Reboot”

exit 0}


and for remediation


{

Write-Output “Reboot Initiated”

exit 0}

Userlevel 4
Badge

Hi Guys,


i need your help i tried to move this to the next level to use baloons and the action center but the scripts run’s fine locally but the moment you put this in system context this never reaches the end-user.


can i pick your brains to see if we can make a workaround or something?


Function Show-BalloonTip {
Param(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateNotNull()]
[String]
$BalloonTipText,
[Parameter(Position = 1)]
[String]
$BalloonTipTitle = 'Tip',
[Parameter(Position = 2)]
[ValidateSet('Error', 'Info', 'None', 'Warning')]
[String]
$BalloonTipIcon = 'None',
[Parameter(Position = 3)]
[Int]
$BalloonTipTime = 1000
)
end {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[Windows.Forms.ToolTipIcon]$BalloonTipIcon = $BalloonTipIcon
$ContextMenu = New-Object System.Windows.Forms.ContextMenu
$MenuItem = New-Object System.Windows.Forms.MenuItem

$NotifyIcon = New-Object Windows.Forms.NotifyIcon -Property @{
BalloonTipIcon = $BalloonTipIcon
BalloonTipText = $BalloonTipText
BalloonTipTitle = $BalloonTipTitle
ContextMenu = $ContextMenu
Icon = [Drawing.Icon]::ExtractAssociatedIcon((Get-Command powershell).Path)
Text = -join $BalloonTipText[0..62]
Visible = $false
}
$NotifyIcon.contextMenu.MenuItems.AddRange($MenuItem)
$NotifyIcon.Visible = $True
$MenuItem.Text = "Exit"
$MenuItem.add_Click({
$NotifyIcon.Visible = $false
$NotifyIcon.ShowInTaskbar = $false
})
$NotifyIcon.ShowBalloonTip($BalloonTipTime)
switch ($Host.Runspace.ApartmentState) {
STA {
$null = Register-ObjectEvent -InputObject $NotifyIcon -EventName BalloonTipClosed -Action {
$Sender.Dispose()
Unregister-Event $EventSubscriber.SourceIdentifier
Remove-Job $EventSubscriber.Action
}
}
default {
continue
}
}
}
}

$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"

### Variables ###

#$wait30Minutes = 1800
#$wait15Minutes = 900
#$rebootTimer = 300

$wait30Minutes = 18
$wait15Minutes = 9
$rebootTimer = 3

$balloonTipIcon = "None"
$balloonTipTitle = "Your IT Department"

if($sysInfo)
#if($sysInfo.RebootRequired)
{
Show-BalloonTip -BalloonTipText "We have installed security updates. Your device will automatically reboot within 90 minutes. Please save your work." -BalloonTipTitle $balloonTipTitle -BalloonTipIcon $balloonTipIcon -BalloonTipTime 7500
Start-Sleep -Seconds $wait30Minutes

Show-BalloonTip -BalloonTipText "We have installed security updates. Your device will automatically reboot within 60 minutes. Please save your work." -BalloonTipTitle $balloonTipTitle -BalloonTipIcon $balloonTipIcon -BalloonTipTime 7500
Start-Sleep -Seconds $wait30Minutes

Show-BalloonTip -BalloonTipText "We have installed security updates. Your device will automatically reboot within 30 minutes. Please save your work." -BalloonTipTitle $balloonTipTitle -BalloonTipIcon $balloonTipIcon -BalloonTipTime 7500
Start-Sleep -Seconds $wait15Minutes

Show-BalloonTip -BalloonTipText "We have installed security updates. Your device will automatically reboot within 15 minutes. Please save your work." -BalloonTipTitle $balloonTipTitle -BalloonTipIcon $balloonTipIcon -BalloonTipTime 15000
Start-Sleep -Seconds 6

### Initate Reboot ###
#shutdown /r /t $rebootTimer /d p:4:1
Write-Output "System Rebooted!"
}
Userlevel 7

The trick I’ve used to get messages to the end user involves running the script as a scheduled task as the currently logged in user. See this worklet for how that works:
 

 


This worklet uses msg.exe to send a notification to the currently logged in user. Once the user dismisses the notification message, a reboot command is immediately issued.
Things you can change in the script:

Edit the “Message to end user” to put in your custom message, such as “Click OK to reboot now”
The time to wait for the scheduled task. In this case we used 30 seconds but you might be able to get away with a shorter time window. In any case, this doesn’t matter to the end user, just …

 

 

 

 

Userlevel 4
Badge

That’s a route i don’t want to go to, i will wait for the improved build-in version.

Userlevel 4
Badge

I have a custom script that does all that. A scheduled task also pops up a powershell window. I’ve also manage to make it hidden. The pop-up only appears if there is a user logged on.


The worket works great for me. The scheduled task does a pending-reboot check every hour and if there is one it will popup the balloon. You can configure the max number of popups per 24hours to avoid annoying the user. It also forces an auto reboot when it detects the computer is idle for a configurable amount of time within a particular time window of the day. So for example, idle detection returns true if computer is idle for 30minutes anywhere between 1am and 5am local time.

Reply