Repository navigation
Skip the AppLocker policy test files when no script policy is configured - #28374
Open
Alexandre Zollinger Chohfi (azchohfi) wants to merge 3 commits into
Open
Alexandre Zollinger Chohfi (azchohfi) wants to merge 3 commits into
Alexandre Zollinger Chohfi (azchohfi) wants to merge 3 commits into
Conversation
To find the system-wide AppLocker policy, PowerShell writes two __PSScriptPolicyTest_* files to %TEMP% on every start, checks them with SAFER, and deletes them. When the machine has no AppLocker script rules and no Software Restriction Policy, the result is always Allowed. Check the places such a policy lives first and skip the test files when none of them has a policy: the compiled AppLocker script policy (%windir%\System32\AppLocker\Script.AppLocker), AppLocker script rules under HKLM\SOFTWARE\Policies\Microsoft\Windows\SrpV2\Script, and SRP under SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiers in HKLM and HKCU. A CodeIdentifiers key with only AuthenticodeEnabled is treated as no policy. Anything that exists or cannot be read keeps the test. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Alexandre Zollinger Chohfi (azchohfi)
requested review from
a team,
Patrick Meinecke (SeeminglyScience) and
Travis Plunk (TravisEz13)
as code owners
November 6, 2026 22:54
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The WOW64 path lookup can miss an effective AppLocker policy and leave the session in FullLanguage, while additional policy-detection and test-reliability issues remain unresolved.
5 open issues
Use the native AppLocker policy path under WOW64 · New Treat an existing empty AppLocker key as present · New Fail the test when the child process exits unsuccessfully · New Account for WLDP early return in the policy probe assertion · New Match File.Exists expectations to conservative error handling · New
What changed in this PR
This PR addresses #28372 by reducing PowerShell startup overhead when no AppLocker script policy or Software Restriction Policy is detected, avoiding temporary policy-test files and their SAFER checks.
Changes:
- Adds policy-file and registry checks before running the existing AppLocker probe.
- Adds xUnit coverage for policy detection helpers and machine configuration.
- Adds a Pester test that monitors policy-test file creation during startup.
| File | Description |
|---|---|
test/xUnit/csharp/test_SystemPolicy.cs |
Tests registry, file, and machine-policy detection. |
test/powershell/engine/Security/AppLockerProbe.Tests.ps1 |
Monitors temporary probe-file creation in a child PowerShell process. |
src/System.Management.Automation/security/wldpNativeMethods.cs |
Adds policy-presence checks and skips the SAFER probe when no policy is detected. |
Review effort: Balanced
- Keep the AppLocker probe in 32-bit processes on 64-bit Windows, where the system directory is redirected. - Treat an existing SrpV2\Script key as a policy even when it is empty. - Fail the Pester test if the child pwsh exits with an error, and do not expect the test files when WDAC enforces lockdown. - Use the same helpers in the xUnit machine check. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


PR Summary
Fixes #28372.
On every start,
SystemPolicy.GetSystemLockdownPolicy()finds the system-wide AppLocker policy by writing two__PSScriptPolicyTest_*files to %TEMP%, checking them withSaferIdentifyLevel/SaferComputeTokenFromLevel, and deleting them. When the machine has no AppLocker script rules and no Software Restriction Policy, the answer is always "allowed".This adds a check before the test files are written. They are skipped only when none of these has a policy:
%windir%\System32\AppLocker\Script.AppLocker, the compiled effective AppLocker script policy (group policy, local policy or MDM);HKLM\SOFTWARE\Policies\Microsoft\Windows\SrpV2\Script(AppLocker script rules from group policy);SOFTWARE\Policies\Microsoft\Windows\Safer\CodeIdentifiersin HKLM and HKCU (Software Restriction Policies, which the SAFER call also enforces).A location counts as "no policy" only if it does not exist. The one exception is the CodeIdentifiers key: Windows can create it with just
AuthenticodeEnabledand nothing else, and that key with no subkeys and no other values does not define an SRP policy (creating one addsDefaultLevel,TransparentEnabled, rule subkeys and so on). If anything exists or cannot be read, the test files are written as before. WDAC and the per-file checks are unchanged.PR Context
Measured on Windows 11 26100 (i9-10900K), Release builds of master 1aac7f5 with and without this change (the two outputs differ only in System.Management.Automation.dll), 40 interleaved runs, median of the paired differences with 95% confidence interval:
pwsh -NoProfile -NonInteractive -Command ...exitGet-ChildItem -Name src | Select-Object -First 5On this machine (no AppLocker or SRP policy) the build without the change writes two test files to %TEMP% per start and the build with it writes none; both report
GetSystemLockdownPolicy()= None and FullLanguage.Tests:
SystemPolicyTests(new): the registry check against a temporary HKCU key (missing, empty, only AuthenticodeEnabled, other value, rule subkey), the file check, and thatHasAppLockerOrSaferScriptPolicy()matches the machine.AppLockerProbe.Tests.ps1(new): starts pwsh with a private TEMP and checks that the test files are written if and only ifHasAppLockerOrSaferScriptPolicy()is true.Start-PSxUnitfor SystemPolicy and SecuritySupport (4 passed) andStart-PSPesterfor test/powershell/engine/Security and the ConstrainedLanguage*.Tests.ps1 files (23 passed, 0 failed; the 101 tests tagged RequireAdminOnWindows did not run because I ran unelevated).I could not test with a real AppLocker or SRP policy because writing those policy keys needs admin rights. To check enforcement on a test machine (as admin):
Set-AppLockerPolicy), rungpupdate /force, and confirmScript.AppLockerexists. As a standard user,pwsh -c '$ExecutionContext.SessionState.LanguageMode'should print ConstrainedLanguage with and without this change, and the new Pester test should pass (test files written).I used GitHub Copilot to investigate this and to help write the change and tests; I reviewed the code and ran the tests above myself.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright header