FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Skip the AppLocker policy test files when no script policy is configured by azchohfi · Pull Request #28374 · PowerShell/PowerShell · GitHub

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
PowerShell:masterfrom
azchohfi:skip-applocker-probe-without-policy
Open

Alexandre Zollinger Chohfi (azchohfi) wants to merge 3 commits into
PowerShell:masterfrom
azchohfi:skip-applocker-probe-without-policy

Conversation

Copy link
Copy Markdown

PR Summary

Fixes #28372.

On every start, SystemPolicy.GetSystemLockdownPolicy() finds the system-wide AppLocker policy by writing two __PSScriptPolicyTest_* files to %TEMP%, checking them with SaferIdentifyLevel/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\CodeIdentifiers in 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 AuthenticodeEnabled and nothing else, and that key with no subkeys and no other values does not define an SRP policy (creating one adds DefaultLevel, 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 ... before after difference
exit 366 ms 326 ms -44.4 ms (27.8 to 56.7)
Get-ChildItem -Name src | Select-Object -First 5 546 ms 508 ms -38.7 ms (30.6 to 43.7)

On 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:

  • xUnit SystemPolicyTests (new): the registry check against a temporary HKCU key (missing, empty, only AuthenticodeEnabled, other value, rule subkey), the file check, and that HasAppLockerOrSaferScriptPolicy() matches the machine.
  • Pester AppLockerProbe.Tests.ps1 (new): starts pwsh with a private TEMP and checks that the test files are written if and only if HasAppLockerOrSaferScriptPolicy() is true.
  • Ran Start-PSxUnit for SystemPolicy and SecuritySupport (4 passed) and Start-PSPester for 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):

  1. AppLocker: start AppIDSvc, create the default script rules and set Script rules to Enforce (secpol.msc or Set-AppLockerPolicy), run gpupdate /force, and confirm Script.AppLocker exists. 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).
  2. SRP: in secpol.msc create Software Restriction Policies with Security Level "Disallowed" (default path rules allow Windows and Program Files). Same check: ConstrainedLanguage for both builds, test files written.
  3. Remove the policies: FullLanguage, and with this change no test files in %TEMP%.

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

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>
Copilot AI balanced review requested due to automatic review settings November 6, 2026 22:54

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

🟡 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 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

Comment thread test/xUnit/csharp/test_SystemPolicy.cs Resolved
- 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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Startup: the AppLocker probe costs about 40 ms on every pwsh start, also when no AppLocker policy exists

2 participants


Back | FazBrowse Home | New Git URL