How to notify logged-on users

You may have already seen or know how to display a nice pop-up toast notification to your Windows 10 users.
If not, I’d like to point out some material related to these notifications:

Now, that you’re familiar with the notifications part, let’s see how to display them.
Being a big fan of what’s robust and sustainable, I’ll show you how to leverage the built-in Windows 10 scheduled tasks to notify your users 😀

Let’s say you have a PowerShell script that triggers a notification in the end-user context. It’s named toast.ps1.
Let’s say you’ve a Group Policy (GPO) that runs a scheduled task under the NT AUTHORITY\System account.

How can you escape the SYSTEM account and run the Toast.ps1 in every interactively logged on standard account?

Well, the solution is to identify these interactively logged on users and run a new scheduled task that targets their identity.

# Identify interactive users
try {
 $Users = @(Get-WmiObject -Query 'Select *  from Win32_Process' -ErrorAction Stop) |
 Where-Object { $_.ProcessName -eq 'explorer.exe'} |
 ForEach-Object {
   User = '{0}\{1}' -f $($_.GetOwner().Domain),$($_.GetOwner().User)
} catch {
 Write-Warning -Message "Failed to get logged on users because $($_.Exception.Message)"
# If any and hour is 10AM for example, notify
if ($Users -and ((Get-Date).ToString('HH',[Globalization.CultureInfo]::InvariantCulture) -in '10')) {
 $Users | ForEach-Object {
 Start-UserNotification -UserName $_ -Prefix 'WhatEver' -FilePath 'C:\Toast.ps1'

Here’s the code sample of the Start-UserNotification function used above:

#Requires -RunAsAdministrator
Function Start-UserNotification {
Start a script in the user context
Start a script in the user context using scheduled tasks
String that represents the targeted user name
String that represents the path to the script to be executed
String that is being used to prefix the task name
Start-UserNotification -UserName LocalUserName -FilePath C:\notif.ps1
[ValidateScript({Test-Path -Path $_ -PathType Leaf})]
Begin {
$errHT = @{ ErrorAction = 'Stop' }
$cmd = '& {0}' -f [Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($FilePath)
$aHT = @{
Execute = 'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe'
Argument = '-NoProfile -WindowStyle Hidden -Exec Bypass -Command "{0}"' -f "$($cmd)"
Process {
End {
# Notify user using a Scheduled task
try {
$taskName = '{0}-Notify' -f [regex]::Escape($Prefix)
Get-ScheduledTask -TaskPath '\' @errHT | Where-Object { $_.TaskName -match "^$($taskName)_" } | ForEach-Object {
if ($pscmdlet.ShouldProcess("$($_.TaskName)", 'Remove previous task')) {
$null = $_ | Stop-ScheduledTask -Verbose @errHT
$null = $_ | Unregister-ScheduledTask -Verbose -Confirm:$false @errHT
Write-Verbose -Message "Successfully remove task $($_.TaskName)"
} catch {
Write-Warning -Message "Failed to stop and unregister because $($_.Exception.Message)"
try {
$HT = @{
TaskName = '{0}_{1}' -f "$($taskName)","$($UserName)"
User = '{0}' -f "$($UserName)"
Force = [switch]::Present
Action = (New-ScheduledTaskAction @aHT @errHT)
Settings = (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -Compatibility 'Win8' @errHT)
if ($pscmdlet.ShouldProcess("$($HT['TaskName'])", 'Create and run task')) {
$null = Register-ScheduledTask @HT @errHT | Start-ScheduledTask @errHT
Write-Verbose -Message "Successfully created and ran task $($HT['TaskName'])"
} catch {
Write-Warning -Message "Failed to register and run notification task because $($_.Exception.Message)"

Here’s how to use the function:

1 thought on “How to notify logged-on users

  1. Pingback: Dew Drop – January 27, 2021 (#3368) – Morning Dew by Alvin Ashcraft

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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