Для оповещения пользователей о различных событиях, вы можете выводить различные графические уведомления из скриптов PowerShell. В PowerShell можно использовать всплывающие уведомления в трее Windows или модальные окно для получения информации от пользователя или подтверждения действия.
You know, these things:
I have seen very convoluted code filled with various APIs to mimic this, but today, I wanted to show you a little of what we can do with VBA and PowerShell that should amaze you and goes far beyond what is possible via other techniques.
In the first section we will explore creating Notification Balloons using naive PowerShell (called from our VBA). In the second section, we’ll kick it up a notch and deploy an open-source PowerShell module that we enable us to create some truly remarkable notifications all from simple VBA calls.
So let’s dig in!
https://youtube.com/watch?v=tqyw62EMteM%3F
Add-Type -AssemblyName System.Windows.Forms
$NotifyIcon = [System.Windows.Forms.NotifyIcon]::new()
$NotifyIcon.ShowBalloonTip(5000, 'Title', 'Balloon Tip Text', 'Info')
This should pop a notification up in the tray but nothing happens?
I tried this on two separate machines–one Windows 11 and one Windows 10, but it didn’t work on either.
Most of the search results reference the Windows.UI.Notifications
namespace and something called “Toast” notifications. But I want to avoid using that since it requires additional dependencies and I know the NotifyIcon
method has worked in the past.
So how can I accomplish this?
The sample scripts provided below are adapted from third-party open-source sites.
PowerShell script to schedule notifications
Display notification as pop-up box
#$actions = New-ScheduledTaskAction -Execute ‘powershell.exe’ -Argument $command “-ExecutionPolicy unrestricted -WindowStyle Hidden -NoLogo -Command $command” |
Display notification as toast message
#$actions = New-ScheduledTaskAction -Execute ‘powershell.exe’ -Argument $command “-ExecutionPolicy unrestricted -WindowStyle Hidden -NoLogo -Command $command” |
What happens at the device end?
Pop-up box notifications
Toast notifications
Вывести всплывающее сообщение на экран с помощью PowerShell
Для вывода простых модального диалогового окна в Windows можно воспользоваться Wscript классами подсистемы сценариев Windows. Следующий PowerShell код выведет обычное текстовое окно с вашим текстом и кнопкой OK.
$wshell = New-Object -ComObject Wscript.Shell
$Output = $wshell.Popup("Скрипт формирования отчета выполнен")
Вы можете настроить вид модального окна такого сообщения и добавить кнопки действия для пользователей. Например, чтобы вывести всплывающее окно с кнопками Да и Нет, выполните:
$Output = $wshell.Popup("Скрипт формирования отчета завершен! Хотите вывести его на экран?",0,"Отчет готов",4+32)
Если пользователь нажмет Да, команда вернет значение
6
, а если Нет –
7
.
В зависимости от выбора пользователя вы можете выполнить какое-то действие, или завершить скрипт.
switch ($Output) { 7 {$wshell.Popup('Нажата Нет')} 6 {$wshell.Popup('Нажата Да')} default {$wshell.Popup('Неверный ввод')} }
Общий синтаксис и параметры метода Popup:
- <Text> — текст сообщения.
- <SecondsToWait> — необязательный, число. Количество секунд, по истечении которого окно будет автоматически закрыто.
- <Title> — текст заголовка окна сообщения (необязательный параметр).
- <Type> — комбинация флагов, определяет тип кнопок и вид значка (числовое значение, не обязательный параметр). Возможные значения флагов:
- 0 — кнопка ОК.
- 1 — кнопки ОК и Отмена.
- 2 — кнопки Стоп, Повтор, Пропустить.
- 3 — кнопки Да, Нет, Отмена.
- 4 — кнопки Да и Нет.
- 5 — кнопки Повтор и Отмена.
- 16 — значок Stop.
- 32 — значок Question.
- 48 — значок Exclamation.
- 64 — значок Information.
Команда PowerShell возвращает целое значение, с помощью которого можно узнать, какая кнопка была нажата пользователем. Возможные значения:
- -1 — таймаут.
- 1 — кнопка ОК.
- 2 — кнопка Отмена.
- 3 — кнопка Стоп.
- 4 — кнопка Повтор.
- 5 — кнопка Пропустить.
- 6 — кнопка Да.
- 7 — кнопка Нет.
Если нужно показать пользователю окно ввода и запросить данные, воспользуйтесь классом Windows Forms.
Чтобы обработать введенные пользователе данные:
if ([string]::IsNullOrWhiteSpace($input)) { Write-Host "Данные не указаны" } else { Write-Host "Вы ввели $input" }
Если нужно вывести всплывающее окно поверх всех окон, используйте команду:
Notice About Content/Downloads/Demos
Disclaimer/Notes:
If you do not have Microsoft Access, simply download and install the freely available runtime version (this permits running MS Access databases, but not modifying their design):
Microsoft Access 2010 Runtime
Microsoft Access 2013 Runtime
Microsoft Access 2016 Runtime
Microsoft 365 Access Runtime
Showing a Pop-Up Message on Remote Computer Using PowerShell
MSG jsmith /server:Mun-RDS1 "Please restart the SUPGUI client in 5 minutes!”
MSG * /server:Mun-RDS1 " The server will be restarted in 10 minutes. Save your files and open documents!"
To send a pop-up graphical notification to a remote computer, you can use the RemoteSendToasNotification.ps1 script from our GitHub repo ( https://github.com/maxbakhub/winposh/blob/main/WindowsDesktopManagement/RemoteSendToasNotification.ps1). The Invoke-Command cmdlet that is used to establish the connection requires that WinRM be enabled and configured on the remote computer.
Отправка сообщения пользователю на удаленный компьютер
С помощью PowerShell вы можете отправить всплывающее сообщение пользователю на удаленный компьютер. Сначала нужно получить список сессии пользователей на удаленном компьютере (в случае RDS сервера):
Чтобы отправить сообщение в сессию пользователя на удаленном компьютер, выполните команду:
MSG kbuldogov /server:rds1 "Сервер будет перезагружен через 10 минут. Закройте документы"
Если всплывающее сообщение нужно отправить всем пользователям укажите * вместо имени пользователя:
MSG * /server:rds1 "Срочное сообщение всем! "
Для отправки всплывающего графического уведомления на удаленный компьютер можно воспользоваться скриптом RemoteSendToasNotification.ps1 из нашего GitHub репозитория ( https://github.com/winadm/posh/blob/master/scripts/RemoteSendToasNotification.ps1). Для подключения к удаленному компьютеру используется командлет Invoke-Command, который использует WinRM.
Page History
Date | Summary of Changes |
---|---|
2024-02-08 | Initial Release |
2024-02-09 | Added Updated BurntToast code eliminating the need for a Helper Function |
2024-02-15 | Added BurntToast Demo Database |
Display a Pop-Up Message with PowerShell
$wshell = New-Object -ComObject Wscript.Shell
$Output = $wshell.Popup("The report generation script is successfully completed!")
Using the various properties of the Popup method, you can customize the appearance of this modal window and add action buttons to it. For example, to display a pop-up prompt with Yes and No buttons, run:
$Output = $wshell.Popup("The script completed successfully. Do you want to view a report?",0,"The report is ready",4+32)
switch ($Output) { 7 {$wshell.Popup('Pressed No')} 6 {$wshell.Popup('Pressed Yes')} default {$wshell.Popup('Invalid input')} }
The general syntax and the available parameters of the Popup method:
- <
Text
> — a message text (string); - <
SecondsToWait
> —a number (optional). Number of seconds before the message window closes automatically; - <
Title
> —string (optional). The title text (caption) of the pop-up window; - <
Type
> —number (optional). A combination of flags that determine the type of buttons and icons.
Possible values for the Type flag:
- 0 — only OK button;
- 1 — OK and Cancel;
- 2 — Stop, Retry, and Skip;
- 3 — Yes, No, and Cancel;
- 4 — Yes and No;
- 5 — Retry and Cancel;
- 16 — Stop icon;
- 32 — Question icon;
- 48 — Exclamation icon;
- 64 — Information icon.
- -1 — timeout;
- 1 — OK button;
- 2 — Cancel button;
- 3 — Stop button;
- 4 — Retry button;
- 5 — Skip button;
- 6 — Yes button;
- 7 — No button.
if ([string]::IsNullOrWhiteSpace($input)) { Write-Host " No information provided" } else { Write-Host " You have entered $input" }
If you want to display a modal dialogue on top of all windows on the desktop:
Вывести уведомление пользователю Windows из скрипта PowerShell
С помощью класса Windows Forms можно вывести более красивые всплывающие сообщения (ballons). Следующий скрипт выведет всплывающее сообщение рядом с панелью уведомлений Windows, которое автоматически исчезнет через 10 секунд:
Для создания красочных всплывающих сообщений в Windows можно использовать отдельный PowerShell модуль BurntToast.
Установите модуля из PowerShell Gallery:
Install-Module -Name BurntToast
Теперь, например, в ранее рассматриваемый скрипт автоматического отключения от Wi-FI сети при подключении к Ethernet можно добавить уведомление с картинкой:
New-BurntToastNotification -Text "Отключение от Wi-Fi сети", "Вы были отключены от Wi-Fi сети, т.к. Вше устройство было подключено к скоростному Ethernet подключению." -AppLogo C:\PS\changenetwork.png
Basic Notifications
Basic PowerShell Windows Notifications
Before developing VBA code to run PowerShell code, we need to have our PowerShell commands ready.
A little digging online, a little playing around in the PowerShell ISE and it doesn’t take long to come up with something like:
[reflection.assembly]::LoadWithPartialName('System.Windows.Forms'); [reflection.assembly]::LoadWithPartialName('System.Drawing'); $notification = New-Object System.Windows.Forms.NotifyIcon; $notification.Icon = [System.Drawing.SystemIcons]::Error; $notification.BalloonTipTitle = 'Title'; $notification.BalloonTipText = 'Text'; $notification.Visible = $true; $notification.ShowBalloonTip(3000);
or here, we switch out the PowerShell icon for Microsoft Access’
[reflection.assembly]::LoadWithPartialName('System.Windows.Forms'); [reflection.assembly]::LoadWithPartialName('System.Drawing'); $notification = New-Object System.Windows.Forms.NotifyIcon; $path = (Get-Process -id (get-process msaccess).id).Path; $notification.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path); $notification.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Error; $notification.BalloonTipTitle = 'Title'; $notification.BalloonTipText = 'Text'; $notification.Visible = $true; $notification.ShowBalloonTip(3000)
Once we had the basics of PowerShell notification commands, we were now ready to bring this over into VBA and create a simple wrapper function.
Now, before going any further, I am now going to present how to run PowerShell command via VBA in this article. I am simply going to use the command PS_Execute() which was presented in my article:
VBA – Run PowerShell Command
So if you’re not familiar with it, please review the above article and grab a copy of the function from there.
and this is what I did:
Public Sub DisplayWindowsNotification() Dim sCmd As String sCmd = "[reflection.assembly]::LoadWithPartialName('System.Windows.Forms');" & _ "[reflection.assembly]::LoadWithPartialName('System.Drawing');" & _ "$notification= New-Object System.Windows.Forms.NotifyIcon;" & _ "$notification.Icon = [System.Drawing.SystemIcons]::Error;" & _ "$notification.BalloonTipTitle = 'Title';" & _ "$notification.BalloonTipText = 'Text';" & _ "$notification.visible = $true;" & _ "$notification.ShowBalloonTip(3000);" Call PS_Execute(sCmd) End Sub
Now, we simply run it to produce:
So we’re in business! Of course, I don’t want to have to create hard-coded sub routines for every case. Instead, I want to create a flexible procedure that I can supply a few arguments to which would generate the custom notification I need. So I modified the above into something like:
Sub CreateWindowsNotification(sTitle As String, _ sMessage As String, _ sIcon As String) ' sIcon can be: Application, Asterisk, Error, Exclamation, Hand, Information, Question, Shield, Warning, WinLogo Dim sCmd As String sCmd = "[reflection.assembly]::loadwithpartialname('System.Windows.Forms');" & _ "[reflection.assembly]::loadwithpartialname('System.Drawing');" & _ "$notify = New-Object System.Windows.Forms.NotifyIcon;" & _ "$notify.Icon = [System.Drawing.SystemIcons]::" & sIcon & ";" & _ "$notify.BalloonTipTitle = '" & sTitle & "';" & _ "$notify.BalloonTipText = '" & sMessage & "';" & _ "$notify.visible = $true;" & _ "$notify.ShowBalloonTip(10);" Call PS_Execute(sCmd) End Sub
Thus, we can use a line such as:
Call CreateWindowsNotification("Production Database", "New Project Ready for Review.", "Information")
Just a heads up regarding the ShowBallonTip method. According to the documentation it takes a timeout parameter:
“The time period, in milliseconds, the balloon tip should display.“
Sadly, things have changed and if you continue reading it stated:
“This parameter is deprecated. Notification display times are now based on system accessibility settings.“
So the timeout value is now ignored, put whatever you’d like as it makes no difference. One more reason to look at the Advanced BurntToast approach instead.
PowerShell NotifyIcon Reference
NotifyIcon Class (System.Windows.Forms)
Specifies a component that creates an icon in the notification area. This class cannot be inherited.
Demo Database
Feel free to download a 100% unlocked copy of the sample database (tested on Win10/Acc365 & Win10/Acc2013):
Download “Windows Notification – BurntToast Demo”
Windows-Notifications-BurntTotast.zip – Downloaded 835 times – 48.42 KB
Advanced Notifications – Using VBA To Run BurntToast
Now the above is great, but there’s one issue that nagged me, and people mentioned to me as well. The fact that the notification heading always stated ‘Windows PowerShell’.
Yes, I could change the icon, but couldn’t find a way to change that title!
So I did some digging and came across an Open-Source project for creating notifications via PowerShell called ‘BurntToast’. From the examples I found online it was exactly what I was looking for and then some!
BurntToast Module
So the first thing we need to do, to be able to exploit BurntToast, is actually install it.
$ModuleName = "BurntToast" Try { $null = Get-InstalledModule $ModuleName -ErrorAction Stop } Catch { if ( -not ( Get-PackageProvider -ListAvailable | Where-Object Name -eq 'Nuget' ) ) { $null = Install-PackageProvider 'Nuget' -Force } $null = Install-Module $ModuleName -Force } $null = Import-Module $ModuleName -Force
Now click on the Run Script button (green arrow).
Give PowerShell a few moments to do it’s thing. That’s it.
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned
and if you wish to test out the new Module to ensure it is function you could simple execute:
New-BurntToastNotification -Text "It's alive!" -SnoozeAndDismiss
or you can use the shorthand syntax:
Toast -Text "It's alive!" -SnoozeAndDismiss
both should generate:
Now, that it’s all installed and operational, we are ready to delve into VBA!
A Work In Progress
Just to mention that I am exploring creating a VBA routine to perform the installation silently. More to come on this in the future.
VBA Code
So after messing around with the Burnt Toast module code for a while I ended up creating 2 procedures:
- Standard notification
- Progress bar notification
Standard notification
Public Sub DisplayWindowsToastNotification(ByVal sTitle As String, _ ByVal sMsg1 As String, _ Optional ByVal sMsg2 As String, _ Optional ByVal sAppLogo As String, _ Optional ByVal sAppId As String, _ Optional ByVal sSound As String = "Default", _ Optional bSnoozeDimiss As Boolean = False) On Error GoTo Error_Handler Dim sCmd As String sCmd = "$ToastHeader = New-BTHeader -Title '" & sTitle & "';" sCmd = sCmd & "Toast -Header $ToastHeader" ' short form -> can also do "New-BurntToastNotification -Header $ToastHeader" sCmd = sCmd & " -Text '" & sMsg1 & "'" If sMsg2 <> "" Then sCmd = sCmd & ", '" & sMsg2 & "'" If sAppLogo = "" Then sCmd = sCmd & " -AppLogo false" 'sCmd = sCmd & " -NoLogo" 'No Good Else sCmd = sCmd & " -AppLogo '" & sAppLogo & "'" End If If sAppId <> "" Then sAppId = GetFIleGUIDPath(sAppId) 'Convert path to use Known GUI (it's required!) sCmd = sCmd & " -AppId '" & sAppId & "'" End If If sSound = "Silent" Then sCmd = sCmd & " -Silent" Else sCmd = sCmd & " -Sound '" & sSound & "'" End If If bSnoozeDimiss Then sCmd = sCmd & " -SnoozeAndDismiss" sCmd = sCmd & ";" 'Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: DisplayWindowsToastNotification" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
Here’s an example of calling it:
DisplayWindowsToastNotification "Planning Database", "New Project", "Project 128876 was just created.", "C:\icons\agenda-153555_640.png", SysCmd(acSysCmdAccessDir) & "msaccess.exe"
Progress bar notification
Public Sub DisplayWindowsProgressToastNotification(ByVal sTitle As String, _ ByVal sMsg1 As String, _ ByVal sIdentifier As String, _ dProgressValue As Double, _ Optional ByVal sMsg2 As String, _ Optional ByVal sAppLogo As String, _ Optional ByVal sAppId As String, _ Optional ByVal sSound As String = "Default", _ Optional bSnoozeDimiss As Boolean = False) On Error GoTo Error_Handler Dim sCmd As String sCmd = "$Progress = New-BTProgressBar -Status 'Copying files' -Value " & dProgressValue & ";" sCmd = sCmd & "$ToastHeader = New-BTHeader -Title '" & sTitle & "';" sCmd = sCmd & "Toast -Header $ToastHeader" ' short form -> can also do "New-BurntToastNotification -Header $ToastHeader" sCmd = sCmd & " -Text '" & sMsg1 & "'" If sMsg2 <> "" Then sCmd = sCmd & ", '" & sMsg2 & "'" sCmd = sCmd & " -ProgressBar $Progress" sCmd = sCmd & " -UniqueIdentifier '" & sIdentifier & "'" If sAppLogo = "" Then sCmd = sCmd & " -AppLogo false" Else sCmd = sCmd & " -AppLogo '" & sAppLogo & "'" End If If sAppId <> "" Then sAppId = GetFIleGUIDPath(sAppId) 'Convert path to use Known GUI (it's required!) sCmd = sCmd & " -AppId '" & sAppId & "'" End If If sSound = "Silent" Then sCmd = sCmd & " -Silent" Else sCmd = sCmd & " -Sound '" & sSound & "'" End If If bSnoozeDimiss Then sCmd = sCmd & " -SnoozeAndDismiss" sCmd = sCmd & ";" 'Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: DisplayWindowsProgressToastNotification" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
Here are a few example of calling it:
DisplayWindowsProgressToastNotification "Planning Database", "Processing Incoming Items", "test011", 0.25, "Mail Items", "C:\icons\agenda-153555_640.png", SysCmd(acSysCmdAccessDir) & "msaccess.exe"
DisplayWindowsProgressToastNotification "Planning Database", "Processing Incoming Items", "test011", 0.65, "Web Submissions", "C:\icons\agenda-153555_640.png", SysCmd(acSysCmdAccessDir) & "msaccess.exe"
DisplayWindowsProgressToastNotification "Planning Database", "Processing Incoming Items", "test011", 1, "Manual Requests", "C:\icons\agenda-153555_640.png", SysCmd(acSysCmdAccessDir) & "msaccess.exe
The first example gives:
The critical thing with the progress bar example is the sIdentifier argument. You want to reuse the same value, whatever you choose it to be, so when you call the procedure again, it doesn’t create a new notification, but rather update the existing one so you can actually show progress!
Helper Function
BurntToast AppId requires the path to use KnownIds so I quickly created a conversion routine, but this still need a lot of work as it is hard-code for my setup.
Function GetFIleGUIDPath(sFile As String) As String 'ProgramFilesX86 'If InStr(sFile, Shell_GetFolderPath(CSIDL_PROGRAM_FILESX86)) > 0 Then sFile = Replace(sFile, Shell_GetFolderPath(CSIDL_PROGRAM_FILESX86), "{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}") If InStr(sFile, "C:\Program Files (x86)") > 0 Then sFile = Replace(sFile, "C:\Program Files (x86)", "{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}") 'ProgramFilesX64 ???? If InStr(sFile, "C:\Program Files") > 0 Then sFile = Replace(sFile, "C:\Program Files", "{6D809377-6AF0-444B-8957-A3773F02200E}") GetFIleGUIDPath = sFile End Function
I made the above to handle common Microsoft Office applications. If you truly want to play around with this further, in the PowerShell ISE, execute:
Get-StartApps
If you’re wonder what some of these GUIDs actually represent, then look over:
Known Folder GUIDs for File Dialog Custom Places – Windows Forms .NET Framework
Learn about known folder GUIDs for file dialog custom places in Windows Forms, by means of the list of GUIDs in this article.
How Far Can We Take Things?!
Public Sub BTAdvancedDemo() On Error GoTo Error_Handler Dim sCmd As String sCmd = "$header = New-BTHeader -Title 'Scheduling Database';" sCmd = sCmd & "$title = New-BTText -Content 'Project Planning Database';" sCmd = sCmd & "$text1 = New-BTText -Content 'New Project';" sCmd = sCmd & "$text2 = New-BTText -Content 'Project 128837 has just been created and is awaiting your approval.';" sCmd = sCmd & "$imageBanner = New-BTImage -Source 'C:\Images\YouTube-Banner_2048x1153.jpg' -HeroImage;" sCmd = sCmd & "$imageMessage = New-BTImage -Source 'C:\Images\convertible_blue.png' -AppLogoOverride;" sCmd = sCmd & "$actions = New-BTAction -SnoozeAndDismiss;" sCmd = sCmd & "$binding = New-BTBinding -Children $title, $text1, $text2 -AppLogoOverride $imageMessage -HeroImage $imageBanner;" sCmd = sCmd & "$visual = New-BTVisual -BindingGeneric $binding;" sCmd = sCmd & "$content = New-BTContent -Visual $visual -Duration Short -Scenario IncomingCall -Header $header -Actions $actions;" sCmd = sCmd & "Submit-BTNotification $content -AppId '{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}\Microsoft Office\Office15\MSACCESS.EXE';" 'Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: BTAdvancedDemo" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
which resulted in
and that’s where I’m at currently. It’s pretty amazing what can be achieved with a few lines of code! It was a lot of fun playing around with all of this to truly help any VBA application stand out!
Just to mention that things can be taken even further. PowerShell enables scripting remote devices, so it would be feasible to even create such notifications (or even the standard built-in ones) and send them to other PCs within an organization. The possibilities are endless, so have fun with all of this!
Lastly, I should mention that I did my development with the current stable version of BurntToast which is 0.8.5. That said, 1.0.0 is just around the corner which will have even more features! So things should only get better as this project matures.
I hope this will help a few of you out there.
BurntToast 0.8.5 md / ReadMe File
Creates and displays a Toast Notification.
Update 2024-02-09
I’ve been fighting with one aspect of the BurntToast implementation and that was the AppId. I didn’t like having a clumsy conversion function in the mix. Normally, I would use Get-StartApps CmdLet to get this value, and it works perfectly in PowerShell ISE, but fails via command line. I’ve inquired regarding this issue and perhaps one day I’ll actually understand why?!
Regardless, it took me a little playing around with things, but I finally got a functional alternative. As such, here are the improved version of the BurntToast procedures which no longer require the use of a helper function to convert the paths.
Standard Notification
Public Sub DisplayWindowsToastNotification(ByVal sTitle As String, _ ByVal sMsg1 As String, _ Optional ByVal sMsg2 As String, _ Optional ByVal sAppLogo As String, _ Optional ByVal sAppId As String, _ Optional ByVal sSound As String = "Default", _ Optional bSnoozeDimiss As Boolean = False) On Error GoTo Error_Handler Dim sCmd As String sCmd = "$ToastHeader = New-BTHeader -Title '" & sTitle & "';" sCmd = sCmd & "Toast -Header $ToastHeader" ' short form -> can also do "New-BurntToastNotification -Header $ToastHeader" sCmd = sCmd & " -Text '" & sMsg1 & "'" If sMsg2 <> "" Then sCmd = sCmd & ", '" & sMsg2 & "'" If sAppLogo = "" Then sCmd = sCmd & " -AppLogo false" 'sCmd = sCmd & " -NoLogo" 'No Good Else sCmd = sCmd & " -AppLogo '" & sAppLogo & "'" End If If sAppId <> "" Then 'Original helper conversion approach 'sAppId = GetFIleGUIDPath(sAppId) 'Convert path to use Known GUI (it's required!) 'sCmd = sCmd & " -AppId '" & sAppId & "'" 'Should work, but doesn't! Works fine in the ISE, need to investigate further 'sAppId = "(Get-StartApps | Where-Object name -eq '" & sAppId & "').AppId" 'sCmd = sCmd & " -AppId " & sAppId & "" 'Better way, no helper conversion required sAppId = "((New-Object -ComObject Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}')" & _ ".Items() | Where-Object { $_.name -like '*" & sAppId & "*' } ).Path" sCmd = sCmd & " -AppId " & sAppId End If If sSound = "Silent" Then sCmd = sCmd & " -Silent" Else sCmd = sCmd & " -Sound '" & sSound & "'" End If If bSnoozeDimiss Then sCmd = sCmd & " -SnoozeAndDismiss" sCmd = sCmd '& ";Start-Sleep -Seconds 8;" Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: DisplayWindowsToastNotification" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
and now you’d call it by doing:
DisplayWindowsToastNotification "Planning Database", "New Project", "Project 128876 was just created.", "C:\icons\agenda-153555_640.png", "Access 201"
DisplayWindowsToastNotification "Planning Database", "New Project", "Project 128876 was just created.", "C:\icons\agenda-153555_640.png", "TeamViewer"
DisplayWindowsToastNotification "Planning Database", "New Project", "Project 128876 was just created.", "C:\icons\agenda-153555_640.png", "Excel 20"
Progress Bar Notification
Public Sub DisplayWindowsProgressToastNotification(ByVal sTitle As String, _ ByVal sMsg1 As String, _ ByVal sIdentifier As String, _ dProgressValue As Double, _ Optional ByVal sMsg2 As String, _ Optional ByVal sAppLogo As String, _ Optional ByVal sAppId As String, _ Optional ByVal sSound As String = "Default", _ Optional bSnoozeDimiss As Boolean = False) On Error GoTo Error_Handler Dim sCmd As String sCmd = "$Progress = New-BTProgressBar -Status 'Copying files' -Value " & dProgressValue & ";" sCmd = sCmd & "$ToastHeader = New-BTHeader -Title '" & sTitle & "';" sCmd = sCmd & "Toast -Header $ToastHeader" ' short form -> can also do "New-BurntToastNotification -Header $ToastHeader" sCmd = sCmd & " -Text '" & sMsg1 & "'" If sMsg2 <> "" Then sCmd = sCmd & ", '" & sMsg2 & "'" sCmd = sCmd & " -ProgressBar $Progress" sCmd = sCmd & " -UniqueIdentifier '" & sIdentifier & "'" If sAppLogo = "" Then sCmd = sCmd & " -AppLogo false" Else sCmd = sCmd & " -AppLogo '" & sAppLogo & "'" End If If sAppId <> "" Then 'Original helper conversion approach 'sAppId = GetFIleGUIDPath(sAppId) 'Convert path to use Known GUI (it's required!) 'sCmd = sCmd & " -AppId '" & sAppId & "'" 'Better way, no helper conversion required sAppId = "((New-Object -ComObject Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}')" & _ ".Items() | Where-Object { $_.name -like '*" & sAppId & "*' } ).Path" sCmd = sCmd & " -AppId " & sAppId End If If sSound = "Silent" Then sCmd = sCmd & " -Silent" Else sCmd = sCmd & " -Sound '" & sSound & "'" End If If bSnoozeDimiss Then sCmd = sCmd & " -SnoozeAndDismiss" sCmd = sCmd & ";" 'Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: DisplayWindowsProgressToastNotification" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
and now you’d call it by doing:
DisplayWindowsProgressToastNotification "Planning Database", "Processing Incoming Items", "test011", 1, "Mail Items", "C:\icons\agenda-153555_640.png", "Access 20"
DisplayWindowsProgressToastNotification "Planning Workbook", "Processing Incoming Items", "test011", 1, "Mail Items", "C:\icons\agenda-153555_640.png", "Excel 20"
Banner Image Notification
Public Sub BTAdvancedDemo() On Error GoTo Error_Handler Dim sCmd As String sCmd = "$header = New-BTHeader -Title 'Scheduling Database';" sCmd = sCmd & "$title = New-BTText -Content 'Project Planning Database';" sCmd = sCmd & "$text1 = New-BTText -Content 'New Project';" sCmd = sCmd & "$text2 = New-BTText -Content 'Project 128837 has just been created and is awaiting your approval.';" sCmd = sCmd & "$imageBanner = New-BTImage -Source 'C:\Users\Daniel\Downloads\YouTube-Banner_2048x1153.jpg' -HeroImage;" sCmd = sCmd & "$imageMessage = New-BTImage -Source 'M:\Databases\icons\convertible_blue.png' -AppLogoOverride;" sCmd = sCmd & "$actions = New-BTAction -SnoozeAndDismiss;" sCmd = sCmd & "$binding = New-BTBinding -Children $title, $text1, $text2 -AppLogoOverride $imageMessage -HeroImage $imageBanner;" sCmd = sCmd & "$visual = New-BTVisual -BindingGeneric $binding;" sCmd = sCmd & "$content = New-BTContent -Visual $visual -Duration Short -Scenario IncomingCall -Header $header -Actions $actions;" sCmd = sCmd & "Submit-BTNotification $content -AppId ((New-Object -ComObject Shell.Application).NameSpace('shell:::{4234d49b-0245-4df3-b780-3893943456e1}')" & _ ".Items() | Where-Object { $_.name -like 'Access 20*' } ).Path;" 'Debug.Print sCmd Call PS_Execute(sCmd, "RemoteSigned") Error_Handler_Exit: On Error Resume Next Exit Sub Error_Handler: MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _ "Error Source: BTAdvancedDemo" & vbCrLf & _ "Error Number: " & Err.Number & vbCrLf & _ "Error Description: " & Err.Description & _ Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _ , vbOKOnly + vbCritical, "An Error has Occurred!" Resume Error_Handler_Exit End Sub
and you’d call it by doing:
Call BTAdvancedDemo
Send a Toast Notification from PowerShell Script
To create PowerShell pop-up notifications in Windows, you can use the third-party BurntToast module from the PowerShell gallery. Install the module:
Install-Module -Name BurntToast
For example, now you can easily add a colorful notification to the script from the post “How to automatically disable Wi-Fi when Ethernet cable is connected”:
New-BurntToastNotification -Text " Wi-Fi network disconnection", " Since your device was connected to a high-speed Ethernet LAN, you have been disconnected from your Wi-Fi network" -AppLogo C:\PS\changenetwork.png