With my recently released RunAsUser module there’s been an influx of questions on what it could be used for. I’ve tried to describe as much as possible on the github page and the previous blog about it. But one I wanted to talk about real quick is the ability to create Toast notifications.
Toast notifications are those little OS native notifications you side in the bottom right of your screen when receiving an e-mail. Our RMM system has the ability to create a notification using an application, but to be honest that notification looks like it came straight out of 1990.
To have a bit better user experience, and to also get the ability to do specific things with user-input I’ve decided to use Burnt Toast. Burnt Toast is a module that give you the ability to generate pretty toast messages with just a couple lines of code. Brilliant really!
Combining my RunAsUser module, and Burnt Toast we’re able to send a script to the currently logged on user’s session and get full functionality in there. One example is to reboot the computer after updates. So lets get going!
The script
The following script can be used to create a toast for reboots. It creates a ‘protocol handler’. It then toasts with a nice Gif of my logo to get the users attention. The script assumes you have trusted the PSGallery before hand.
#Checking if ToastReboot:// protocol handler is present New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT -erroraction silentlycontinue | out-null $ProtocolHandler = get-item 'HKCR:\ToastReboot' -erroraction 'silentlycontinue' if (!$ProtocolHandler) { #create handler for reboot New-item 'HKCR:\ToastReboot' -force set-itemproperty 'HKCR:\ToastReboot' -name '(DEFAULT)' -value 'url:ToastReboot' -force set-itemproperty 'HKCR:\ToastReboot' -name 'URL Protocol' -value '' -force new-itemproperty -path 'HKCR:\ToastReboot' -propertytype dword -name 'EditFlags' -value 2162688 New-item 'HKCR:\ToastReboot\Shell\Open\command' -force set-itemproperty 'HKCR:\ToastReboot\Shell\Open\command' -name '(DEFAULT)' -value 'C:\Windows\System32\shutdown.exe -r -t 00' -force } Install-Module -Name BurntToast Install-module -Name RunAsUser invoke-ascurrentuser -scriptblock { $heroimage = New-BTImage -Source 'https://media.giphy.com/media/eiwIMNkeJ2cu5MI2XC/giphy.gif' -HeroImage $Text1 = New-BTText -Content "Message from IT" $Text2 = New-BTText -Content "Your IT provider has installed updates on your computer at $(get-date). Please select if you'd like to reboot now, or snooze this message." $Button = New-BTButton -Content "Snooze" -snooze -id 'SnoozeTime' $Button2 = New-BTButton -Content "Reboot now" -Arguments "ToastReboot:" -ActivationType Protocol $5Min = New-BTSelectionBoxItem -Id 5 -Content '5 minutes' $10Min = New-BTSelectionBoxItem -Id 10 -Content '10 minutes' $1Hour = New-BTSelectionBoxItem -Id 60 -Content '1 hour' $4Hour = New-BTSelectionBoxItem -Id 240 -Content '4 hours' $1Day = New-BTSelectionBoxItem -Id 1440 -Content '1 day' $Items = $5Min, $10Min, $1Hour, $4Hour, $1Day $SelectionBox = New-BTInput -Id 'SnoozeTime' -DefaultSelectionBoxItemId 10 -Items $Items $action = New-BTAction -Buttons $Button, $Button2 -inputs $SelectionBox $Binding = New-BTBinding -Children $text1, $text2 -HeroImage $heroimage $Visual = New-BTVisual -BindingGeneric $Binding $Content = New-BTContent -Visual $Visual -Actions $action Submit-BTNotification -Content $Content }
And that’s it! you must be wondering how it looks, so lets show you that too!

