Monitoring with PowerShell: Notifying users of Windows Updates

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!

12 thoughts on “Monitoring with PowerShell: Notifying users of Windows Updates

  1. Justin

    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

    Reply
    1. Kelvin Tegelaar Post author

      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.

      Reply
      1. Justin

        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”

        Reply
        1. luis

          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

          Reply
          1. Kelvin Tegelaar Post author

            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.

  2. Dan

    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.

    Reply
  3. Tom

    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

    Reply
    1. Kelvin Tegelaar Post author

      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. 🙂

      Reply
  4. Patrick

    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?

    Reply
      1. Patrick

        I think I was confusing in what I was trying to describe, the toast notification does not come across for the user.

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.