UPDATE: The script used here has been severely updated: https://www.imab.dk/windows-10-toast-notification-script/. The scenario described here is still relevant though, so I recommend that you still read through this 🙂
This will be a small but exciting contribution to my ‘Windows as a Service’ series!
The usual story here is, that everyone wants to add more user-friendliness to the whole experience around Windows Servicing.
End-users generally doesn’t care about new versions of Windows and they also, generally speaking, find interruptions in their work annoying, especially if those interruptions come unexpected.
So we come up with clever solutions to solve those problems and this will be an addition to that; remind the user with a big nice Windows toast notification when a Windows upgrade is pending. This is for the obvious reminder, but also to lure the end-user into a voluntary participation.
Find some of my previous WaaS posts here:
Part 1: https://www.imab.dk/windows-as-a-service-sharing-my-precache-and-in-place-upgrade-task-sequences-part-1/
Part 2: https://www.imab.dk/windows-as-a-service-sharing-my-precache-and-in-place-upgrade-task-sequences-part-2/
What Is This?
What is this and how does it work? I’m not the first person to advocate for the use of the toast mechanism in Windows 10 and I’m most certainly not the last.
Trevor Jones at https://smsagent.blog/ has again created something inspiring, as well as the guys behind https://automationsynd.github.io/. Both solutions involves using toast notifications in Windows 10 with SCCM.
Needless to say, I also ended up feeling the urge and put something together which I’m using in my own WaaS setup. The effect of the toast is astonishing. I will elaborate later.
This is the delicious magic. Download the script and open it with your favorite ISE and study it. I will elaborate where necessary in the next section.
IMPORTANT NOTE: The script is tailored to a requirement of having the SCCM client installed. This is the entry in the registry around which app (Read: Software Center) that is doing the notification. If you don’t have the SCCM client installed, the toast won’t display! Alternatively, use something else. I have included an alternative app in the end of the script for uses on devices without a SCCM client.
>> https://gallery.technet.microsoft.com/Windows-10-Toast-9f228eb1 <<
Run The Script
Simply running above script as is, will yield below result. So far so good. The text is obviously customized by myself and for my needs. The reference to Yammer is for internal use.
Also, I’m afraid the picture I’m using here and which is included in the script as a base64 string is protected by copyright (it’s a paid picture), so I’m kind of preventing you from using it with an annoying watermark. Sorry 🙂
When hitting ‘Install now’, Software Center is launched opening an application, which again is launching the Task Sequence. This is something I have covered in a previous post here, on how to use Powershell App Deployment Toolkit to upgrade Windows 10: https://www.imab.dk/how-can-i-in-place-upgrade-to-windows-10-1803-using-powershell-app-deployment-toolkit-and-sccm-system-center-configuration-manager-part-2/
Note: Stating the obvious, I’m using Powershell App Deployment for recognizability AND some additional user-friendliness.
Software Center is launched because of this line in the script:
# Application in Software Center running the task sequence $Application = "softwarecenter:SoftwareID=ScopeId_A9117680-D054-482B-BC97-532E6CBD0E6B/Application_4920c244-5b1e-4434-9117-fded57f5c80f"
Where the ID is obtained in the Software Center following the instructions outlined in below illustration:
Image Used In The Toast
The base64 string for the image is generated using below Powershell. This is directly copied from Trevor Jones: https://smsagent.blog/
Note: The image used here in my toast is 360*150 pixels.
# Convert an image file to base64 string $File = "C:\Temp\News_imab.jpg" $Image = [System.Drawing.Image]::FromFile($File) $MemoryStream = New-Object System.IO.MemoryStream $Image.Save($MemoryStream, $Image.RawFormat) [System.Byte]$Bytes = $MemoryStream.ToArray() $Base64 = [System.Convert]::ToBase64String($Bytes) $Image.Dispose() $MemoryStream.Dispose() $Base64 | out-file "C:\Temp\News_imab.txt"
More Toast Options
I’ve included some more options in the Powershell script in the very end: Deadline information and snooze action.
<# Deadline information. Add this into the toast XML for additional information about upcoming deadline <group> <subgroup> <text hint-style="base" hint-align="left">Your deadline:</text> <text hint-style="caption" hint-align="left">$(Get-Date -Date $Deadline -Format "dd MMMM yyy HH:mm")</text> </subgroup> </group> #> <# Snooze action. Copy this into the toast XML for added snooze functionality <actions> <input id="snoozeTime" type="selection" title="Click Snooze to be reminded in:" defaultInput="15"> <selection id="15" content="15 minutes"/> <selection id="60" content="1 hour"/> <selection id="240" content="4 hours"/> <selection id="480" content="8 hours"/> </input> <action activationType="protocol" arguments="$Application" content="Install now" /> <action activationType="system" arguments="snooze" hint-inputId="snoozeTime" content=""/> <action activationType="system" arguments="dismiss" content="Not now"/> </actions> #>
Deadline is obviously meant to be aligned with a required deployment in SCCM. The snooze option is self-explanatory, though not something I intent to use. If you enable these “features”, the toast will look similar to the example below.
Putting It All To Use
The use case here is all based on my own environment and the way I do Windows Servicing. I’m using the Powershell script creating the toast in a old school package in SCCM. The few details are as following:
- Save the New-ToastNotification.ps1 onto your source file library
- Create a package with source files containing the Powershell script
- Create a Program running the Powershell script in USER context
- Command line: powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File .\New-ToastNotification.ps1
Here are some screenshots of that process for your convenience, though it’s very basic SCCM:
The toast notification is only relevant for computers/users who haven’t run the IPU already, but also computers where all of our Pre-Checks has passed and thus the same collection as we use for deploying the actual IPU TS.
EXCLUDING the collection, where the upgrade has completed (we don’t want to remind users about an installation they already completed):
Run the toast notification on a schedule. For example every day at noon or whatever suits your needs:
These numbers are astonishing. The deployment of the Windows upgrade is so far only made AVAILABLE and thus, all of these succeeded upgrades are due to voluntary user participation after 1 day.
Now, this environment is still based on a mid-size company in Denmark, and I only manage 1000 (one thousand) devices roughly, but 18% user-participation is 18% – regardless of the size.
63 thoughts on “Windows as a Service: Remind users of pending Windows upgrades using Windows toast notifications, part 3”
To replace the image, what resolution does the image need to be?
Hey Mike, mine is 360*150 pixels 🙂
Just to save others time if they need the specific resolution, the hero image dimensions are 364×180 pixels at 100% scaling. we had to center our company logo and after playing around, we looked it up.
What is stopping it from spamming the user with multiple notifications.
If i just take the script and run it over and over again i get multiple notifications.
So let’s say i leave the computer on over the weekend and when i come back i can have several of them?
Or if a user just snooze for a week will it build up with one additional everyday?
Hey Fredrik, only one toast will be active at a time, though if the first isn’t dismissed the subsequent will displayed immediately thereafter. This is due to the nature of the toast being a reminder and doesn’t dismiss itself. You can change that behavior changing this: toast scenario=”reminder” from reminder to long or short.
Snooze functionality isn’t well suited for a reminder which requires the user to dismiss it. So you are right, if you run this on a schedule and none of them are dismisses because the computer is left on over the weekend, the user might find several reminders to be dismissed. You will have to work around that, if that’s a scenario you don’t want.
A great alternative is to use a scheduled task instead with a trigger that doesn’t build up several toast notifications 🙂
wonderfully simple and elegant solution. Thank you! Something like this should have been baked into SCCM in the first place.
I can run this with no problem locally (ps admin, exec policy unrestricted) so the script is fine after my tweaks… when putting it to package it does not. I can see blue ps screen flashing rapidly when timer hits.
PS execution policy is set to bypass in Client Settings.
Program can run only when user is logged.
Run mode > run with users rights
Commandline is like yours.
Something is wrong… and cant figure it out. Like you said, very basic stuff, but… 🙂
Any help appreciated!
Hey and thank you 🙂 Does the script without your tweaks behave the same? 😮
Hi, it does the same with your original version. Could you show with more details how to do that package & deployment since the problem seems to be there most likely.
Although it should’t be so trivial. But i’m obviously missing something.
What in particular are you interested in to see? Have you tried messing around with the visibility? Hidden, normal etc. The flashing PS screen doesn’t sound right. The script is fire and forget and it’s Windows doing the toast.
You might want to add some troubleshooting steps in there to see how much of the script is actually being executed.
I cannot reproduce the scenario on two different environments I’m afraid 🙁
I had the same scenario. What i did was that i run the same script manually in PS, one with Admin rights, and one with user rights. The Admin PS always shows the Toast notification. The user one failed due to access denied to the log file. so the script fails to run, cannot write to file in “programdata” folder.
Hey, I find it weird that a default user doesnt have access rights to programdata. You may change the location directly in the script to something else. Or perhaps even create the folder manually c:\programdata\toastnotificationscript to see if it makes a difference.
Thanks for excelent scriptv 🙂 I’m trying to use your script for reminder to enduser for installation of Office update (monthly channel users). When i run the script localy everything work great; the user get redirected to correct update in Software Center when clicking the ‘Install now’ in the toast message. But when deploying it using SCCM nothing happens when user try to click ‘Install now’ in the notification toast. Any tips?
Hey, initial thought is around the context. How’s the Office update deployed vs. how’s the toast deployed. The toast runs in user context and thus browse the Software Center as the user. 🙂
Thanks for this.
I’ve made some modifications so it takes parameter input for the Title, Body texts and a PackageID to make it a bit more flexible. The PackageID addition allows it to have it automatically add the deadline to the text rather than having to manually match it with a deployment:
# Get the deadline:
$Program = gwmi -namespace ‘root\ccm\ClientSDK’ -query “SELECT * FROM CCM_Program WHERE PackageID = `’$PackageID`'”
$Deadline = $Program.ConvertToDateTime($Program.Deadline)
Then to ensure it doesn’t pop up when there’s no actual required deployment for the specified PackageID:
# Display the toast notification
So now i only need one Package where i can just add/deploy Programs with command lines like this:
“C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe” -Executionpolicy bypass -file .\New-ToastNotification.ps1 -PackageID “PS100E80” -Title “SomethingSomethingDarkside” -Body1 “This is paragraph 1, where we tell you stuff is happening.” -Body2 “This is paragraph 2, where we show you more text that you probably won’t read.”
Great idea – thanks for sharing 🙂
Little issue I’ve run into that I’m hoping you fixed somewhere. How did you get past the Application showing as having failed immediately after it’s launched the TS to run the upgrade because the detection criteria for the app (the reg key UpgradeStatus being set to “0”) hasn’t been set at that point so the App thinks it’s failed.
Hi Andy, the first thought here was that it should fail and then have the detection method being applied during the TS and then run a application evaluation also during the TS, but I actually changed this in SCCM 1810 seeing we now have the option to repair applications. So I’ve reverted to correctly applying the dection method in the application but also enabled the repair option on the application in case something goes wrong and the TS is not being run. Hope that makes sense 🙂
Have you thought about adjusting this script to handle Software Updates with Config Mgr? More specifically giving the user the option to choose the reboot time themselves within a deadline.
The built-in notification system for reboot in the config mgr client needs improvement. I know that a lot of sysadmins who would love this feature.
Let me know if that’s something you’d consider 🙂
Yeah, the uses for the toast mechanism can be many and I currently have a few plan on expanding the options and flexibility of the script. Thank you for letting me know 🙂
Thanks for this, really useful.
One point, I had to remove .\ from the command line for the toast notification to pop up (so it now reads powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File New-ToastNotification.ps1) Otherwise I was getting an empty PowerShell window appear for a moment and then the package failed.
One question too, is there a way to add some intelligence to the toast script so that it will only run on 1703? I have deployed to a user collection and it is showing up on computers that already have 1803.
Thanks! Yes, I will add some logic to the script so it detects the OS. Initially I relied on the collection updating it’s members, but I see how it’s more convenient to have that in the script. Standby 🙂
This is only possible with an application right? I’m not able to call a task sequence directly with this method?
Correct. I haven’t found a way to do so, but I’m also leveraging Powershell App Deployment Toolkit with an application to initiate the actual task sequence for even further user friendliness 🙂
Thanks for this great tuto !
I am currently trying to do the exact same thing. I think this will do the job : https://ccmexec.com/2017/09/launching-a-task-sequence-using-an-application-link-in-configmgr-1706/
I did mention how you can execute a task sequence from an application, but thank you 🙂
Thanks for all your work I will use it for the IPU Windows 10.
I just have one problem when running the application to run the TS it says it installed en then it finished, it doesn’t start the actual task sequence. When starting this script manual then the actual TS will run.
Thanks for this great script!
I have a problem with one thing that I cannot figure out.
When I run this from sccm to a computer, it works when the user is local admin but not when the user don’t have admin rights. Is this by design and would it be possible to get this working for non admin user?
Hey, no, this is not something I require in the script. I’ve tested this for non-admin users and everything displays just fine 🙂
Execution is complete for program Run Toast Notification. The exit code is 0, the execution status is Success
i get this success in sccm log but then i get when i run it manually:
VERBOSE: No HeroImage file set as parameter. Using local image file
VERBOSE: No LogoImage file set as parameter. Using local image file
VERBOSE: Successfully loaded C:\temp\GPFiles\Tools\config-toast-rebootpending.xml
VERBOSE: Loading xml content from C:\temp\GPFiles\Tools\config-toast-rebootpending.xml into variables
VERBOSE: Successfully loaded xml content from C:\temp\GPFiles\Tools\config-toast-rebootpending.xml
VERBOSE: PendingRebootCheck set to True. Checking for pending reboots
VERBOSE: Running Test-PendingRebootRegistry function
VERBOSE: Check returned TRUE on ANY of the registry checks: Reboot is pending!
VERBOSE: Running Test-PendingRebootWMI function
VERBOSE: Computer has SCCM client installed – checking for pending reboots in WMI
VERBOSE: Check returned false on checking WMI for pending reboot: Reboot is not pending!
VERBOSE: Creating the xml for no dismiss button
VERBOSE: Toast notification is used in regards to pending reboot registry. TestPendingRebootRegistry returned True
VERBOSE: All good. Displaying the toast notification
VERBOSE: Something went wrong when displaying the toast notification
I get this error when i run it manually without admin rights and this works when i am admin…
New-Object : Cannot create type. Only core types are supported in this language mode.
At C:\temp\GPFiles\Tools\New-ToastNotification.ps1:615 char:17
+ $ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
+ CategoryInfo : PermissionDenied: (:) [New-Object], PSNotSupportedException
+ FullyQualifiedErrorId : CannotCreateTypeConstrainedLanguage,Microsoft.PowerShell.Commands.NewObjectCommand
You cannot call a method on a null-valued expression.
At C:\temp\GPFiles\Tools\New-ToastNotification.ps1:616 char:5
+ CategoryInfo : InvalidOperation: (:) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Found the problem, it was our applocker that prevented the script from running…
It seems that this script does not work when using applocker, ideas?
Here is a link to explaining the problem:
Sorry for the late reply. I assume if you digitally sign the script and approve the publisher in AppLocker, that would do the trick. I know the script currently runs with restricted language with applocker, but signing and approving the publisher should do it.
Tried with signing and approving but the problem is not with the script but rather with __PSScriptPolicyTest*.ps1/psm1 files that are used to determine which Language Mode PowerShell will run in, they are blocked by applocker.
The program is installed as specified inside of the folder programdata. A new task was created as per the instructions. But, the task does not run by itself. I have to manually launch the task. Then, if I hit refresh on the right side, the task stops immediately. Not sure why? And, just did a test installing new windows updates with a pending restart and the toast notification did not pop. Any ideas?
First of thank you for sharing the code and documenting everything, it really helps the community as a whole! By chance has anyone been able to get the Toast Notification to not just launch the Software Center\Task Sequence but launch the ScopeID defined?
I am trying to get the Install option to launch the “Available” Application\Task Sequence without further User Interaction.
how swap out that http://www.imad.dk with an internal url to a wiki or document or should I look at adding that to some other location?
You can edit that in the .xml if you download the toast notification script from here: https://www.imab.dk/windows-10-toast-notification-script/ 🙂
Right but I meant how do you add an actual URL – so they can click on it and go to a URL we specify like an internal web page
Oh, that’s something I will have to look into – I haven’t tried that myself. Thanks 🙂
No experience with XML, how could I add an action to schedule to install?
I’m trying to get the image replaced but although my image is 364*132px it is still not fully showing.
There’s a section about the image being in base64 code in the script but I guess that is no longer valid and hasn’t got anything to do with my issue right?
Depending on what image you are trying to replace, the dimensions should be 364×180 pixels at 100% scaling. The base64 code is a bad idea, as it really takes up a lot of characters. Just include a real image file. See: https://www.imab.dk/windows-10-toast-notification-script/
I am trying to run the script from a unc path i get an error
Something is not right about toast nofications in Windows
No config file set as parameter. Using local config file
can you please let me know how can i run this file from UNC Path and task scheduler
Hi. Don’t run the actual script from an UNC path. Run it locally, while the config file may be a UNC path.
Thanks a ton working..
Can you be more specific, run it locally?
Hey, don’t call the script from a network share. You may place the config files on a network share, but the script cannot. If run with Configuration Manager, the script is run locally from the ccmcache. That’s what I meant with locally 🙂
Hi This is an awesome project!
But I seem to be struggling to get the toast notifications to appear, despite it saying that they are being delivered. Ive tried on a couple of machines 1803,1809, they are AAD Joined only with Intune MDM.
Below is my log. The only thing which is obvious is the message “Something is not right about toast notifications in Windows”. The script will run, but toasts might not be displayed” when I check what determines this which is the Reg key under HKCU\Software\Microsoft\Windows\CurrentVersion\PushNotifications I add it an no longer get the warning but I still dont get the notifications. All other Toast notifications seem to be working without issue.
Any help would be much appreciated.
2019-09-27 12:55:02 INFO: Running supported version of Windows. Windows 10 and workstation OS detected
2019-09-27 12:55:02 INFO: Something is not right about toast notifications in Windows. The script will run, but toasts might not be displayed
2019-09-27 12:55:02 INFO: No config file set as parameter. Using local config file
2019-09-27 12:55:02 INFO: Successfully loaded C:\ProgramData\ToastNotificationScript1.4.2\config-toast.xml
2019-09-27 12:55:02 INFO: Loading xml content from C:\ProgramData\ToastNotificationScript1.4.2\config-toast.xml into variables
2019-09-27 12:55:03 INFO: Successfully loaded xml content from C:\ProgramData\ToastNotificationScript1.4.2\config-toast.xml
2019-09-27 12:55:03 INFO: PendingRebootCheck set to True. Checking for pending reboots
2019-09-27 12:55:03 INFO: Running Test-PendingRebootRegistry function
2019-09-27 12:55:03 INFO: Check returned TRUE on ANY of the registry checks: Reboot is pending!
2019-09-27 12:55:03 INFO: Running Test-PendingRebootWMI function
2019-09-27 12:55:03 WARNING: Computer has no SCCM client installed – skipping checking WMI for pending reboots
2019-09-27 12:55:03 INFO: Greeting with given name selected. Replacing HeaderText
2019-09-27 12:55:04 INFO: Running Get-GivenName function
2019-09-27 12:55:08 WARNING: Current security context is not associated with an Active Directory domain or forest..
2019-09-27 12:55:08 INFO: Given name not found in AD or no local AD available. Continuing looking for given name elsewhere
2019-09-27 12:55:08 INFO: Creating the xml for displaying both action button and dismiss button
2019-09-27 12:55:08 WARNING: Conditions for displaying toast notifications for UpgradeOS are not fulfilled
2019-09-27 12:55:08 WARNING: Conditions for displaying toast notifications for pending reboot uptime are not fulfilled
2019-09-27 12:55:08 INFO: Toast notification is used in regards to pending reboot registry. TestPendingRebootRegistry returned True
2019-09-27 12:55:08 INFO: All good. Displaying the toast notification
Ignore my comment just noticed SCCM client as a requirement
SCCM is not per say a requirement. How are you running the script? According to your log, pending reboots are found in the registry and not in WMI with the SCCM client because it’s not installed, but the toast should display regardless. You just need to use Powershell as the app in the config: “UsePowershellApp” Enabled=”True”
How to remove the toast notification once the upgrade is completed?
If you are using my latest script, you will have the option to only target specific OS builds. Once the OS upgrade finishes and the build number now matches the destination OS build, the notification will no longer display.
Hi Martin, a great script and will prove invaluable for our OS and software upgrades. Just one question, sorry if this already filtered through and pending. A portion of our estate is still on Windows 10 version 1511 and we’d like to add this approach to help the take-up of the upgrade. When we tried this and although the toast appears, graphics and body text do not display – is there a limitation in this OS version? We have tested a version that was adapted for Windows 7, that’s fine but far less functional.
Yes, I’m afraid the logics behind the actual toast notification lies within the OS itself, and coming 1709 Microsoft added several other possibilities, such as images and new text elements.
Can this be modified to detect a required application deployment rather than OS Upgrade? We need to create a toast notification for users to be aware of a required app we are deploying that requires a reboot, but also want to give the users adequate time to postpone install with a defined deadline?
Been playing with this and although i’m adding in the Software Center scope ID for the application, when clicking install on the toast notification, it brings up OS Updates menu in Software Center and does not trigger the install of the application. What am i missing?
Sure, you can reference an application instead and also grab the deadline of this with the dynamic deadline option. If you’re still being sent to the OSUpgrade page, something is not right in your config.xml 🙂
This script is great. However, I cannot get it to display notification on a v1709 system in our environment. v1809 works great, but same script, deployed in same way (via SCCM) will not display a notification on a 1709 system. thoughts?
I have a quick question: I am running ToastNotification as a test and standalone before adding to ConfigMgr. I am using the tag successfully when I click ‘Install Now’. However, is there any way to hide the cmd prompt flashing up (ToastRunApplicationID.cmd)? It’s not a biggie but would be nice to not see it!
Yeah, the prompt shows due to the nature of command prompt being a command prompt. If you want it to be completely silent, you could leverage some vbs code to initiate the powershell script instead. Or even if calling the powershell script directly from the custom protocol. The latter I haven’t tried though.
Programmers and their annoying toast notifications leave me alone!!!!! Stop with your awful UI practices! shit
Appreciate the feedback! 🙂