And that’s it! as always, Happy PowerShelling!
Hi Kelvin!
As always, thank you for your amazing scripts. I am working on getting this one working, it was not working for me, so I added a start-transcript command and stop-transcript to capture what was gong on. Below is the output I am getting when running this using the 64-bit version of powershell as the SYSTEM user through my RMM. Any ideas on this?
invoke-ascurrentuser : Could not execute as currently logged on user: Exception calling “StartProcessAsCurrentUser”
with “4” argument(s): “CreateProcessAsUser failed. (Access is denied, Win32ErrorCode 5 – 0x00000005)”
At RebootNotifications.ps1:25
char:1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], MethodInvocationException
+ FullyQualifiedErrorId : System.Management.Automation.MethodInvocationException,Invoke-AsCurrentUser
invoke-ascurrentuser : Could not execute as currently logged on user: Exception calling “StartProcessAsCurrentUser”
with “4” argument(s): “CreateProcessAsUser failed. (Access is denied, Win32ErrorCode 5 – 0x00000005)”
At RebootNotifications.ps1:25 char:1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], MethodInvocationException
+ FullyQualifiedErrorId : System.Management.Automation.MethodInvocationException,Invoke-AsCurrentUser
Any help you can provide would be most appreciated!
Cheers!
JustMirsk
This really looks like it either couldn’t access the PowerShell executable, or that it could not create a process due to not having enough permissions.
What RMM are you using? could you try executing this with your RMM:
$pwshPath = (Get-Process -Id $pid).Path
write-host $pwshPath
This should show the command it tries to pass to RunAsUser.
Thanks for the really fast reply! Here is the output from the script, I ran a start and stop transcript so you can see everything that gets output.
**********************
Transcript started, output file is c:\temp\powershell.log
C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe
**********************
Windows PowerShell transcript end
End time: 20200719181625
**********************
I don’t see anything specifically wrong here. I have other powershell scripts that do run as SystemUser (at least I have them set to run as System User and they execute with elevated privileges without having to provide credentials etc).
I am running a lesser known RMM, Naverisk. Naverisk natively will run PowerShell with C:\WINDOWS\SysWOW64\WindowsPowerShell\v1.0\powershell.exe. I am specifically calling my powershell scripts with a batch file using the command of:
%SystemRoot%\sysnative\WindowsPowerShell\v1.0\PowerShell.exe -ExecutionPolicy Bypass -Command “Path to my PS1”
Same here using Powershell on my computer.
invoke-ascurrentuser : Could not execute as currently logged on user: Excepción al llamar a “StartProcessAsCurrentUser” con los argumentos “5”: “WTSQueryUserToken failed to get access
token. (El cliente no dispone de un privilegio requerido, Win32ErrorCode 1314 – 0x00000522)”
En línea: 16 Carácter: 1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], MethodInvocationException
+ FullyQualifiedErrorId : System.Management.Automation.MethodInvocationException,Invoke-AsCurrentUser
Do you have an EDR installed?
Thanks
Great script BTW 🙂
0x00000522 means a privilege cannot be obtained, so the token cannot be copied. This might be EDR, it could also be some permissions have been removed from the SYSTEM account.
Is there a way for that notification to stay until a user accepts it?
Too often users can claim they didn’t see the notification.
Hi Kelvin,
Thanks for another great script!
I’ve seen that you use N-Central and I was wondering how you would use this to replace the ugly pop-ups they use? I don’t know how you could detect if any patches were installed and if so, then run this command. Or do you just run it at a set time after the install element of a maintenance window?
Thanks,
Tom
We have maintenance policy without N-Central generated pop-up. We then check if updates have been installed using a monitoring script, and as self-healing run the script above. 🙂
When I run the script I get the PID returned to me, but nothing happens on screen. No errors from running the script. Any ideas?
the script doesn’t give any output directly, you’ll have to return the output from the script by redirecting it with |out-file or transcribing 🙂
I think I was confusing in what I was trying to describe, the toast notification does not come across for the user.
Hey Patrick,
I’m not sure if you’re still having this issue but I was able to resolve it on my RMM by utilizing the invoke-ascurrentuser at the end of script, with the contents of all the Toast notifications as the scriptblock.
So it effectively looks like this:
$scriptblock = { }
invoke-ascurrentuser -NonElevatedSession -scriptblock $scriptblock
I’m not certain why this allows it to work properly instead of outputting the PID.
Just to clarify , does this alert know to prompt when a windows update requires rebooting ? is it aware that updates are pending ?
Thanks
No, this just pop-ups the notification. You’ll have to use your RMM for the detection part. 🙂
So excited to use this but I’m having some of the same issues others have mentioned.
Specifically, when running this from a SYSTEM session, I get the PID returned very quickly, but nothing ever appears in the user session.
When I run from the user session, it works great.
Right now I’m testing using the backstage feature in CW Control before moving this into a CW Automate script.
Any thoughts or ways I can trap further error/issue information?
Hi Travis,
You can try a start-transcript in your scriptblock, so you can see exactly what happens during the running of the script.
Another option is to install the latest version of “RunAsUser” and use the switch “-UseWindowsPowershell”. I’ve seen some RMMs execute PowerShell as part of a process of another executable, so it would fail to run. Hope that helps!
Hi Kelvin I really appreciated for this Script.
I run the commands on powershellISE . I got the error.
Please Have look on the error message.
Name Property
—- ——–
command
invoke-ascurrentuser : The ‘invoke-ascurrentuser’ command was found in the module
‘RunAsUser’, but the module could not be loaded. For more information, run ‘Import-Module
RunAsUser’.
At line:16 char:1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (invoke-ascurrentuser:String) [], CommandNo
tFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
Can you run “Import-module RunAsUser” and show the output of that? 🙂
I just fixed the above issue, but now i have another one
invoke-ascurrentuser : The ‘invoke-ascurrentuser’ command was found in the module
‘RunAsUser’, but the module could not be loaded. For more information, run
‘Import-Module RunAsUser’.
At line:16 char:1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (invoke-ascurrentuser:String) [], Comma
ndNotFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
invoke-ascurrentuser : The ‘invoke-ascurrentuser’ command was found in the module
‘RunAsUser’, but the module could not be loaded. For more information, run
‘Import-Module RunAsUser’.
At line:16 char:1
+ invoke-ascurrentuser -scriptblock {
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (invoke-ascurrentuser:String) [], Comma
ndNotFoundException
+ FullyQualifiedErrorId : CouldNotAutoloadMatchingModule
Hi Kelvin,
Your Script is cool and it’s working fine.
This Script is only working on administrator user, Script is not working on non administartor users.
can you please fix this issue or could you please suggest here.
How to run the script on NON Administrator forcefully
Regards
Sahil
From the doc:
Sometimes you need to run an application that does not elevate itself, for this use the -NonElevatedSession switch:
$scriptblock = { “Hello world” | out-file “C:\Temp\HelloWorld.txt” }
invoke-ascurrentuser -NonElevatedSession -scriptblock $scriptblock
That should solve your predicament 🙂
#Checking if ToastReboot:// protocol handler is present
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT -erroraction silentlycontinue | out-null
$ProtocolHandler = get-item ‘HKCR:\ToastReboot’ -erroraction ‘silentlycontinue’
if (!$ProtocolHandler) {
#create handler for reboot
New-item ‘HKCR:\ToastReboot’ -force
set-itemproperty ‘HKCR:\ToastReboot’ -name ‘(DEFAULT)’ -value ‘url:ToastReboot’ -force
set-itemproperty ‘HKCR:\ToastReboot’ -name ‘URL Protocol’ -value ” -force
new-itemproperty -path ‘HKCR:\ToastReboot’ -propertytype dword -name ‘EditFlags’ -value 2162688
New-item ‘HKCR:\ToastReboot\Shell\Open\command’ -force
set-itemproperty ‘HKCR:\ToastReboot\Shell\Open\command’ -name ‘(DEFAULT)’ -value ‘C:\Windows\System32\shutdown.exe -r -t 00’ -force
}
Install-Module -Name BurntToast
Install-module -Name RunAsUser
$scriptblock = { “Hello world” | out-file “C:\Temp\HelloWorld.txt” }
invoke-ascurrentuser -NonElevatedSession -scriptblock $scriptblock
{
$heroimage = New-BTImage -Source ‘https://media.giphy.com/media/eiwIMNkeJ2cu5MI2XC/giphy.gif’ -HeroImage
$Text1 = New-BTText -Content “Message from IT”
$Text2 = New-BTText -Content “Your IT provider has installed updates on your computer at $(get-date). Please select if you’d like to reboot now, or snooze this message.”
$Button = New-BTButton -Content “Snooze” -snooze -id ‘SnoozeTime’
$Button2 = New-BTButton -Content “Reboot now” -Arguments “ToastReboot:” -ActivationType Protocol
$5Min = New-BTSelectionBoxItem -Id 5 -Content ‘5 minutes’
$10Min = New-BTSelectionBoxItem -Id 10 -Content ’10 minutes’
$1Hour = New-BTSelectionBoxItem -Id 60 -Content ‘1 hour’
$4Hour = New-BTSelectionBoxItem -Id 240 -Content ‘4 hours’
$1Day = New-BTSelectionBoxItem -Id 1440 -Content ‘1 day’
$Items = $5Min, $10Min, $1Hour, $4Hour, $1Day
$SelectionBox = New-BTInput -Id ‘SnoozeTime’ -DefaultSelectionBoxItemId 10 -Items $Items
$action = New-BTAction -Buttons $Button, $Button2 -inputs $SelectionBox
$Binding = New-BTBinding -Children $text1, $text2 -HeroImage $heroimage
$Visual = New-BTVisual -BindingGeneric $Binding
$Content = New-BTContent -Visual $Visual -Actions $action
Submit-BTNotification -Content $Content
}
And I want to run in simple PowerShell ise in any machine what i need to do.
Powershell 7 & BurntToast
It seems, that pwsh.exe is a requirement to use BurntToast with the Protocol Handler to execute scripts with a simple button.
How do u use PWSH.EXE within Datto RMM?
The example above uses PowerShell 5. The only reason for PowerShell 7 should be for the newer functionality.
Have you had any luck/experience implementing this through ConnectWise? Have tried a couple different implementations to no avail would love to have this available. Awesome script by the way.
I cannot figure out how to open Software center or ANY application with a button. can anyone help out?
Awesome work as always Kelvin!
In testing this on my end, underneath the hero image when the toast notification appears, it shows the PowerShell Icon, and then spells out ‘Windows PowerShell’ to the right of that icon, right above my message.
Your gif example shows the PowerShell icon neatly placed beside your $Text1 line ‘IT Message’. Is this a quirk of later feature releases of Windows 10 from when you first posted this, or did you do something differently?