Constrained Language Mode and Custom Detection Scripts

by | Sep 24, 2024 | Blog

At Patch My PC (PMPC), ensuring seamless app deployment is a priority. During a recent Win32App deployment via Intune, a detection script failure highlighted the role of Constrained Language Mode (CLM) in restricting certain script executions. This post dives into how CLM can impact the Intune Custom detection scripts and how to manage it using AppLocker.

Detection Rules

When deploying Win32Apps in Intune, detection rules are critical for confirming successful installation. We automatically handle this at PMPC by generating detection scripts, simplifying the process for customers. The detection scripts are minified to reduce their size due to the size limitations of Intune policy payloads.

For example, this is the detection script that is automatically created for the Simba Spark ODBC Driver

intune custom detection script example:

In this case, the custom detection rule involved a PowerShell script containing:

[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(''))

The Detection Rules Issue

When the application is being installed, the detection rule’s job is to verify if the application has been successfully installed. However, the custom detection script for the Win32App failed. To investigate further, we need to check the agentexecutor.log. This important log file is located in the Intune Management Extension folder.

The agentexecutor.log in the intunemanagementextension log folder contains all the information about PowerShell scripts that were executed from the IME

Upon review, we found this error message inside the agentexecutor.log. The term ‘l’ is not recognized as the name of a cmdlet, function, script file, or operable program.

When looking at the error: The term 'l' is not recognized as the name of a cmdlet, function, script file, or operable program.  It seems that Constrained Language Mode is activated on the device

After checking the Agentexecutor.log, we suspected that Constrained Language Mode (CLM) was blocking the script’s use of the .NET method FromBase64String. Why? Let me share some background information about CLM to get some understanding, about what was happening.

Understanding Constrained Language Mode (CLM)

Constrained Language Mode (CLM) is a PowerShell security feature that restricts the execution of certain features, such as custom .NET methods, COM objects, and dynamic types. Security policies such as AppLocker or Windows Defender Application Control (WDAC) often enforce CLM to limit the risk posed by unauthorized or malicious scripts.

In CLM, PowerShell allows basic cmdlets and operations while blocking the use of advanced scripting features. This mode is typically applied in environments where users need limited PowerShell functionality, but higher security is required. For example, scripts that rely on .NET methods like [Convert]::FromBase64String() will be blocked.

Constrained Mode can be enforced at a per-user level through AppLocker or globally across a system. It ensures that untrusted scripts cannot access full PowerShell capabilities, reducing the risk of exploitation while maintaining administrative functionality.

In summary, CLM is a powerful way to restrict PowerShell’s execution environment. It enhances security by limiting scripts to essential operations unless they are explicitly trusted.

Which language mode is PowerShell using?

To verify if PowerShell is running in Constrained Language Mode, you can check the language mode by executing

$ExecutionContext.SessionState.LanguageMode

If the result is ConstrainedLanguage, CLM is active.

When executing $ExecutionContext.SessionState.LanguageMode it becamse obvious that constrainedlanguage mode was active

If the result is FullLanguage mode, CLM is not active, and PowerShell runs in FullLanguage mode.

With PowerShell Constrained Language Mode being active, the use of most .NET methods in the PowerShell session will be restricted, only allowing those explicitly documented by Microsoft. The method FromBase64String, which belongs to the .NET System.Convert class, is not included in the allowed types. Therefore, with CLM enabled, scripts using FromBase64String will be blocked. This means that the entire detection script, such as the one generated by Patch My PC (PMPC), will fail if it attempts to use this method, ultimately preventing the detection rule from running successfully.

The Root Cause – Incorrect Configuration of CLM

After spending some time on the case we noticed that Constrained Language Mode was enabled system-wide. CLM can be activated by entering this command in your PowerShell session.

Constrained Languange Mode was configured System-wide

This method applies the restriction system-wide, impacting both user and system contexts. This could lead to unintended side effects such as breaking the Win32app Detection rule. Instead, we recommend configuring AppLocker policies to manage Constrained Language Mode more selectively, applying it only where necessary.

A Better Approach – Use AppLocker Powershell Constrained Language Mode

Rather than enforcing CLM globally via the PSLockDownPolicy or using PowerShell to enable CLM, a better approach is to use AppLocker to control script execution. AppLocker allows administrators to configure rules that manage whether a PowerShell script runs in Full Language Mode or Constrained Language Mode.

By configuring AppLocker rules based on the script’s publisher, you can allow specific scripts to run in Full Language Mode. This will grant them access to advanced PowerShell features without applying global restrictions, preventing detection failures while maintaining security.

Let’s discuss a bit how Applocker determines the language mode to fully understand why it could be a better approach.

Applocker Powershell constrained language mode.

