Win10: Multi-Language Toast Notifications

BEFORE YOU BEGIN

In this blog I will be using a Toast Notification script created by Martin Bengtsson.

TOAST NOTIFICATION

In my search for a solution to display notifications to our end users during our new Dynamic Driver and BIOS Update process, I found a blog by Martin Bengtsson.
Martin’s Blog: https://bit.ly/35o4sz4
I will not be deep-diving into the details, so please read Martin’s blog above if you want detailed information about Toast Notifications.
My version is modified to fit our multi-language environment and other needs.
Toast Notification - Danish
Toast Notification - English
Toast Notification - Norwegian
If you can't make it work with "Software Center" as the app for toast notifications, make sure you haven't deleted or hidden the original Software Center shortcut!
Changes I've made:
Added:
    Multi-Language support
    Several new text variables in the XML config file
    Look in WMI for given name if no local AD is available.
    More detailed logging
Changed:
    Date formatting
    All text can now be edited directly in the XML config file
    Log Path
    Removed a few script errors showing while running it manually in PowerShell ISE

Deploy it

In my environment we are using ConfigMgr so I want to show how it's done in our environment, but read Martin's documentation to see how it can be deployed through Group Policy.
What I've done in our environment is create a package that contains all the files except the configuration files because I point to them through a UNC path for easier access if I need to change anything.
Explorer - The Files
Then I create a program running PowerShell that executes Show-ToastNotification.ps1, this script will look at the system locale language, and execute the New-ToastNotification.ps1 with the correct language configuration file.
DISM - System Locale Language
ConfigMgr - Program
Command line example:
1
PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File ".\Show-ToastNotification.ps1"
Copied!
To implement my modified edition of Martin's Toast Notification script to your environment, download it from my GitHub repo.

Script

