HackBlue

Tools · Windows security and Event Logs · 17 / 27

PowerShell execution policy explained: why it is not a security boundary

Understand Restricted, RemoteSigned, AllSigned, and Bypass, how scopes combine, and which controls actually stop untrusted scripts.

8 min read · practice only with authorization

What execution policy does

Execution policy decides whether PowerShell will run script files and whether they must be signed. Restricted runs no scripts. RemoteSigned requires a signature on scripts downloaded from the internet, identified by the Mark of the Web. AllSigned requires every script to be signed. Bypass and Unrestricted run everything, with Unrestricted warning on downloaded files.

Scopes stack: MachinePolicy and UserPolicy from Group Policy win over Process, CurrentUser, and LocalMachine. Get-ExecutionPolicy -List shows them all.

Snippet
Get-ExecutionPolicy -List
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Why it is not a boundary

Microsoft documents execution policy as a safety feature to prevent accidental script runs, not a security control. Any user can start powershell -ExecutionPolicy Bypass, pipe a script’s text into PowerShell, or paste commands interactively. None of those are blocked by execution policy.

Attackers routinely add -ep bypass to their commands. Seeing that in a 4688 command line is a useful hunting clue but not proof of malice, because administrators use it too.

Lab: see the limits

Set the CurrentUser policy to AllSigned. Try running an unsigned local script and see it fail. Then run it with powershell -ExecutionPolicy Bypass -File, and again by reading it with Get-Content and piping to Invoke-Expression. Both succeed.

Check the Mark of the Web on a downloaded script with Get-Item -Stream Zone.Identifier, and remove it with Unblock-File, to understand what RemoteSigned actually checks.

Snippet
Set-Content .\hello.ps1 'Write-Output "hello from script"'
Set-ExecutionPolicy AllSigned -Scope CurrentUser -Force
.\hello.ps1                          # blocked
powershell -ExecutionPolicy Bypass -File .\hello.ps1   # runs
Get-Content .\hello.ps1 | Invoke-Expression              # runs
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force

Controls that do enforce

Application control with App Control for Business (WDAC) or AppLocker can enforce Constrained Language Mode for PowerShell, which blocks most of the APIs attackers use. AMSI lets Defender scan script content at runtime. Script block logging records what ran. Those are the layers that matter.

Keep execution policy at RemoteSigned or AllSigned as a guardrail for users, and invest in the enforcing controls.

Diagram

Execution policy versus application control

Which one an attacker can switch off.

Execution policy

Purpose. Prevent accidental script runs.

Bypass. -ExecutionPolicy Bypass, piping, pasting.

Role. Guardrail only.

WDAC or AppLocker with Constrained Language

Purpose. Enforce which code may run.

Bypass. Requires a policy flaw or admin rights.

Role. Real control.

Check yourself

1. What does RemoteSigned require?

2. Why is execution policy not a security boundary?

3. Which control actually restricts what PowerShell code can do?