When AppLocker is configured, PowerShell can run in either Full Language Mode or Constrained Language Mode depending on whether the script is trusted. Default AppLocker rules enforce Constrained Language Mode for scripts unless they are explicitly allowed (e.g., through a certificate, path, or publisher rule).

During startup, PowerShell checks the AppLocker policy using temporary PSScriptPolicyTest*.ps1 and PSScriptPolicyTest*.psm1 files to determine the correct language mode.

During startup, PowerShell checks the AppLocker policy using temporary PSScriptPolicyTest*.ps1 and PSScriptPolicyTest*.psm1 files to determine the correct language mode.When the ps1 is blocked we will notice the event 8007 in the event log

What is the _PSLockdownpolicy

The PSLockdownPolicy is a system-wide setting in PowerShell that determines the level of restrictions applied to PowerShell scripts and commands. This policy directly controls the language mode of PowerShell, affecting what users or scripts can execute within the environment. It is particularly relevant when security mechanisms like Constrained Language Mode (CLM) are in place to prevent the execution of unauthorized scripts.

Here’s an overview of the different lockdown policy levels:

  1. FullLanguage: No restrictions are applied to the PowerShell environment. Scripts can run with the full range of PowerShell commands and functionalities.

  2. ConstrainedLanguage: A restricted mode in which only a subset of PowerShell cmdlets and operations is allowed. This mode is enforced primarily on systems with strict AppLocker or Device Guard configurations. It limits the execution of certain script types (e.g., .NET method calls like FromBase64String, which is a part of the .NET System.Convert Class) unless the script is signed or comes from a trusted source.

  3. NoLanguage: This is the most restrictive mode, where no scripts or commands can be executed. Users can only run individual cmdlets interactively, but cannot write or execute any PowerShell scripts or expressions.

  4. RestrictedLanguage: Similar to NoLanguage, it severely limits what can be executed but allows basic, built-in commands.

PSLockdownPolicy is usually configured with a PowerShell script from Intune to enforce security policies on a system. PowerShell queries this policy to determine the allowed execution environment. It’s commonly used in environments where security and prevention of script-based attacks are crucial.

Important: Do not create an Applocker rule to allow the PSScriptPolicyTest*.ps1 files. This could unintentionally bypass security and allow all scripts to run in Full Language Mode, defeating the purpose of CLM.

Solving the Detection Script Issue

In our case, the detection script failed because CLM blocked the use of the .NET method FromBase64String. To fix this, we advise removing the global PSLockDownPolicy / CLM setting and instead adding an AppLocker rule that allows the detection script to run in Full Language Mode.

With Applocker configured to restrict the execution PowerShell, it’s best practise to configure a code-signing certificate in the PMPC console, to digitally sign the detection scripts.

Step by step guide to configure a code-signing certificate in the PMPC console, to digitally sign the detection scripts.

Please Note: When using Intune Apps for Patch My PC Cloud, the detection scripts are signed by default. To get the details needed for the AppLocker rules whitelist, go to a win32 app published through the PMPC Cloud portal. Once there, save the detection script as a .ps1 file and check the Properties of the newly saved file. You can view the Digital Signature and the certificate used to sign the script.

Adding the publisher to our existing Applocker Policy

With the Detection scripts digitally signed, we could configure an Applocker rule to ensure the detection scripts are always allowed (even in user mode). The AppLocker rule below was configured based on the script’s publisher, ensuring that the detection script could bypass CLM restrictions without compromising system security.

importing the poweshell script to fetch the published of the script so we can add it to the Applocker policy to make sure it will always be allowed and not getting blocked by the constrained language mode

After adding the Patch My PC published to our Applocker policy, we can export this Applocker rule and add it to the existing Applocker PowerShell scripts policy (UTF-8). By adding this publisher to our Applocker policy, we can ensure that the custom detection script can always be executed without any barriers.

If you want to learn more about Applocker and how we could configure a pretty secure baseline, feel free to read this blog post. It will guide you through configuring the Applocker policy from scratch. If you don’t want to build it from scratch, you could also use some automation to deploy the Applocker baseline I put together.

Deploy Applocker to Intune with PowerShell (call4cloud.nl)

Summary

“When deploying Win32Apps in Intune, Constrained Language Mode (CLM) can interfere with detection scripts that depend on restricted methods. Instead of enforcing global CLM restrictions, a more effective approach is to use AppLocker to selectively allow trusted scripts to run in Full Language Mode while maintaining strong security controls.

Our goal is not to compromise security but to strike the right balance. By configuring AppLocker (or WDAC) policies, you can restrict PowerShell scripts to only those digitally signed with a trusted code-signing certificate. This approach ensures functionality without sacrificing protection.

At Patch My PC, we automate detection rules to simplify deployments, but it’s essential to have the proper configurations in place to ensure smooth app deployments and maintain a secure environment.”