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
##*=============================================

}