Script (Config.xml)
1
<?xml version="1.0" encoding="utf-8"?>
2
<Configuration>
3
<Feature Name="Toast" Enabled="True" /> <!-- Enables or disables the entire toast notification -->
4
<Feature Name="UpgradeOS" Enabled="False" /> <!-- Specifies if the toast is used for OS upgrades. If set to True, the targetOS build is taking into account -->
5
<Feature Name="PendingRebootUptime" Enabled="False" /> <!-- Enables the toast for reminding users of restarting their device if it exceeds the uptime defined in MaxUptimeDays -->
6
<Feature Name="PendingRebootCheck" Enabled="False" /> <!-- Enables the toast for reminding users of pending reboots found in registry/WMI -->
7
<Option Name="TargetOS" Build="18134" /> <!-- The actual build number of the targeted OS. 18351 = 1903 | 17763 = 1809. This option has no effect if OSUpgrade is set to False -->
8
<Option Name="MaxUptimeDays" Value="-6" /> <!-- When using the toast for checking for pending reboots. A reboot is considered pending if computer uptime exceeds the value set here -->
9
<Option Name="PendingRebootUptimeText" Enabled="False" Value="Your computer is required to restart due to having exceeded the maximum allowed uptime." /> <!-- Adds an additional group to the toast with text about the uptime of the computer -->
10
<Option Name="PendingRebootCheckText" Enabled="False" Value="Reason: Pending reboots was found in registry or WMI." /> <!-- -->
11
<Option Name="Deadline" Enabled="True" Value="30-09-2019 08:00" /> <!-- Adds an additional group to the toast with text about the deadline of the OSUpgrade. The value must be entered "dd-MM-yyyy HH:mm" it will be formatted to correct culture format by the PowerShell Script -->
12
<Option Name="UseSoftwareCenterApp" Enabled="False" /> <!-- The app in Windows doing the action notification - can't be both SoftwareCenter and Powershell -->
13
<Option Name="UsePowershellApp" Enabled="True" /> <!-- The app in Windows doing the action notification - can't be both SoftwareCenter and Powershell -->
14
<Option Name="CustomAudio" Enabled="False" TextToSpeech="Hey you - wake up. Your computer needs to restart. Do it now."/>
15
<Option Name="ActionButton" Enabled="True" Value="Install" /> <!-- Enables or disables the action button. Value is equal to the name displayed on the button -->
16
<Option Name="DismissButton" Enabled="True" Value="Not now" /> <!-- Enables or disables the dismiss button. Value is equal to the name displayed on the button -->
17
<Option Name="SnoozeButton" Enabled="True" Value="Snooze" /> <!-- Enabling this option will always enable action button and dismiss button -->
18
<Option Name="Scenario" Type="reminder" /> <!-- Possible values are: reminder | short | long -->
19
<Option Name="Action" Value="softwarecenter:Page=OSD" /> <!-- Action taken when using the ActionButton. Can be link to SoftwareCenter if used with UpgradeOS -->
20
<Text Option="GreetGivenName" Enabled="True" /> <!-- Displays the toast with a personal greeting using the users given name retrieved from AD -->
21
<Text Name="AttributionText">www.osdsune.com</Text>
22
<Text Name="HeaderText">Kindly reminder from HelpDesk.</Text>
23
<Text Name="TitleText">New updates available!</Text>
24
<Text Name="BodyText1">There are new Dell drivers and BIOS updates available. Do yourself a favor and install them yourself... Or we will do it for you ;-)</Text>
25
<Text Name="BodyText2">It will take 10-40 minutes and requires a restart of your PC. But don't worry, you will receive an adequate amount of reminders before any actions are taken automatically.</Text>
26
<Text Name="SnoozeText">Click Snooze to be reminded again in:</Text>
27
<Text Name="DeadlineText">Your deadline is:</Text>
28
<Text Name="GreetMorningText">Good morning</Text>
29
<Text Name="GreetAfternoonText">Good afternoon</Text>
30
<Text Name="GreetEveningText">Good evening</Text>
31
<Text Name="MinutesText">Minutes</Text>
32
<Text Name="HourText">Hour</Text>
33
<Text Name="HoursText">Hours</Text>
34
<Text Name="ComputerUptimeText">Computer uptime:</Text>
35
<Text Name="ComputerUptimeDaysText">days.</Text>
36
</Configuration>
Copied!
Script (Show-ToastNotification.ps1)
1
<#
2
.SYNOPSIS
3
Language detection for toasted notifications in Windows 10.
4
5
.DESCRIPTION
6
This script will check for "System Locale" language in registry.
7
0414 = nb_NO
8
0406 = da_DK
9
0409 = en_US
10
11
.NOTES
12
Version: 1.9.8.19
13
Author: Sune Thomsen
14
Creation date: 15-08-2019
15
Last modified date: 19-08-2019
16
17
.LINK
18
https://www.osdsune.com
19
#>
20
21
$RegKey = "HKLM:\SYSTEM\CurrentControlSet\Control\Nls\Language"
22
$RegName = "Default"
23
$RegValue_daDK = "0406"
24
$RegValue_nbNO = "0414"
25
$OSLanguage = Get-ItemPropertyValue -Path $RegKey -Name $RegName -ErrorAction SilentlyContinue
26
27
if ($OSLanguage -eq "$RegValue_daDK"){
28
PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File $PSScriptRoot\New-ToastNotification.ps1 -Config "\\UNCPath\Config\config-toast-update-daDK.xml"
29
break
30
}
31
32
if ($OSLanguage -eq "$RegValue_nbNO"){
33
PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File $PSScriptRoot\New-ToastNotification.ps1 -Config "\\UNCPath\Config\config-toast-update-nbNO.xml"
34
break
35
}
36
37
if (($OSLanguage -ne "$RegValue_daDK") -and ($OSLanguage -ne "$RegValue_nbNO")){
38
PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File $PSScriptRoot\New-ToastNotification.ps1 -Config "\\UNCPath\Config\config-toast-update-enUS.xml"
39
break
40
}
Copied!
Script (New-ToastNotification.ps1)
1
<#
2
.SYNOPSIS
3
Create nice Windows 10 toast notifications for the logged on user in Windows.
4
5
.DESCRIPTION
6
Everything is customizeable through config-toast.xml.
7
Config-toast.xml can be locally or set to an UNC path with the -Config parameter.
8
This way you can quickly modify the configuration without the need to push new files to the computer running the toast.
9
Can be used for improving the numbers in Windows Servicing as well as kindly reminding users of pending reboots.
10
All actions are logged to a local log file in C:\Windows\Temp\New-Toastnotificaion.log
11
12
.PARAMETER Config
13
Specify the path for the config.xml. If none is specificed, the script uses the local config.xml
14
15
.NOTES
16
Filename: New-ToastNotification.ps1
17
Version: 1.2
18
Author: Martin Bengtsson
19
Blog: www.imab.dk
20
Twitter: @mwbengtsson
21
22
Version history:
23
1.0 - script created
24
1.1 - Separated checks for pending reboot in registry/WMI from OS uptime.
25
More checks for conflicting options in config.xml.
26
The content of the config.xml is now imported with UTF-8 encoding enabling other characters to be used in the text boxes.
27
1.2 - Added option for personal greeting using given name retreived from Active Directory. If no AD available, the script will use a placeholder.
28
Added ToastReboot protocol example, enabling the toast to carry out a potential reboot.
29
30
2019-08-21 Modified by @SuneThomsenDK
31
OSDSune https://www.osdsune.com/home/blog/2019/windows10-toast-notification
32
Added:
33
- Multi-Language support
34
- Several new text variables in XML config file
35
- Look in WMI for given name if no local AD is available.
36
- More detailed logging
37
38
Changed:
39
- Date formatting
40
- All text can now be edited directly in the XML config file
41
- Log Path
42
- Removed a few script errors showing while running it manually in PowerShell ISE
43
44
Removed:
45
-
46
47
To use it for multi-language purpose execute this command: PowerShell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File .\Show-ToastNotification.ps1
48
49
.LINKS
50
https://www.imab.dk/windows-10-toast-notification-script/
51
#>
52
53
[CmdletBinding()]
54
param(
55
[Parameter(HelpMessage='Path to XML Configuration File')]
56
[string]$Config
57
)
58
59
######### FUNCTIONS #########
60
61
# Create write log function
62
function Write-Log {
63
[CmdletBinding()]
64
param(
65
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
66
[ValidateNotNullOrEmpty()]
67
[Alias("LogContent")]
68
[string]$Message,
69
70
# EDIT with your location for the local log file
71
[Parameter(Mandatory=$false)]
72
[Alias('LogPath')]
73
[string]$Path="$env:SystemRoot\Temp\" + "New-ToastNotification.log",
74
75
[Parameter(Mandatory=$false)]
76
[ValidateSet("Error","Warn","Info")]
77
[string]$Level="Info"
78
)
79
80
Begin
81
{
82
# Set VerbosePreference to Continue so that verbose messages are displayed.
83
$VerbosePreference = 'Continue'
84
}
85
Process
86
{
87
if ((Test-Path $Path)){
88
$LogSize = (Get-Item -Path $Path).Length/1MB
89
$MaxLogSize = 5
90
}
91
92
# Check for file size of the log. If greater than 5MB, it will create a new one and delete the old.
93
if ((Test-Path $Path) -AND $LogSize -gt $MaxLogSize){
94
Write-Error "Log file $Path already exists and file exceeds maximum file size. Deleting the log and starting fresh."
95
Remove-Item $Path -Force
96
$NewLogFile = New-Item $Path -Force -ItemType File
97
}
98
# If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
99
elseif (!(Test-Path $Path)){
100
Write-Verbose "Creating $Path."
101
$NewLogFile = New-Item $Path -Force -ItemType File
102
}
103
else{
104
# Nothing to see here yet.
105
}
106
107
# Format Date for our Log File
108
$FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
109
110
# Write message to error, warning, or verbose pipeline and specify $LevelText
111
switch ($Level){
112
'Error' {
113
Write-Error $Message
114
$LevelText = 'ERROR:'
115
}
116
'Warn' {
117
Write-Warning $Message
118
$LevelText = 'WARNING:'
119
}
120
'Info' {
121
Write-Verbose $Message
122
$LevelText = 'INFO:'
123
}
124
}
125
126
# Write log entry to $Path
127
"$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append
128
}
129
End
130
{
131
}
132
}
133
134
# Create Pending Reboot function for registry
135
function Test-PendingRebootRegistry {
136
Write-Log -Message "Running Test-PendingRebootRegistry function"
137
$CBSRebootKey = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -ErrorAction Ignore
138
$WURebootKey = Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -ErrorAction Ignore
139
$FileRebootKey = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -ErrorAction Ignore
140
141
if (($CBSRebootKey -ne $null) -OR ($WURebootKey -ne $null) -OR ($FileRebootKey -ne $null)){
142
Write-Log -Message "Check returned TRUE on ANY of the registry checks: Reboot is pending!"
143
return $true
144
}
145
Write-Log -Message "Check returned FALSE on ANY of the registry checks: Reboot is NOT pending!"
146
return $false
147
}
148
149
# Create Pending Reboot function for WMI via SCCM client
150
function Test-PendingRebootWMI {
151
Write-Log -Message "Running Test-PendingRebootWMI function"
152
if (Get-Service -Name ccmexec){
153
Write-Log -Message "Computer has SCCM client installed - checking for pending reboots in WMI"
154
$Util = [wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities"
155
$Status = $Util.DetermineIfRebootPending()
156
if(($Status -ne $null) -AND $Status.RebootPending){
157
Write-Log -Message "Check returned TRUE on checking WMI for pending reboot: Reboot is pending!"
158
return $true
159
}
160
Write-Log -Message "Check returned FALSE on checking WMI for pending reboot: Reboot is NOT pending!"
161
return $false
162
}
163
else{
164
Write-Log -Message "Computer has no SCCM client installed - skipping checking WMI for pending reboots" -Level Warn
165
return $false
166
}
167
}
168
169
# Create Get Device Uptime function
170
function Get-DeviceUptime {
171
$OS = Get-WmiObject Win32_OperatingSystem
172
$Uptime = (Get-Date) - ($OS.ConvertToDateTime($OS.LastBootUpTime))
173
$Uptime.Days
174
}
175
176
# Create Get GivenName function
177
function Get-GivenName {
178
# Thanks to Trevor Jones @ http://smsagent.blog
179
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
180
Clear-Variable -Name GivenName -ErrorAction SilentlyContinue
181
try{
182
$PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Domain, [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain())
183
$GivenName = ([System.DirectoryServices.AccountManagement.Principal]::FindByIdentity($PrincipalContext,[System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName,[Environment]::UserName)).GivenName
184
$PrincipalContext.Dispose()
185
}
186
catch [System.Exception]{
187
Write-Log -Message "$_."
188
}
189
190
if ($GivenName){
191
Write-Log -Message "Given name retrieved from Active Directory"
192
$GivenName
193
}
194
elseif (!($GivenName)){
195
Write-Log -Message "Given name not found in AD or no local AD available. Continuing looking for given name elsewhere"
196
if (Get-Service -Name ccmexec){
197
Write-Log -Message "Looking for given name in WMI with CCM client"
198
$LoggedOnSID = Get-WmiObject -Namespace ROOT\CCM -Class CCM_UserLogonEvents -Filter "LogoffTime=null" | Select -ExpandProperty UserSID
199
if ($LoggedOnSID.GetType().IsArray){
200
Write-Log -Message "Multiple SID's found. Skipping"
201
$GivenName = ""
202
$GivenName
203
}
204
else{
205
$RegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\SessionData"
206
$DisplayName = (Get-ChildItem -Path $RegKey | Where-Object {$_.GetValue("LoggedOnUserSID") -eq $LoggedOnSID}).GetValue("LoggedOnDisplayName")
207
if ($DisplayName){
208
Write-Log -Message "Given name found in WMI with the CCM client"
209
$GivenName = $DisplayName.Split()[0].Trim()
210
$GivenName
211
}
212
else{
213
$GivenName = ""
214
$GivenName
215
}
216
}
217
}
218
}
219
elseif (!($GivenName)){
220
# More options for given name here
221
}
222
else{
223
Write-Log -Message "No given name found. Using nothing as placeholder"
224
$GivenName = ""
225
$GivenName
226
}
227
}
228
229
######### GENERAL VARIABLES #########
230
231
# Getting executing directory
232
$global:ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
233
234
# Setting image variables
235
$LogoImage = "file:///$global:ScriptPath/ToastLogoImage.jpg"
236
$HeroImage = "file:///$global:ScriptPath/ToastHeroImage.jpg"
237
$RunningOS = Get-WmiObject -Class Win32_OperatingSystem | Select-Object BuildNumber
238
239
# If no config file is set as parameter, use the default.
240
# Default is executing directory. In this case, the config-toast.xml must exist in same directory as the New-ToastNotification.ps1 file
241
if (!$Config){
242
Write-Log -Message "No config file set as parameter. Using local config file"
243
$Config = Join-Path ($global:ScriptPath) "config-toast.xml"
244
}
245
246
# Load config.xml
247
if (Test-Path $Config){
248
try{
249
$Xml = [xml](Get-Content -Path $Config -Encoding UTF8)
250
Write-Log -Message "Successfully loaded $Config"
251
}
252
catch{
253
$ErrorMessage = $_.Exception.Message
254
Write-Log -Message "Error, could not read $Config"
255
Write-Log -Message "Error message: $ErrorMessage"
256
Exit 1
257
}
258
}
259
else{
260
Write-Log -Message "Error, could not find or access $Config"
261
Exit 1
262
}
263
264
# Load xml content into variables
265
try{
266
Write-Log -Message "Loading xml content from $Config into variables"
267
268
# Load Toast Notification features
269
$ToastEnabled = $Xml.Configuration.Feature | Where-Object {$_.Name -like 'Toast'} | Select-Object -ExpandProperty 'Enabled'
270
$UpgradeOS = $Xml.Configuration.Feature | Where-Object {$_.Name -like 'UpgradeOS'} | Select-Object -ExpandProperty 'Enabled'
271
$PendingRebootUptime = $Xml.Configuration.Feature | Where-Object {$_.Name -like 'PendingRebootUptime'} | Select-Object -ExpandProperty 'Enabled'
272
$PendingRebootCheck = $Xml.Configuration.Feature | Where-Object {$_.Name -like 'PendingRebootCheck'} | Select-Object -ExpandProperty 'Enabled'
273
274
# Load Toast Notification options
275
$PendingRebootUptimeTextEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'PendingRebootUptimeText'} | Select-Object -ExpandProperty 'Enabled'
276
$PendingRebootUptimeTextValue = $Xml.Configuration.Option | Where-Object {$_.Name -like 'PendingRebootUptimeText'} | Select-Object -ExpandProperty 'Value'
277
$MaxUptimeDays = $Xml.Configuration.Option | Where-Object {$_.Name -like 'MaxUptimeDays'} | Select-Object -ExpandProperty 'Value'
278
$PendingRebootCheckTextEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'PendingRebootCheckText'} | Select-Object -ExpandProperty 'Enabled'
279
$PendingRebootCheckTextValue = $Xml.Configuration.Option | Where-Object {$_.Name -like 'PendingRebootCheckText'} | Select-Object -ExpandProperty 'Value'
280
$TargetOS = $Xml.Configuration.Option | Where-Object {$_.Name -like 'TargetOS'} | Select-Object -ExpandProperty 'Build'
281
$DeadlineEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'Deadline'} | Select-Object -ExpandProperty 'Enabled'
282
$DeadlineContent = $Xml.Configuration.Option | Where-Object {$_.Name -like 'Deadline'} | Select-Object -ExpandProperty 'Value'
283
$SCAppName = $Xml.Configuration.Option | Where-Object {$_.Name -like 'UseSoftwareCenterApp'} | Select-Object -ExpandProperty 'Name'
284
$SCAppStatus = $Xml.Configuration.Option | Where-Object {$_.Name -like 'UseSoftwareCenterApp'} | Select-Object -ExpandProperty 'Enabled'
285
$PSAppName = $Xml.Configuration.Option | Where-Object {$_.Name -like 'UsePowershellApp'} | Select-Object -ExpandProperty 'Name'
286
$PSAppStatus = $Xml.Configuration.Option | Where-Object {$_.Name -like 'UsePowershellApp'} | Select-Object -ExpandProperty 'Enabled'
287
$CustomAudio = $Xml.Configuration.Option | Where-Object {$_.Name -like 'CustomAudio'} | Select-Object -ExpandProperty 'Enabled'
288
$CustomAudioTextToSpeech = $Xml.Configuration.Option | Where-Object {$_.Name -like 'CustomAudio'} | Select-Object -ExpandProperty 'TextToSpeech'
289
$Scenario = $Xml.Configuration.Option | Where-Object {$_.Name -like 'Scenario'} | Select-Object -ExpandProperty 'Type'
290
$Action = $Xml.Configuration.Option | Where-Object {$_.Name -like 'Action'} | Select-Object -ExpandProperty 'Value'
291
292
# Load Toast Notification buttons
293
$ActionButtonEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'ActionButton'} | Select-Object -ExpandProperty 'Enabled'
294
$ActionButtonContent = $Xml.Configuration.Option | Where-Object {$_.Name -like 'ActionButton'} | Select-Object -ExpandProperty 'Value'
295
$DismissButtonEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'DismissButton'} | Select-Object -ExpandProperty 'Enabled'
296
$DismissButtonContent = $Xml.Configuration.Option | Where-Object {$_.Name -like 'DismissButton'} | Select-Object -ExpandProperty 'Value'
297
$SnoozeButtonEnabled = $Xml.Configuration.Option | Where-Object {$_.Name -like 'SnoozeButton'} | Select-Object -ExpandProperty 'Enabled'
298
$SnoozeButtonContent = $Xml.Configuration.Option | Where-Object {$_.Name -like 'SnoozeButton'} | Select-Object -ExpandProperty 'Value'
299
300
# Load Toast Notification text
301
$GreetGivenName = $Xml.Configuration.Text| Where-Object {$_.option -like 'GreetGivenName'} | Select-Object -ExpandProperty 'Enabled'
302
$AttributionText = $Xml.Configuration.Text| Where-Object {$_.Name -like 'AttributionText'} | Select-Object -ExpandProperty '#text'
303
$HeaderText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'HeaderText'} | Select-Object -ExpandProperty '#text'
304
$TitleText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'TitleText'} | Select-Object -ExpandProperty '#text'
305
$BodyText1 = $Xml.Configuration.Text | Where-Object {$_.Name -like 'BodyText1'} | Select-Object -ExpandProperty '#text'
306
$BodyText2 = $Xml.Configuration.Text | Where-Object {$_.Name -like 'BodyText2'} | Select-Object -ExpandProperty '#text'
307
$SnoozeText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'SnoozeText'} | Select-Object -ExpandProperty '#text'
308
$DeadlineText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'DeadlineText'} | Select-Object -ExpandProperty '#text'
309
$GreetMorningText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'GreetMorningText'} | Select-Object -ExpandProperty '#text'
310
$GreetAfternoonText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'GreetAfternoonText'} | Select-Object -ExpandProperty '#text'
311
$GreetEveningText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'GreetEveningText'} | Select-Object -ExpandProperty '#text'
312
$MinutesText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'MinutesText'} | Select-Object -ExpandProperty '#text'
313
$HourText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'HourText'} | Select-Object -ExpandProperty '#text'
314
$HoursText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'HoursText'} | Select-Object -ExpandProperty '#text'
315
$ComputerUptimeText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'ComputerUptimeText'} | Select-Object -ExpandProperty '#text'
316
$ComputerUptimeDaysText = $Xml.Configuration.Text | Where-Object {$_.Name -like 'ComputerUptimeDaysText'} | Select-Object -ExpandProperty '#text'
317
318
Write-Log -Message "Successfully loaded xml content from $Config"
319
}
320
catch{
321
Write-Log -Message "Xml content from $Config was not loaded properly"
322
Exit 1
323
}
324
325
# Check if toast is enabled in config.xml
326
if ($ToastEnabled -ne "True"){
327
Write-Log -Message "Toast notification is not enabled. Please check $Config file"
328
Exit 1
329
}
330
331
# Checking for conflicts in config. Some combinations makes no sense, thus trying to prevent those from happening
332
if (($UpgradeOS -eq "True") -AND ($PendingRebootCheck -eq "True")){
333
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
334
Write-Log -Message "Error. You can't have both ÜpgradeOS feature set to True AND PendingRebootCheck feature set to True at the same time" -Level Warn
335
Exit 1
336
}
337
if (($UpgradeOS -eq "True") -AND ($PendingRebootUptime -eq "True")){
338
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
339
Write-Log -Message "Error. You can't have both ÜpgradeOS feature set to True AND PendingRebootUptime feature set to True at the same time" -Level Warn
340
Exit 1
341
}
342
if (($PendingRebootCheck -eq "True") -AND ($PendingRebootUptime -eq "True")){
343
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
344
Write-Log -Message "Error. You currently can't have both PendingReboot features set to True. Please use them seperately." -Level Warn
345
Exit 1
346
}
347
if (($SCAppStatus -eq "True") -AND ($PSAppStatus -eq "True")){
348
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
349
Write-Log -Message "Error. You can't have both SoftwareCenter app set to True AND PowershellApp set to True at the same time" -Level Warn
350
Exit 1
351
}
352
if (($SCAppStatus -ne "True") -AND ($PSAppStatus -ne "True")){
353
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
354
Write-Log -Message "Error. You need to enable at least 1 app in the config doing the notification. ie. Software Center or Powershell" -Level Warn
355
Exit 1
356
}
357
if (($UpgradeOS -eq "True") -AND ($PendingRebootUptimeTextEnabled -eq "True")){
358
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
359
Write-Log -Message "Error. You can't have UpgradeOS set to True and PendingRebootUptimeText set to True at the same time" -Level Warn
360
Exit 1
361
}
362
if (($UpgradeOS -eq "True") -AND ($PendingRebootCheckTextEnabled -eq "True")){
363
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
364
Write-Log -Message "Error. You can't have UpgradeOS set to True and PendingRebootCheckText set to True at the same time" -Level Warn
365
Exit 1
366
}
367
if (($PendingRebootUptimeTextEnabled -eq "True") -AND ($PendingRebootCheckTextEnabled -eq "True")){
368
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
369
Write-Log -Message "Error. You can't have PendingRebootUptimeText set to True and PendingRebootCheckText set to True at the same time" -Level Warn
370
Write-Log -Message "You should only enable one of the text options." -Level Warn
371
Exit 1
372
}
373
if (($PendingRebootCheck -eq "True") -AND ($PendingRebootUptimeTextEnabled -eq "True")){
374
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
375
Write-Log -Message "Error. You can't have PendingRebootCheck set to True and PendingRebootUptimeText set to True at the same time." -Level Warn
376
Write-Log -Message "You should use PendingRebootCheck with the PendingRebootCheckText option instead" -Level Warn
377
Exit 1
378
}
379
if (($PendingRebootUptime -eq "True") -AND ($PendingRebootCheckTextEnabled -eq "True")){
380
Write-Log -Message "Error. Conflicting selection in the $Config file" -Level Warn
381
Write-Log -Message "Error. You can't have PendingRebootUptime set to True and PendingRebootCheckText set to True at the same time." -Level Warn
382
Write-Log -Message "You should use PendingRebootUptime with the PendingRebootUptimeText option instead" -Level Warn
383
Exit 1
384
}
385
386
# Running Pending Reboot Checks
387
if ($PendingRebootCheck -eq "True"){
388
Write-Log -Message "PendingRebootCheck set to True. Checking for pending reboots"
389
$TestPendingRebootRegistry = Test-PendingRebootRegistry
390
$TestPendingRebootWMI = Test-PendingRebootWMI
391
}
392
if ($PendingRebootUptime -eq "True"){
393
Write-Log -Message "PendingRebootUptime set to True. Checking for device uptime"
394
$Uptime = Get-DeviceUptime
395
}
396
397
# Check for required entries in registry for when using Software Center as application for the toast
398
if ($SCAppStatus -eq "True"){
399
400
# Path to the notification app doing the actual toast
401
$RegPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings"
402
$App = "Microsoft.SoftwareCenter.DesktopToasts"
403
404
# Creating registry entries if they don't exists
405
if (!(Test-Path -Path "$RegPath\$App")){
406
New-Item -Path "$RegPath\$App" -Force
407
New-ItemProperty -Path "$RegPath\$App" -Name "ShowInActionCenter" -Value 1 -PropertyType "DWORD" -Force
408
New-ItemProperty -Path "$RegPath\$App" -Name "Enabled" -Value 1 -PropertyType "DWORD" -Force
409
}
410
411
# Make sure the app used with the action center is enabled
412
if ((Get-ItemProperty -Path "$RegPath\$App" -Name "Enabled" -ErrorAction SilentlyContinue).Enabled -ne "1"){
413
New-ItemProperty -Path "$RegPath\$App" -Name "Enabled" -Value 1 -PropertyType "DWORD" -Force
414
}
415
}
416
417
# Check for required entries in registry for when using Powershell as application for the toast
418
if ($PSAppStatus -eq "True"){
419
420
# Register the AppID in the registry for use with the Action Center, if required
421
$RegPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings"
422
$App = "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe"
423
424
# Creating registry entries if they don't exists
425
if (!(Test-Path -Path "$RegPath\$App")){
426
New-Item -Path "$RegPath\$App" -Force
427
New-ItemProperty -Path "$RegPath\$App" -Name "ShowInActionCenter" -Value 1 -PropertyType "DWORD"
428
}
429
430
# Make sure the app used with the action center is enabled
431
if ((Get-ItemProperty -Path "$RegPath\$App" -Name "ShowInActionCenter" -ErrorAction SilentlyContinue).ShowInActionCenter -ne "1"){
432
New-ItemProperty -Path "$RegPath\$App" -Name "ShowInActionCenter" -Value 1 -PropertyType "DWORD" -Force
433
}
434
}
435
436
# Checking if running toast with personal greeting with given name
437
if ($GreetGivenName -eq "True"){
438
Write-Log -Message "Greeting with given name selected. Replacing HeaderText"
439
$Hour = (Get-Date).TimeOfDay.Hours
440
if ($Hour –ge 0 –and $Hour –lt 12){
441
$Greeting = $GreetMorningText
442
}
443
elseif ($Hour –ge 12 –and $Hour –lt 16){
444
$Greeting = $GreetAfternoonText
445
}
446
else{
447
$Greeting = $GreetEveningText
448
}
449
$GivenName = Get-GivenName
450
$HeaderText = "$Greeting $GivenName"
451
}
452
453
# Create the default toast notification XML with action button and dismiss button
454
if (($ActionButtonEnabled -eq "True") -AND ($DismissButtonEnabled -eq "True")){
455
Write-Log -Message "Creating the xml for displaying both action button and dismiss button"
456
[xml]$Toast = @"
457
<toast scenario="$Scenario">
458
<visual>
459
<binding template="ToastGeneric">
460
<image placement="hero" src="$HeroImage"/>
461
<image id="1" placement="appLogoOverride" hint-crop="circle" src="$LogoImage"/>
462
<text placement="attribution">$AttributionText</text>
463
<text>$HeaderText</text>
464
<group>
465
<subgroup>
466
<text hint-style="title" hint-wrap="true" >$TitleText</text>
467
</subgroup>
468
</group>
469
<group>
470
<subgroup>
471
<text hint-style="body" hint-wrap="true" >$BodyText1</text>
472
</subgroup>
473
</group>
474
<group>
475
<subgroup>
476
<text hint-style="body" hint-wrap="true" >$BodyText2</text>
477
</subgroup>
478
</group>
479
</binding>
480
</visual>
481
<actions>
482
<action activationType="protocol" arguments="$Action" content="$ActionButtonContent"/>
483
<action activationType="system" arguments="dismiss" content="$DismissButtonContent"/>
484
</actions>
485
</toast>
486
"@
487
}
488
489
# NO action button and NO dismiss button
490
if (($ActionButtonEnabled -ne "True") -AND ($DismissButtonEnabled -ne "True")){
491
Write-Log -Message "Creating the xml for no action button and no dismiss button"
492
[xml]$Toast = @"
493
<toast scenario="$Scenario">
494
<visual>
495
<binding template="ToastGeneric">
496
<image placement="hero" src="$HeroImage"/>
497
<image id="1" placement="appLogoOverride" hint-crop="circle" src="$LogoImage"/>
498
<text placement="attribution">$AttributionText</text>
499
<text>$HeaderText</text>
500
<group>
501
<subgroup>
502
<text hint-style="title" hint-wrap="true" >$TitleText</text>
503
</subgroup>
504
</group>
505
<group>
506
<subgroup>
507
<text hint-style="body" hint-wrap="true" >$BodyText1</text>
508
</subgroup>
509
</group>
510
<group>
511
<subgroup>
512
<text hint-style="body" hint-wrap="true" >$BodyText2</text>
513
</subgroup>
514
</group>
515
</binding>
516
</visual>
517
<actions>
518
</actions>
519
</toast>
520
"@
521
}
522
523
# Action button and NO dismiss button
524
if (($ActionButtonEnabled -eq "True") -AND ($DismissButtonEnabled -ne "True")){
525
Write-Log -Message "Creating the xml for no dismiss button"
526
[xml]$Toast = @"
527
<toast scenario="$Scenario">
528
<visual>
529
<binding template="ToastGeneric">
530
<image placement="hero" src="$HeroImage"/>
531
<image id="1" placement="appLogoOverride" hint-crop="circle" src="$LogoImage"/>
532
<text placement="attribution">$AttributionText</text>
533
<text>$HeaderText</text>
534
<group>
535
<subgroup>
536
<text hint-style="title" hint-wrap="true" >$TitleText</text>
537
</subgroup>
538
</group>
539
<group>
540
<subgroup>
541
<text hint-style="body" hint-wrap="true" >$BodyText1</text>
542
</subgroup>
543
</group>
544
<group>
545
<subgroup>
546
<text hint-style="body" hint-wrap="true" >$BodyText2</text>
547
</subgroup>
548
</group>
549
</binding>
550
</visual>
551
<actions>
552
<action activationType="protocol" arguments="$Action" content="$ActionButtonContent"/>
553
</actions>
554
</toast>
555
"@
556
}
557
558
# Dismiss button and NO action button
559
if (($ActionButtonEnabled -ne "True") -AND ($DismissButtonEnabled -eq "True")){
560
Write-Log -Message "Creating the xml for no action button"
561
[xml]$Toast = @"
562
<toast scenario="$Scenario">
563
<visual>
564
<binding template="ToastGeneric">
565
<image placement="hero" src="$HeroImage"/>
566
<image id="1" placement="appLogoOverride" hint-crop="circle" src="$LogoImage"/>
567
<text placement="attribution">$AttributionText</text>
568
<text>$HeaderText</text>
569
<group>
570
<subgroup>
571
<text hint-style="title" hint-wrap="true" >$TitleText</text>
572
</subgroup>
573
</group>
574
<group>
575
<subgroup>
576
<text hint-style="body" hint-wrap="true" >$BodyText1</text>
577
</subgroup>
578
</group>
579
<group>
580
<subgroup>
581
<text hint-style="body" hint-wrap="true" >$BodyText2</text>
582
</subgroup>
583
</group>
584
</binding>
585
</visual>
586
<actions>
587
<action activationType="system" arguments="dismiss" content="$DismissButtonContent"/>
588
</actions>
589
</toast>
590
"@
591
}
592
593
# Snooze button - this option will always enable both action button and dismiss button regardless of config settings
594
if ($SnoozeButtonEnabled -eq "True"){
595
Write-Log -Message "Creating the xml for snooze button"
596
[xml]$Toast = @"
597
<toast scenario="$Scenario">
598
<visual>
599
<binding template="ToastGeneric">
600
<image placement="hero" src="$HeroImage"/>
601
<image id="1" placement="appLogoOverride" hint-crop="circle" src="$LogoImage"/>
602
<text placement="attribution">$AttributionText</text>
603
<text>$HeaderText</text>
604
<group>
605
<subgroup>
606
<text hint-style="title" hint-wrap="true" >$TitleText</text>
607
</subgroup>
608
</group>
609
<group>
610
<subgroup>
611
<text hint-style="body" hint-wrap="true" >$BodyText1</text>
612
</subgroup>
613
</group>
614
<group>
615
<subgroup>
616
<text hint-style="body" hint-wrap="true" >$BodyText2</text>
617
</subgroup>
618
</group>
619
</binding>
620
</visual>
621
<actions>
622
<input id="snoozeTime" type="selection" title="$SnoozeText" defaultInput="15">
623
<selection id="15" content="15 $MinutesText"/>
624
<selection id="30" content="30 $MinutesText"/>
625
<selection id="60" content="1 $HourText"/>
626
<selection id="240" content="4 $HoursText"/>
627
<selection id="480" content="8 $HoursText"/>
628
</input>
629
<action activationType="protocol" arguments="$Action" content="$ActionButtonContent"/>
630
<action activationType="system" arguments="snooze" hint-inputId="snoozeTime" content="$SnoozeButtonContent"/>
631
<action activationType="system" arguments="dismiss" content="$DismissButtonContent"/>
632
</actions>
633
</toast>
634
"@
635
}
636
637
# Add an additional group and text to the toast xml used for notifying about possible deadline. Used with UpgradeOS option
638
if ($DeadlineEnabled -eq "True"){
639
640
$LocalCulture = Get-Culture
641
$RegionDateFormat = [System.Globalization.CultureInfo]::GetCultureInfo($LocalCulture.LCID).DateTimeFormat.LongDatePattern
642
$RegionTimeFormat = [System.Globalization.CultureInfo]::GetCultureInfo($LocalCulture.LCID).DateTimeFormat.ShortTimePattern
643
$DeadlineContent = $DeadlineContent
644
$LocalFormat = $DeadlineContent
645
$LocalFormat = [DateTime]::ParseExact($LocalFormat, "dd-MM-yyyy HH:mm", $Null)
646
$LocalFormat = Get-Date $LocalFormat -f "$RegionDateFormat $RegionTimeFormat"
647
648
$DeadlineGroup = @"
649
<group>
650
<subgroup>
651
<text hint-style="base" hint-align="left">$DeadlineText</text>
652
<text hint-style="caption" hint-align="left">$LocalFormat</text>
653
</subgroup>
654
</group>
655
"@
656
$Toast.toast.visual.binding.InnerXml = $Toast.toast.visual.binding.InnerXml + $DeadlineGroup
657
}
658
659
# Add an additional group and text to the toast xml
660
if ($PendingRebootCheckTextEnabled -eq "True"){
661
$PendingRebootGroup = @"
662
<group>
663
<subgroup>
664
<text hint-style="body" hint-wrap="true" >$PendingRebootCheckTextValue</text>
665
</subgroup>
666
</group>
667
"@
668
$Toast.toast.visual.binding.InnerXml = $Toast.toast.visual.binding.InnerXml + $PendingRebootGroup
669
}
670
671
# Add an additional group and text to the toast xml used for notifying about computer uptime. Only add this if the computer uptime exceeds MaxUptimeDays.
672
if (($PendingRebootUptimeTextEnabled -eq "True") -AND ($Uptime -gt "$MaxUptimeDays")){
673
$UptimeGroup = @"
674
<group>
675
<subgroup>
676
<text hint-style="body" hint-wrap="true" >$PendingRebootUptimeTextValue</text>
677
</subgroup>
678
</group>
679
<group>
680
<subgroup>
681
<text hint-style="base" hint-align="left">$ComputerUptimeText $Uptime $ComputerUptimeDaysText</text>
682
</subgroup>
683
</group>
684
"@
685
$Toast.toast.visual.binding.InnerXml = $Toast.toast.visual.binding.InnerXml + $UptimeGroup
686
}
687
688
# Toast used for upgrading OS. Checking running OS buildnumber. No need to display toast, if the OS is already running on TargetOS
689
if (($UpgradeOS -eq "True") -AND ($RunningOS.BuildNumber -lt "$TargetOS")){
690
Write-Log -Message "Toast notification is used in regards to OS upgrade. Taking running OS build into account"
691
# Load required objects
692
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
693
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
694
695
# Load the notification into the required format
696
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
697
$ToastXml.LoadXml($Toast.OuterXml)
698
699
# Display the toast notification
700
try{
701
Write-Log -Message "All good. Displaying the toast notification"
702
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($App).Show($ToastXml)
703
}
704
catch{
705
Write-Log -Message "Something went wrong when displaying the toast notification" -Level Warn
706
Write-Log -Message "Make sure the script is running as the logged on user" -Level Warn
707
}
708
709
if ($CustomAudio -eq "True"){
710
Invoke-Command -ScriptBlock {Add-Type -AssemblyName System.Speech
711
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
712
$speak.Speak("$CustomAudioTextToSpeech")
713
$speak.Dispose()
714
}
715
}
716
# Stopping script. No need to accidently run further toasts
717
break
718
}
719
720
# Toast used for PendingReboot check and considering OS uptime
721
if (($PendingRebootUptime -eq "True") -AND ($Uptime -gt "$MaxUptimeDays")){
722
Write-Log -Message "Toast notification is used in regards to pending reboot. Uptime count is greater than $MaxUptimeDays"
723
# Load required objects
724
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
725
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
726
727
# Load the notification into the required format
728
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
729
$ToastXml.LoadXml($Toast.OuterXml)
730
731
# Display the toast notification
732
try{
733
Write-Log -Message "All good. Displaying the toast notification"
734
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($App).Show($ToastXml)
735
}
736
catch{
737
Write-Log -Message "Something went wrong when displaying the toast notification" -Level Warn
738
Write-Log -Message "Make sure the script is running as the logged on user" -Level Warn
739
}
740
741
if ($CustomAudio -eq "True"){
742
Invoke-Command -ScriptBlock {Add-Type -AssemblyName System.Speech
743
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
744
$speak.Speak("$CustomAudioTextToSpeech")
745
$speak.Dispose()
746
}
747
}
748
# Stopping script. No need to accidently run further toasts
749
break
750
}
751
752
# Toast used for pendingReboot check and considering checks in registry
753
if (($PendingRebootCheck -eq "True") -AND ($TestPendingRebootRegistry -eq $True)){
754
Write-Log -Message "Toast notification is used in regards to pending reboot registry. TestPendingRebootRegistry returned $TestPendingRebootRegistry"
755
# Load required objects
756
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
757
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
758
759
# Load the notification into the required format
760
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
761
$ToastXml.LoadXml($Toast.OuterXml)
762
763
# Display the toast notification
764
try{
765
Write-Log -Message "All good. Displaying the toast notification"
766
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($App).Show($ToastXml)
767
}
768
catch{
769
Write-Log -Message "Something went wrong when displaying the toast notification" -Level Warn
770
Write-Log -Message "Make sure the script is running as the logged on user" -Level Warn
771
}
772
773
if ($CustomAudio -eq "True"){
774
Invoke-Command -ScriptBlock {Add-Type -AssemblyName System.Speech
775
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
776
$speak.Speak("$CustomAudioTextToSpeech")
777
$speak.Dispose()
778
}
779
}
780
# Stopping script. No need to accidently run further toasts
781
break
782
}
783
784
# Toast used for pendingReboot check and considering checks in WMI
785
if (($PendingRebootCheck -eq "True") -AND ($TestPendingRebootWMI -eq $True)){
786
Write-Log -Message "Toast notification is used in regards to pending reboot WMI. TestPendingRebootWMI returned $TestPendingRebootWMI"
787
# Load required objects
788
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
789
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
790
791
# Load the notification into the required format
792
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
793
$ToastXml.LoadXml($Toast.OuterXml)
794
795
# Display the toast notification
796
try{
797
Write-Log -Message "All good. Displaying the toast notification"
798
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($App).Show($ToastXml)
799
}
800
catch{
801
Write-Log -Message "Something went wrong when displaying the toast notification" -Level Warn
802
Write-Log -Message "Make sure the script is running as the logged on user" -Level Warn
803
}
804
805
if ($CustomAudio -eq "True"){
806
Invoke-Command -ScriptBlock {Add-Type -AssemblyName System.Speech
807
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
808
$speak.Speak("$CustomAudioTextToSpeech")
809
$speak.Dispose()
810
}
811
}
812
# Stopping script. No need to accidently run further toasts
813
break
814
}
815
816
# Toast not used for either OS upgrade or Pending reboot. Run this if all features are set to false in config.xml
817
if (($UpgradeOS -ne "True") -AND ($PendingRebootCheck -ne "True") -AND ($PendingRebootUptime -ne "True")){
818
Write-Log -Message "Toast notification is not used in regards to OS upgrade OR Pending Reboots. Displaying default toast"
819
# Load required objects
820
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
821
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
822
823
# Load the notification into the required format
824
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
825
$ToastXml.LoadXml($Toast.OuterXml)
826
827
# Display the toast notification
828
try{
829
Write-Log -Message "All good. Displaying the toast notification"
830
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($App).Show($ToastXml)
831
}
832
catch{
833
Write-Log -Message "Something went wrong when displaying the toast notification" -Level Warn
834
Write-Log -Message "Make sure the script is running as the logged on user" -Level Warn
835
}
836
837
if ($CustomAudio -eq "True"){
838
Invoke-Command -ScriptBlock {Add-Type -AssemblyName System.Speech
839
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
840
$speak.Speak("$CustomAudioTextToSpeech")
841
$speak.Dispose()
842
}
843
}
844
# Stopping script. No need to accidently run further toasts
845
break
846
}
Copied!
A special thanks go to Martin! If you have any questions regarding this topic, feel free to reach out to me. I am most active on Twitter!
Now go out and impress your boss and colleagues!
Last modified 1yr ago