Prerequisites
Steps to reproduce
Summary of the new feature / enhancement
PSAuthorizationManager.IsTrustedPublisher() only checks CurrentUser\TrustedPublisher (StoreLocation.CurrentUser). It does not consult LocalMachine\TrustedPublisher. This causes validly signed scripts to be blocked under GPO-enforced AllSigned when:
- The process runs as LocalSystem or another service account (whose
CurrentUser\TrustedPublisher is not the enterprise-managed store and is typically empty/unpopulated)
- A Group Policy enforces AllSigned at MachinePolicy or UserPolicy scope
- An administrator or GPO has deployed the signing certificate to
LocalMachine\TrustedPublisher
PowerShell treats the publisher as unknown, calls AuthenticodePrompt(), and because the host is non-interactive (host == null || host.UI == null), returns DoNotRun — blocking the script with AuthorizationManager check failed.
This bug also exists in Windows PowerShell 5.1
The same IsTrustedPublisher() code path exists in Windows PowerShell 5.1 (System.Management.Automation.dll). The behavior is identical — only CurrentUser\TrustedPublisher is consulted. Since PS 5.1 is in maintenance mode, we understand it is unlikely to receive this fix, but the issue should be documented here as it affects the majority of enterprise Windows systems that still rely on PS 5.1 for automation and VM extension execution.
This bug prevents customers from securing their systems
Enterprise security teams deploy AllSigned execution policy via Group Policy specifically to prevent execution of unsigned or untrusted scripts — this is a fundamental security best practice recommended by Microsoft, CIS benchmarks, and DISA STIGs.
However, this bug creates an impossible choice for security-conscious organizations:
- Enforce AllSigned (as security policy requires) → Microsoft's own signed scripts break because PowerShell ignores the machine-wide TrustedPublisher store where enterprise admins deploy certificates. Azure VM extensions, Windows services, and automation all fail silently.
- Relax execution policy to RemoteSigned or Bypass → automation works, but the security posture is weakened, violating compliance requirements.
There is no workaround that preserves both security and functionality:
- Adding certs to SYSTEM's
CurrentUser\TrustedPublisher is fragile and non-standard — no enterprise tooling (GPO, Intune, SCCM) targets per-user stores for service accounts.
- The only enterprise-standard mechanism for deploying trusted publisher certificates —
LocalMachine\TrustedPublisher via GPO — is the one store PowerShell doesn't check.
The net effect is that PowerShell's AllSigned policy is incompatible with non-interactive execution of Microsoft-signed scripts, which undermines customers' ability to both secure their systems and use Azure/Microsoft services.
Real-world impact
This affects any software that ships signed .ps1 scripts and runs them non-interactively under AllSigned:
- Azure VM extensions (Dependency Agent, Custom Script Extension, Log Analytics, Azure Monitor Agent) — all run as SYSTEM with no interactive session
- Windows services that execute PowerShell scripts
- Scheduled tasks running as LocalSystem or a service account
- Intune/SCCM-deployed PowerShell scripts
We are seeing this on ~279 enterprise Azure VMs where GPO enforces AllSigned. The scripts are ESRP-signed with valid Authenticode signatures (Get-AuthenticodeSignature reports Valid), but PowerShell blocks them because the signer cert is not in CurrentUser\TrustedPublisher for the SYSTEM account.
Steps to reproduce
Prerequisites: Download the attached Exit0.ps1 (a signed Microsoft script that simply calls exit 0).
# 1. Verify the script has a valid Authenticode signature
Get-AuthenticodeSignature .\Exit0.ps1
# 2. Confirm the signer cert is NOT in CurrentUser\TrustedPublisher
# (it won't be unless you've manually added it)
Get-ChildItem Cert:\CurrentUser\TrustedPublisher
# 3. Run under AllSigned in non-interactive mode — this simulates GPO-enforced AllSigned
pwsh -NonInteractive -ExecutionPolicy AllSigned -File .\Exit0.ps1
# Result: "AuthorizationManager check failed"
To demonstrate that LocalMachine\TrustedPublisher is ignored, add the signer cert there and retry:
# 4. Extract the signer cert and add it to LocalMachine\TrustedPublisher (requires admin)
$sig = Get-AuthenticodeSignature .\Exit0.ps1
Export-Certificate -Cert $sig.SignerCertificate -FilePath signer.cer
Import-Certificate -FilePath signer.cer -CertStoreLocation Cert:\LocalMachine\TrustedPublisher
# 5. Retry — still fails because PowerShell only checks CurrentUser\TrustedPublisher
pwsh -NonInteractive -ExecutionPolicy AllSigned -File .\Exit0.ps1
# Result: STILL "AuthorizationManager check failed"
# 6. Now add to CurrentUser\TrustedPublisher — this is what PowerShell actually checks
Import-Certificate -FilePath signer.cer -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
# 7. Retry — now it works
pwsh -NonInteractive -ExecutionPolicy AllSigned -File .\Exit0.ps1
# Result: Success (exit 0)
Steps 4-7 prove that LocalMachine\TrustedPublisher is ignored and only CurrentUser\TrustedPublisher is consulted.
To reproduce as LocalSystem (the real-world scenario), use PsExec -s or a scheduled task running as SYSTEM.
Expected behavior
A validly signed script whose signer certificate is trusted in LocalMachine\TrustedPublisher should execute under AllSigned, regardless of whether the certificate is also in CurrentUser\TrustedPublisher.
Actual behavior
PowerShell only checks CurrentUser\TrustedPublisher. The certificate in LocalMachine\TrustedPublisher is ignored. In non-interactive mode, AuthenticodePrompt() returns DoNotRun immediately, and the script is blocked with:
AuthorizationManager check failed.
---> PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.
Relevant source code
In src/System.Management.Automation/security/SecurityManager.cs:
IsTrustedPublisher() — Opens new X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser) only. Never opens StoreLocation.LocalMachine.
AuthenticodePrompt() — When host == null || host.UI == null, returns RunPromptDecision.DoNotRun with no fallback to check additional stores.
Proposed technical implementation details
- In
IsTrustedPublisher(), after checking CurrentUser\TrustedPublisher, also check LocalMachine\TrustedPublisher if the certificate was not found.
- Preserve deny precedence: if the certificate is in
CurrentUser\Disallowed or LocalMachine\Disallowed (Untrusted stores), it should remain blocked regardless of its presence in LocalMachine\TrustedPublisher.
- The check order should be: CU\Disallowed → LM\Disallowed → CU\TrustedPublisher → LM\TrustedPublisher.
This is orthogonal to #21550 and PR #25824. Those address what identity material should be trusted (OID/EKU identity for Azure Trusted Signing cert rotation). This issue addresses which Windows certificate stores PowerShell consults when deciding whether a valid Authenticode signer is trusted. Even with OID support from PR #25824, PowerShell will still fail enterprise/SYSTEM scenarios if it only consults CurrentUser.
Expected behavior
Actual behavior
The script's signature is rejected. The script does not run.
Error details
Environment data
Name Value
---- -----
PSVersion 7.5.5
PSEdition Core
OS Microsoft Windows 10.0.26200
Platform Win32NT
Visuals
No response
Prerequisites
Steps to reproduce
Summary of the new feature / enhancement
PSAuthorizationManager.IsTrustedPublisher()only checksCurrentUser\TrustedPublisher(StoreLocation.CurrentUser). It does not consultLocalMachine\TrustedPublisher. This causes validly signed scripts to be blocked under GPO-enforced AllSigned when:CurrentUser\TrustedPublisheris not the enterprise-managed store and is typically empty/unpopulated)LocalMachine\TrustedPublisherPowerShell treats the publisher as unknown, calls
AuthenticodePrompt(), and because the host is non-interactive (host == null || host.UI == null), returnsDoNotRun— blocking the script withAuthorizationManager check failed.This bug also exists in Windows PowerShell 5.1
The same
IsTrustedPublisher()code path exists in Windows PowerShell 5.1 (System.Management.Automation.dll). The behavior is identical — onlyCurrentUser\TrustedPublisheris consulted. Since PS 5.1 is in maintenance mode, we understand it is unlikely to receive this fix, but the issue should be documented here as it affects the majority of enterprise Windows systems that still rely on PS 5.1 for automation and VM extension execution.This bug prevents customers from securing their systems
Enterprise security teams deploy AllSigned execution policy via Group Policy specifically to prevent execution of unsigned or untrusted scripts — this is a fundamental security best practice recommended by Microsoft, CIS benchmarks, and DISA STIGs.
However, this bug creates an impossible choice for security-conscious organizations:
There is no workaround that preserves both security and functionality:
CurrentUser\TrustedPublisheris fragile and non-standard — no enterprise tooling (GPO, Intune, SCCM) targets per-user stores for service accounts.LocalMachine\TrustedPublishervia GPO — is the one store PowerShell doesn't check.The net effect is that PowerShell's AllSigned policy is incompatible with non-interactive execution of Microsoft-signed scripts, which undermines customers' ability to both secure their systems and use Azure/Microsoft services.
Real-world impact
This affects any software that ships signed
.ps1scripts and runs them non-interactively under AllSigned:We are seeing this on ~279 enterprise Azure VMs where GPO enforces AllSigned. The scripts are ESRP-signed with valid Authenticode signatures (
Get-AuthenticodeSignaturereportsValid), but PowerShell blocks them because the signer cert is not inCurrentUser\TrustedPublisherfor the SYSTEM account.Steps to reproduce
Prerequisites: Download the attached
Exit0.ps1(a signed Microsoft script that simply callsexit 0).To demonstrate that
LocalMachine\TrustedPublisheris ignored, add the signer cert there and retry:Steps 4-7 prove that
LocalMachine\TrustedPublisheris ignored and onlyCurrentUser\TrustedPublisheris consulted.To reproduce as LocalSystem (the real-world scenario), use
PsExec -sor a scheduled task running as SYSTEM.Expected behavior
A validly signed script whose signer certificate is trusted in
LocalMachine\TrustedPublishershould execute under AllSigned, regardless of whether the certificate is also inCurrentUser\TrustedPublisher.Actual behavior
PowerShell only checks
CurrentUser\TrustedPublisher. The certificate inLocalMachine\TrustedPublisheris ignored. In non-interactive mode,AuthenticodePrompt()returnsDoNotRunimmediately, and the script is blocked with:Relevant source code
In
src/System.Management.Automation/security/SecurityManager.cs:IsTrustedPublisher()— Opensnew X509Store(StoreName.TrustedPublisher, StoreLocation.CurrentUser)only. Never opensStoreLocation.LocalMachine.AuthenticodePrompt()— Whenhost == null || host.UI == null, returnsRunPromptDecision.DoNotRunwith no fallback to check additional stores.Proposed technical implementation details
IsTrustedPublisher(), after checkingCurrentUser\TrustedPublisher, also checkLocalMachine\TrustedPublisherif the certificate was not found.CurrentUser\DisallowedorLocalMachine\Disallowed(Untrusted stores), it should remain blocked regardless of its presence inLocalMachine\TrustedPublisher.Relationship to #21550 / PR #25824
This is orthogonal to #21550 and PR #25824. Those address what identity material should be trusted (OID/EKU identity for Azure Trusted Signing cert rotation). This issue addresses which Windows certificate stores PowerShell consults when deciding whether a valid Authenticode signer is trusted. Even with OID support from PR #25824, PowerShell will still fail enterprise/SYSTEM scenarios if it only consults
CurrentUser.Expected behavior
The script executes.Actual behavior
The script's signature is rejected. The script does not run.Error details
Environment data
Visuals
No response