Execution Policy & Script Security Basics
PowerShell Fundamentals
Chapter 10 · Execution Policy & Script Security Basics
Chapter 7 already flagged this moment: the first time you try to run a local .ps1 file, PowerShell may refuse outright with a message about scripts being disabled on the system. That's execution policy — and the single most important thing to understand about it, stated plainly by Microsoft's own documentation, is also the most counterintuitive: it is not a security boundary. It's a safety rail against running something by accident, not a lock that keeps a determined attacker out.
The Policy Levels
| Policy | What it allows |
|---|---|
| Restricted | No scripts at all — only interactive commands typed directly. The factory default on client Windows. |
| AllSigned | Every script must carry a valid digital signature — even ones you wrote yourself, on your own machine. |
| RemoteSigned | Locally created scripts run freely; scripts that came from the internet must be signed. The default on Windows Server. |
| Unrestricted | Everything runs, but a downloaded script shows a one-time confirmation prompt before executing. |
| Bypass | Nothing is blocked, no warnings shown at all — typically used deliberately for a single automated task, not as a standing setting. |
Get-ExecutionPolicy / Set-ExecutionPolicy & Scope
Multiple scopes can hold a policy at once — MachinePolicy and UserPolicy (set by Group Policy, taking precedence over everything else), then Process, CurrentUser, and LocalMachine in that order. The narrowest scope with a real (non-Undefined) value wins.
A Temporary Bypass, Scoped to One Session
-Scope Process only affects the current PowerShell window — it evaporates the moment that window closes, leaving LocalMachine's own policy completely untouched. This is the right tool for "let this one trusted script run right now" without permanently loosening anything.
Mark of the Web: What "Remote" in RemoteSigned Actually Means
RemoteSigned's distinction between "local" and "downloaded" isn't a guess based on file location — Windows itself tags any file that arrived via a browser, email client, or similar with a hidden NTFS marker called the Mark of the Web (technically a Zone.Identifier alternate data stream). A script you typed and saved yourself never gets this tag; one you downloaded does, which is exactly what RemoteSigned checks for.
powershell.exe -EncodedCommand, or piping text into Invoke-Expression all skip execution policy entirely, none of them counting as "running a script file." Execution policy exists to stop accidental execution — double-clicking an unfamiliar .ps1, or a script quietly shipped inside something else running without you noticing — not to stop someone determined to run code on a machine they already have access to.
A Practical Default
For a personal development machine, RemoteSigned is the sane, commonly recommended setting: your own scripts run without friction, while anything that arrived from the internet still needs either a real signature or a conscious Unblock-File first — a reasonable balance between convenience and the "did I mean to run this" habit this whole chapter is really about.
Get-ExecutionPolicy -List before assuming why — it's easy to fix the wrong scope (loosening LocalMachine when a stricter UserPolicy set by Group Policy is the actual blocker) if you don't first see which scope is genuinely in control.
Hands-On Exercises
Explain why RemoteSigned lets a script you wrote yourself run freely while blocking one you downloaded, even if both files sit in the same folder. What specific mechanism (named in this chapter) is actually responsible for a file counting as "remote"?
Explain why Microsoft describes execution policy as "not a security boundary." Name one concrete way, from this chapter, that someone could run PowerShell code while completely bypassing it.
📄 View solutionYou need to run a single trusted script once without permanently changing your machine's execution policy. Write the command(s) you'd use, and explain why -Scope Process is the right choice here rather than -Scope LocalMachine.
Chapter 10 Quick Reference
- Restricted — no scripts at all (client Windows default); AllSigned — every script needs a signature; RemoteSigned — local scripts free, remote ones need a signature (Windows Server default); Unrestricted — everything runs with a warning on remote scripts; Bypass — nothing blocked
Get-ExecutionPolicy -List— shows every scope; the narrowest defined one winsSet-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass— a temporary, session-only override- Mark of the Web /
Zone.Identifier— the hidden NTFS tag that actually makes a file count as "remote" forRemoteSigned Unblock-File— removes the Mark of the Web from a script you've reviewed and trust- Execution policy is not a security boundary — trivially bypassed via
-EncodedCommand,Invoke-Expression, or pasting directly into the console; it prevents accidental execution only - Practical default:
RemoteSignedfor a personal dev machine - Next chapter: Modules, Aliases & the PowerShell Gallery