Сценарий для отправки запланированных уведомлений на устройство windows

Для оповещения пользователей о различных событиях, вы можете выводить различные графические уведомления из скриптов PowerShell. В PowerShell можно использовать всплывающие уведомления в трее Windows или модальные окно для получения информации от пользователя или подтверждения действия.

You know, these things:

Сценарий для отправки запланированных уведомлений на устройство windows

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

scheduled notification displayed on device end as pop-up box

Toast notifications

scheduled message displayed on device end as toast message

Вывести всплывающее сообщение на экран с помощью PowerShell

Для вывода простых модального диалогового окна в Windows можно воспользоваться Wscript классами подсистемы сценариев Windows. Следующий PowerShell код выведет обычное текстовое окно с вашим текстом и кнопкой OK.

$wshell = New-Object -ComObject Wscript.Shell
$Output = $wshell.Popup("Скрипт формирования отчета выполнен")

Wscript.Shell вывод уведомлений в POwershell

Вы можете настроить вид модального окна такого сообщения и добавить кнопки действия для пользователей. Например, чтобы вывести всплывающее окно с кнопками Да и Нет, выполните:

$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"
}

Вывести окно для ввода данных пользователя в powershell скрипте

Если нужно вывести всплывающее окно поверх всех окон, используйте команду:

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.

Send toast notification to remote computer with Invoke-Command

Отправка сообщения пользователю на удаленный компьютер

С помощью PowerShell вы можете отправить всплывающее сообщение пользователю на удаленный компьютер. Сначала нужно получить список сессии пользователей на удаленном компьютере (в случае RDS сервера):

qwinsta: список сессий пользователей на удаленном компьютере

Чтобы отправить сообщение в сессию пользователя на удаленном компьютер, выполните команду:

MSG kbuldogov /server:rds1 "Сервер будет перезагружен через 10 минут. Закройте документы"

Если всплывающее сообщение нужно отправить всем пользователям укажите * вместо имени пользователя:

MSG * /server:rds1 "Срочное сообщение всем! "

PowerShell msg вывести сообщение пользователю на удаленном компьютере

Для отправки всплывающего графического уведомления на удаленный компьютер можно воспользоваться скриптом RemoteSendToasNotification.ps1 из нашего GitHub репозитория ( https://github.com/winadm/posh/blob/master/scripts/RemoteSendToasNotification.ps1). Для подключения к удаленному компьютеру используется командлет Invoke-Command, который использует WinRM.

Отправить всплывающее сообщение пользователю на удаленный компьютер Windows

Page History

DateSummary of Changes
2024-02-08Initial Release
2024-02-09Added Updated BurntToast code eliminating the need for a Helper Function
2024-02-15Added 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!")

Wscript - powershell show a windows with the notification

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:

display a pop-up message box with PowerShell with yes/no

$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"
}

PowerShell show GUI input box

If you want to display a modal dialogue on top of all windows on the desktop:

:/>  Запись в кэше dns устарела попробуйте использовать ip адрес вместо имени компьютера

Вывести уведомление пользователю Windows из скрипта PowerShell

С помощью класса Windows Forms можно вывести более красивые всплывающие сообщения (ballons). Следующий скрипт выведет всплывающее сообщение рядом с панелью уведомлений Windows, которое автоматически исчезнет через 10 секунд:

всплывающее уведомление в POwerShell

Для создания красочных всплывающих сообщений в 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

Вывести всплывающее уведомление uvedomlenie New-BurntToastNotification

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);

Сценарий для отправки запланированных уведомлений на устройство windows

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)

Сценарий для отправки запланированных уведомлений на устройство windows

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:

Windows PowerShell

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:

Сценарий для отправки запланированных уведомлений на устройство windows

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")

Сценарий для отправки запланированных уведомлений на устройство windows

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

Сценарий для отправки запланированных уведомлений на устройство windows

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:

Сценарий для отправки запланированных уведомлений на устройство windows

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"

Сценарий для отправки запланированных уведомлений на устройство windows

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:

:/>  Как запустить и правильно настроить msconfig в Windows

Сценарий для отправки запланированных уведомлений на устройство windows

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:

Сценарий для отправки запланированных уведомлений на устройство windows

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
Сценарий для отправки запланированных уведомлений на устройство windows

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.

:/>  Полезные скрипты power shell для windows

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

balloon tip notification with PowerShell in windows 10

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

Show toast notification from a PowerShell script

Оставьте комментарий