I have a script running as Local System which does some stuff, including checking if it's a user logged on, and if yes, it runs a PowerShell snippet to show a toast notification, such as below.
If the PS runs as current user, it works ok. If it runs as LocalSystem, the current user does not see the toast because the output is sent Session 0 (for local system account).
Is it possible to display a toast notification to logged on user, if running as Local System and without requesting user's credentials?
Add-Type -AssemblyName System.Windows.Forms
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info
$balloon.BalloonTipText = "$Text"
$balloon.BalloonTipTitle = "$Title"
$balloon.Visible = $true
$balloon.ShowBalloonTip($Miliseconds)
It is possible to display a toast notification to the current active logged on user using PowerShell if running as the SYSTEM user in Session 0 without requesting the user's credentials.
Two solutions to do this follow the "Background Notes"
Please note that this section is written for all viewers of this post, rather than just the original questioner.
SYSTEM
refers to the synonyms NT Authority\SYSTEM
and Local System
.
Many Windows services run as the SYSTEM
user although others run as users with less privileges such as LOCAL SERVICE
and NETWORK SERVICE
.
For each logged in user a Windows session is created numbered from 1 which contains the user's windows.
An additional background session called Session 0 is also created which the Windows services and User Mode Drivers run in. More info at the following link.
Sessions, Desktops, and Windows Stations
All services except the Per-User Services run in Session 0.
If you are using a service for such a script I recommend looking at using one of the two alternatives below:
Create a Session 1 sub-process as already done by some services.
Use the Windows Task Scheduler
instead to run your main script or notification script in the same session as the current active user. This schedule task can be set to trigger on an event.
Note the following security caveat. Scripts in Powershell 5 can be interrupted giving control to a user. For Powershell 6 and later this behaviour is disabled by use of the noninteractive option.
Two solutions are presented below to solve the original problem. Both use an intervening program to move from Session 0 to Session 1.
Both will flash briefly a PowerShell window which is disconcerting for users and is hard to hide. Some hiding tips are provided in the link below.
How To Run A PowerShell Script Without Display a Window
The following solutions as typed require paths without spaces. Full paths must be used if given. You will have to edit these paths to suit.
Test methodology is included.
The first solution requires the PSExec.exe
program. It is part of PSTools
available at the following link. It is also used to test both solutions.
The second solution requires the ServiceUI.exe
program. It is part of the Microsoft Deployment Toolkit (MDT)
available at the following link.
Microsoft Deployment Toolkit (MDT)
The ServiceUI.exe
program is buried in the MDT
install directory as follows.
Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe
I copied it to E:\Programs\MDT\ServiceUI.exe
to make it simpler to use in PowerShell
BalloonTest.ps1
$Miliseconds=50000
$Text="Hi"
$Title="Test"
Add-Type -AssemblyName System.Windows.Forms
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path)
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info
$balloon.BalloonTipText = "$Text"
$balloon.BalloonTipTitle = "$Title"
$balloon.Visible = $true
$balloon.ShowBalloonTip($Miliseconds)
WhoAmISession.ps1
whoami
$Session=(Get-Process -PID $pid).SessionID
echo "Session=$Session"
Start a cmd.exe
window as the Administrator
.
The following command will provide a SYSTEM user Session 0 PowerShell execution environment as shown in the image.
E:\Programs\PSTools\psexec -s powershell.exe -file e:\test\WhoAmISession.ps1
To show the Toast notification in PowerShell
if running as the SYSTEM
user in Session 0
use the following command. This will show the Toast notification if the current active logged in user is using Session 1
. Some modification will be needed for other sessions.
E:\Programs\PSTools\psexec -s -i 1 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1
To test start a "cmd.exe"
window as the "Administrator"
and enter the following command. This will show the Toast notification if the current active logged in user is using Session 1
as shown in the image.
E:\Programs\PSTools\psexec -s powershell.exe E:\Programs\PSTools\psexec -s -i 1 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1
To show the Toast notification in PowerShell
if running as the SYSTEM
user in Session 0
use the following command. This will show the Toast notification to the current active logged in user.
E:\Programs\MDK\ServiceUI.exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1
To test start a "cmd.exe"
window as the "Administrator"
and enter the following command. This will show the Toast notification to the current active logged in user as shown in the image.
E:\Programs\PSTools\psexec -s powershell.exe E:\Programs\MDK\ServiceUI.exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1