Add Custom Notifications to a ConfigMgr Task Sequence

One feature I would really like to see added to a Configuration Manager task sequence is the ability to natively provide notification messages to the logged-on user. Previously, to accomplish this, I have used simple pop-up notifications like the Wscript Shell Popup method in a PowerShell script, together with the handy ServiceUI utility in MDT to display the notification in the logged-on users’ session. This has worked well enough for simple messages, and has been useful in several scenarios. For example, see my blog post about prompting for input during a task sequence.

Recently I wrote a PowerShell function to display my own custom notifications using WPF, called New-WPFMessageBox. This allows for much greater customisation of the message box, including adding your own WPF content. So I decided to revisit displaying notifications during a task sequence using this new function instead. In this post I will show you how to add a “Restart Required” notification to run at the end of a task sequence. This can be used to advise the user that a restart needs to take place after the installation of some software for example, and give them the option to restart immediately, or restart later.

RestartRequired

Instead of using the ServiceUI utility – which works well, but it still runs in SYSTEM context even though it will allow you to display in the logged-on users’ session – I decided on a different method that allows you to truly run a process in the users’ context. Thanks to a tip from Roger Zander I found some C# sharp code by a guy named Justin Murray that can be used in PowerShell to make this possible.

Invoke-PSScriptAsUser

Create a new PowerShell script containing the following code. In the $Source variable, copy and paste the C# code from https://github.com/murrayju/CreateProcessAsUser/blob/master/ProcessExtensions/ProcessExtensions.cs. I have renamed the namespace (line 4 in the C# code) from namespace murrayju.ProcessExtensions to namespace Runasuser.


Param($File)

$Source = @"

"@

# Load the custom type
Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $Source -Language CSharp -ErrorAction Stop

# Run PS as user to display the message box
[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("$env:windir\System32\WindowsPowerShell\v1.0\Powershell.exe"," -ExecutionPolicy Bypass -WindowStyle Hidden -File $PSScriptRoot\$File")

Save this script as Invoke-PSScriptAsUser.ps1

Display-RestartNotification

Create a new PowerShell script containing the following code. At the top paste in my New-WPFMessageBox function from https://gist.github.com/SMSAgentSoftware/0c0eee98a673b6ac34f5215ea6841beb. You can, of course, customise the notification as you wish.


# Paste here New-WPFMessageBox function from https://gist.github.com/SMSAgentSoftware/0c0eee98a673b6ac34f5215ea6841beb

$Params = @{
    Content = "You must restart your computer before using Software X."
    Title = "Computer Restart Required!"
    TitleFontSize = 20
    TitleFontWeight = "Bold"
    TitleBackground = "OrangeRed"
    ButtonType = "None"
    CustomButtons = "RESTART NOW","RESTART LATER"
    Sound = 'Windows Notify'
}

New-WPFMessageBox @Params
If ($WPFMessageBoxOutput -eq "RESTART NOW")
{
    Restart-Computer
}

The function saves the content of the button you click to the variable $WPFMessageBoxOutput, so you can use this to perform certain actions depending on which button the user clicks, in this case simply restarting the computer. This variable is only available in the script scope however.

Save this script as Display-RestartNotification.ps1.

Create a Package

Now create a standard package in ConfigMgr containing both of these scripts in the same directory, and distribute the content. No program is required for the package.

Configure Task Sequence

In your task sequence, add a Run Powershell Script step. Reference the package you created and enter the script name and parameters:

Script name: Invoke-PSScriptAsUser.ps1

Parameters: -File Display-RestartNotification.ps1

TS

When the task sequence executes, it will run the Invoke-PSScriptAsUser.ps1 in SYSTEM context, which will in turn run PowerShell in the logged-on users’ context and run the Display-RestartNotification.ps1 script, which displays the notification to the user.

The task sequence will not wait for the user to respond to the message; it will simply finish up in the background and the notification will remain on screen until the user responds to it.

If you enabled the option to Show task sequence progress then the notification will display behind the task sequence progress UI. Since this is the last step in the sequence it doesn’t matter, but if you have other steps running after the notification, you should hide the task sequence progress UI at that point. Since ConfigMgr 1706 we have the TSDisableProgressUI task sequence variable that can do that for us, so simply place a step before the notification step disabling the progress UI:

tsui

The ability to run a process in the user context during a task sequence is quite useful, not just for displaying notifications, but for running any code or process that must run in the user context, for example setting HKCU registry keys, or triggering a baseline evaluation that has user-based settings.

2 thoughts on “Add Custom Notifications to a ConfigMgr Task Sequence

  1. Getting error: Missing closing ‘}’ in statement block or type definition.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingEndCurlyBrace
    Where does that need to be corrected?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.