Introduction
My Toast Notification Script unfortunately only works in PowerShell Full Language Mode (for the time being. I have plans to look into this).
This requirement does not work well with AppLocker and having Constrained Language Mode enabled. My solution to this, is to digitally sign the New-ToastNotification.ps1 file. While working my way through the process myself, I realized that a few changes to the Toast Notification Script itself was needed.
The changes made to this “edition” of the script, are only targeted Configuration Manager. I’m not sure that moving between PowerShell Language Modes coming from Proactive Remediations in Intune, is something that’s possible (if anyone knows this, please let me know).
Additionally to the changes needed, I thought the process itself would make a decent and useful blog post. So here goes. 🙂
AppLocker
- The docs on AppLocker can be found here: AppLocker (Windows) – Windows security | Microsoft Docs
Fast-forwarding past all of the setup of AppLocker and verifying things are working, you will start noticing, that some of your scripts which used to work, no longer work as intended.
With the broken functionality comes following entries in the AppLocker event log: Microsoft-Windows-AppLocker/MSI and Script
- %OSDRIVE%\USERS\MAB\APPDATA\LOCAL\TEMP\__PSSCRIPTPOLICYTEST_PWABLEXA.45H.PSM1 was prevented from running.
- %OSDRIVE%\USERS\MAB\APPDATA\LOCAL\TEMP\__PSSCRIPTPOLICYTEST_WN0403TR.GPB.PS1 was prevented from running.
Constrained Language
Then you realize, that PowerShell is operating in what’s called Constrained Language Mode, and therefore have reduced functionality, which is the reason for the Toast Notification Script is no longer working.
- More on Constrained Language Mode here: PowerShell Constrained Language Mode – PowerShell Team (microsoft.com)
You can verify the current language mode by running: $ExecutionContext.SessionState.LanguageMode
Below is an illustration of the broken functionality, when running the New-ToastNotification.ps1 file directly on a system, where AppLocker is configured and Constrained Language Mode enabled:
Certificate Authority
The solution to this, is to digitally sign the New-ToastNotification.ps1 file.
- A little something on PowerShell code signing: about Signing – PowerShell | Microsoft Docs
There are 2 routes to accomplish this: 1) buy a code signing certificate from a public vendor 2) issue your own code signing certificate from an internal CA.
I chose the latter, and created a code signing template on our internal CA server and issued the template, making it available for certificate requests.
I will not go into details on the CA portion, but for your convenience, find a few snippets of the template and certificate I created below.
Certificate Template:
Certificate Enrollment:
Final Certificate:
PowerShell Code Signing
Sign the New-ToastNotification.ps1 file using PowerShell similar to below:
$cert = Get-ChildItem -Path Cert:\CurrentUser\My –CodeSigningCert Set-AuthenticodeSignature -Certificate $cert -FilePath "C:\Temp\ToastNotificationScript\New-ToastNotification.ps1"
The result will be an added signature block, in the very end of the New-ToastNotification.ps1 file:
AppLocker whitelisting
Regardless of how you prefer to manage your AppLocker rules, you will need to whitelist the publisher, matching that of your newly issued code signing certificate.
Below is an illustration when this is done via Group Policy:
Toast Notification Script
What really changed in this “edition”, is the addition of a new function: Terminate-ToastProcess.
Long story short is, that calling the New-ToastNotification.ps1 file (which requires Full Language Mode) from a Constrained Language Mode session, requires dot-sourcing in order to protect the boundary between the two sessions.
- More on Dot-Sourcing here: PowerShell Constrained Language mode and the Dot-Source Operator – PowerShell Team (microsoft.com)
Otherwise running the script will return following error:
Cannot dot-source this command because it was defined in a different language mode. To invoke this command without importing its contents, omit the '.' operator.
Now, this part was indeed tricky and the only real solution to the problem, was to call powershell.exe with the parameter -noexit:
- powershell.exe -ExecutionPolicy RemoteSigned -Noexit .\New-ToastNotification.ps1 -Config “https://krpublicfiles.blob.core.windows.net/toastnotification/config-toast-rebootpending.xml”
-Noexit also means that powershell.exe, when run from ConfigMgr, will run indefinitely. To counter this part, I created the mentioned function, which terminates the parent powershell.exe process gracefully with exit code 0 (to satisfy the program in ConfigMgr).
Configuration Manager
Using this edition of the script is similar to the current official version.
Create a package containing the New-ToastNotification.ps1 file, distribute to your distribution points, and create a program running the script similar to this:
- powershell.exe -ExecutionPolicy RemoteSigned -Noexit .\New-ToastNotification.ps1 -Config “https://krpublicfiles.blob.core.windows.net/toastnotification/config-toast-runpackageid.xml”
GitHub
Find the New-ToastNotification-AppLocker-Edition.ps1 on my GitHub repository: Toast-Notification-Script/New-ToastNotification-AppLocker-Edition.ps1 at master · imabdk/Toast-Notification-Script (github.com)
ENJOY 🙂
we are using your script for toast notifications, but have seem issues where the notification will not “pop up”, but after a reboot (possible a logoff/logon too) that they show up in the notifications list. thoughts?
we are deploying via SCCM/Config Mgr.
Do you have focus assist enabled? Can you try and set the scenario option in the config.xml to alarm instead of reminder. Setting it to alarm, basically bypasses focus assist. Also, are you using your own custom app for doing the notification? See version 2.3.0. Let me know how you proceed.
Hey Martin!
We was gonna use it now, we have applocker and I signed the .ps1 file and it run, but after clicking install it did not start the feature update from software center.
Then I looked at the applocker logs and it prevented the .cmd script to run.
%OSDRIVE%\USERS\ANWT\APPDATA\ROAMING\TOASTNOTIFICATIONSCRIPT\SCRIPTS\TOASTRUNUPDATEID.CMD was prevented from running.
Am I doing something wrong or is this problem for everybody with applocker scripting rules enabled?
Right, that’s what applocker is about. Whitelist the scripts on their location and you’re set. 🙂
I Will try 🙂 thanks 😊
I’ve signed the script successfully, and while it seems to be working, I’m getting a huge amount errors on the package deployment. Specifically Message ID 10070, Program Failed (Run Time Exceeded). I’m still deploying with user rights doing this. Do you think it could be the NoExit PowerShell parameter (I don’t see that used on the other page detailing deploying without signature)?
AppLocker has nuked my Intune user-context toast notification script also ðŸ˜
Keeping my eyes peeled for any hints of a solution. Thanks for the guidance so far!