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. 🙂
- 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.
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:
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.
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:
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).
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”
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)