Allow Nerdio scripted actions on Hosts with WDAC script enforcement

Hi all,

we are currently testing Windows Defender Application Control (= WDAC) to lock down a hardened host pool. One core feature of WDAC is script enforcement. In a nutshell, it forces unsigned scripts and interactive powershell sessions into constrained language, while scripts signed with a trusted certificate are allowed to run in full language.

Important note: Full language code must not be executed in a constrained language environment and vice versa, eg.

  • Trying to run a signed script by dot sourcing it from an interactive session
  • Calling an unsigned script within a signed script

Crossing the boundary between languages is explicitly forbidden by design. This is what I believe is causing scripts executed via Nerdios' scripted actions to fail:

C:\\Packages\\Plugins\\Microsoft.Compute.CustomScriptExtension\\1.9.5\\Downloads\\0\\be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1: 
Cannot dot-source this command because it was defined in a different language mode. To invoke this command without
importing its contents, omit the \u0027.\u0027 operator.
CategoryInfo          : InvalidOperation: (:) [be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1], NotSupportedException
FullyQualifiedErrorId : DotSourceNotSupported,be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1

 

To get a better understanding of what's happening, I've enabled powershell transcription on our test host:

**********************
Windows PowerShell transcript start
Start time: 20260202145847
Username: WORKGROUP\SYSTEM
RunAs User: WORKGROUP\SYSTEM
Configuration Name: 
Machine: AZVMTST001 (Microsoft Windows NT 10.0.26200.0)
Host Application: powershell -ExecutionPolicy Unrestricted -File be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1 -ScriptName ef59550daacb9c7c1698e712d7b449a9.ps1 -ScriptParameters <redacted>
Process ID: 1536
PSVersion: 5.1.26100.7462
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.26100.7462
BuildVersion: 10.0.26100.7462
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
**********************
Command start time: 20260202145848
**********************
PS>C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9.5\Downloads\0\be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1
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.
C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9.5\Downloads\0\be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1
: 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.
    + CategoryInfo          : InvalidOperation: (:) [be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1], NotSupportedException
    + FullyQualifiedErrorId : DotSourceNotSupported,be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1

**********************
Windows PowerShell transcript end
End time: 20260202145848
**********************

 

Both files be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1 and ef59550daacb9c7c1698e712d7b449a9.ps1 are signed with a trusted signing certificate and run fine by themselves. The problem seems to stem from running powershell with the -File parameter, as described here:

Scenario 2: The Hidden Trigger - PowerShell.exe -File with [CmdletBinding()]

This is the less obvious scenario that catches many people off guard. When you use both of these conditions together:

  1. PowerShell.exe -File script.ps1 (using the -File parameter)
  2. The script contains [CmdletBinding()]

PowerShell automatically uses dot sourcing behavior, which can trigger the language mode boundary crossing issue. Neither condition alone causes problems - it's specifically their combination.

Source: https://www.appcontrol.ai/post/powershell-constrained-language-mode-the-wdac-security-feature-that-s-breaking-your-scripts

 

I am able to reproduce the described behaviour:

  • Running powershell -ExecutionPolicy Unrestricted -File be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1 -ScriptName ef59550daacb9c7c1698e712d7b449a9.ps1 -ScriptParameters <redacted> causes the dot sourcing error
  • Running powershell -ExecutionPolicy Unrestricted -Command ".\be7c94b1-6a24-403c-9637-a1f9fc05aabf.ps1 -ScriptName ef59550daacb9c7c1698e712d7b449a9.ps1 -ScriptParameters <redacted>" works as expected

 

Solution:

Change the Azure Custom Script Extension execution triggered by nerdio to not use dot sourcing by calling powershell with the -Command parameter instead of -File

 

If you need any more information to reproduce this behaviour in your lab, feel free to ask.

2

Comments (2 comments)

0
Avatar
Boryana Borisova

Thank you for the information share. Looking into hardening non-persistent/multi-session AVDs  with WDAC, but I recall how invasive and tricky it can be to balance security with operations with it. Do you have any tips or references on how to configure WDAC for such an environment that doesn't break Nerdio?

0
Avatar
Lars Bertulies

Do you have any tips or references on how to configure WDAC for such an environment that doesn't break Nerdio?

Leave “Script Enforcement” disabled, as it (currently) breaks scripted actions in Nerdio.

Define a managed installer in WDAC to minimize overhead for manual rule creation and, if possible, deploy EVERYTHING via said managed installer.

Disable embedded automatic update functionality in software packages (eg. Google Chrome, Adobe Reader…), as it breaks the WDAC rules created via managed installer.

 

Please sign in to leave a comment.