Public/OSDCloudIPU/Invoke-IPUPreInstallNotification.ps1
function Invoke-IPUPreInstallNotifications { <# .SYNOPSIS --. .DESCRIPTION Triggers Notifications when Upgrade Starts .INPUTS None. .OUTPUTS None. .NOTES Created by @gwblok .LINK https://garytown.com .LINK https://www.recastsoftware.com .COMPONENT -- .FUNCTIONALITY -- #> ## Set script requirements #Requires -Version 3.0 ##*============================================= ##* VARIABLE DECLARATION ##*============================================= #region VariableDeclaration ## Get script path and name [string]$ScriptPath = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Definition) [string]$ScriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Definition) Start-Transcript Write-Output -------------------------------------- Write-Output $ScriptPath $ScriptName Get-Date #Registry Path that will get Tagged $registryPath = "HKLM:\SOFTWARE\WaaS" $TimeStamp = Get-Date -f s $keynameStart = "CA_PreInstallNotification_Start" $keynameFinish = "CA_PreInstallNotification_Finish" New-ItemProperty -Path $registryPath -Name $keynameStart -Value $TimeStamp -Force #Logfile generated by this script $WaaSFolder = "$($env:ProgramData)\WaaS" $logfile = "$WaaSFolder\CustomActions.log" $whoami = whoami # Load some required namespaces $null = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] $null = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] Add-Type -Path "$PSScriptRoot\Microsoft.Toolkit.Uwp.Notifications.dll" if (!($Global:ModuleBase = (Get-Module -Name OSD).ModuleBase)){Import-Module -Name OSD} if ($Global:ModuleBase = (Get-Module -Name OSD).ModuleBase){ $Global:NotificationsPath = "$Global:ModuleBase\Projects\assembly\Microsoft.Toolkit.Uwp.Notifications.dll" Write-Host "Adding Type Notifications: $Global:NotificationsPath" Add-Type -Path $Global:NotificationsPath } #endregion ##*============================================= ##* END VARIABLE DECLARATION ##*============================================= ##*============================================= ##* FUNCTION LISTINGS ##*============================================= #region FunctionListings #CMTraceLog Function formats logging in CMTrace style function CMTraceLog { [CmdletBinding()] Param ( [Parameter(Mandatory=$false)] $Message, [Parameter(Mandatory=$false)] $ErrorMessage, [Parameter(Mandatory=$false)] $Component = "Notification", [Parameter(Mandatory=$false)] [int]$Type, [Parameter(Mandatory=$true)] $LogFile ) <# Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red) #> $Time = Get-Date -Format "HH:mm:ss.ffffff" $Date = Get-Date -Format "MM-dd-yyyy" if ($ErrorMessage -ne $null) {$Type = 3} if ($Component -eq $null) {$Component = " "} if ($Type -eq $null) {$Type = 1} $LogMessage = "<![LOG[$Message $ErrorMessage" + "]LOG]!><time=`"$Time`" date=`"$Date`" component=`"$Component`" context=`"`" type=`"$Type`" thread=`"`" file=`"`">" $LogMessage | Out-File -Append -Encoding UTF8 -FilePath $LogFile } ##*============================================= ##* END FUNCTION LISTINGS ##*============================================= ##*============================================= ##* SCRIPT BODY ##*============================================= #region ScriptBody CMTraceLog -Message "--------------------------" -Type 1 -LogFile $LogFile CMTraceLog -Message "Starting $ScriptName" -Type 1 -LogFile $LogFile CMTraceLog -Message "Running as: $whoami" -Type 1 -LogFile $LogFile $SetupProgressPath = "HKLM:System\Setup\mosetup\volatile" CMTraceLog -Message "Waiting For SetupProgress Value to be populated..." -Type 1 -LogFile $LogFile $Minutes = 1 DO { $SetupProgress = Get-ItemPropertyValue -Path $SetupProgressPath -Name "SetupProgress" -ErrorAction SilentlyContinue if (!($SetupProgress)) { $Minutes += 1 Start-Sleep -Seconds 60 } if ($Minutes -eq 20) { CMTraceLog -Message "Waited $Minutes Minutes, exiting script with Exit 20, I'm tired of waiting" -Type 3 -LogFile $LogFile $TimeStamp = Get-Date -f s New-ItemProperty -Path $registryPath -Name $keynameFinish -Value $TimeStamp -Force exit 20 } } Until ($SetupProgress) $ToastTag = "PowerShell" $ToastGroup = "PowerShell" $ToastContentBuilder = [Microsoft.Toolkit.Uwp.Notifications.ToastContentBuilder]::new() $ProgressBar = [Microsoft.Toolkit.Uwp.Notifications.AdaptiveProgressBar]@{ Title = [Microsoft.Toolkit.Uwp.Notifications.BindableString]::new("progressTitle") Value = [Microsoft.Toolkit.Uwp.Notifications.BindableProgressBarValue]::new("progressValue") ValueStringOverride = [Microsoft.Toolkit.Uwp.Notifications.BindableString]::new("progressValueString") Status = [Microsoft.Toolkit.Uwp.Notifications.BindableString]::new("progressStatus") } $ToastContent = $ToastContentBuilder.AddText("Upgrading Windows 10..."). AddVisualChild($ProgressBar). AddText("Please do not reboot until you're notified..."). GetToastContent() $Toast = [Windows.UI.Notifications.ToastNotification]::new($ToastContent.GetXml()) $Toast.Tag = $ToastTag $Toast.Group = $ToastGroup $dict = New-Object 'System.Collections.Generic.Dictionary[[string],[string]]' $dict.Add("progressValue","$SetupProgressNumber") $dict.Add("progressValueString","$SetupProgress% Complete") $dict.Add("progressStatus","Installing...") $dict.Add("progressTitle","Processing Feature Update of Windows to 20H2") $Toast.Data = [Windows.UI.Notifications.NotificationData]::new($dict, 0) CMTraceLog -Message "Triggering Toast" -Type 1 -LogFile $LogFile $Notification = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Windows.SystemToast.SecurityAndMaintenance") $Notification.Show($Toast) ### Run to here first to display Start-Sleep -Seconds 2 do { Start-Sleep -Seconds 5 $SetupProgress = Get-ItemPropertyValue -Path $SetupProgressPath -Name "SetupProgress" -ErrorAction SilentlyContinue $SetupProgressNumber = $SetupProgress / 100 ### Update the Toast! (Run this separately to update) $dict = New-Object 'System.Collections.Generic.Dictionary[[string],[string]]' $dict.Add("progressValue","$SetupProgressNumber") $dict.Add("progressValueString","$SetupProgress% Complete") $dict.Add("progressStatus","Installing...") $dict.Add("progressTitle","Processing Feature Update of Windows to 20H2") $NotificationData = [Windows.UI.Notifications.NotificationData]::new($dict, 0) [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Windows.SystemToast.SecurityAndMaintenance").Update($NotificationData, $ToastTag, $ToastGroup) } Until ($SetupProgress -eq "100") if ($SetupProgress -eq "100") { ### Update the Toast! (Run this separately to update) $dict = New-Object 'System.Collections.Generic.Dictionary[[string],[string]]' $dict.Add("progressValue","$SetupProgressNumber") $dict.Add("progressValueString","$SetupProgress% Complete") $dict.Add("progressStatus","Waiting for Restart") $dict.Add("progressTitle","First Phase of Feature Update of Windows to 20H2 Complete") $NotificationData = [Windows.UI.Notifications.NotificationData]::new($dict, 0) [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Windows.SystemToast.SecurityAndMaintenance").Update($NotificationData, $ToastTag, $ToastGroup) } $TimeStamp = Get-Date -f s New-ItemProperty -Path $registryPath -Name $keynameFinish -Value $TimeStamp -Force CMTraceLog -Message "Finished $ScriptName" -Type 1 -LogFile $LogFile exit $exitcode #endregion ##*============================================= ##* END SCRIPT BODY ##*============================================= } |