Updated: October 2026
A script you wrote yesterday refuses to run on a new laptop, and the error points at something called an execution policy. The quick fix people paste online is one line, and it quietly changes how every script on that machine behaves. Here's what the execution policy in PowerShell does, how its scopes stack, how to fix the "running scripts is disabled" error without opening the whole fleet, and what to use when you need real control over scripts.
What the Execution Policy Does
The execution policy decides whether PowerShell will load configuration files and run scripts, and whether those scripts need a digital signature. It only applies on Windows. On Linux and macOS it's fixed at Unrestricted and can't be changed.
Microsoft is blunt about its limits. The execution policy "isn't a security boundary, it's defense in depth," says the current about_Execution_Policies page on Microsoft Learn (updated August 2026). Its own example: a user who can't run a script can type the script's contents at the prompt instead. The policy exists to stop people running scripts by accident, not to stop someone who wants to.
That framing matters for everything below. Treat the execution policy as a seatbelt for your technicians, not a lock against attackers.
The Seven Policy Values
| Policy | Local script | Downloaded, unsigned script | Where you meet it |
|---|---|---|---|
| Restricted | Blocked | Blocked | Windows client default in Windows PowerShell 5.1 |
| AllSigned | Needs a trusted signature | Blocked | Fleets that sign everything |
| RemoteSigned | Runs | Blocked until signed or unblocked | Windows Server default |
| Unrestricted | Runs | Runs after a warning | Linux and macOS, always |
| Bypass | Runs | Runs, no prompt | Apps that embed PowerShell, one-off runs |
| Default | Resets to the platform default | Undoing a change | |
| Undefined | Clears one scope | Removing a setting |
Restricted still lets you run single commands. It blocks .ps1 files, module script files and PowerShell profiles. If every scope is Undefined, a Windows client falls back to Restricted and a Windows Server falls back to RemoteSigned.
Windows PowerShell 5.1, the one built into Windows, and PowerShell 7 keep separate settings. Changing one doesn't touch the other. PowerShell 7 stores its policy in powershell.config.json, while 5.1 uses the registry.
Scopes and Precedence
You can set a policy at five scopes, and PowerShell uses the highest one that isn't Undefined:
- MachinePolicy - set by Group Policy for the computer. Set-ExecutionPolicy can't change it.
- UserPolicy - set by Group Policy for the user.
- Process - the current session only, held in
$Env:PSExecutionPolicyPreferenceand gone when the window closes. - CurrentUser - the signed-in user, stored under HKCU in 5.1. No admin rights needed.
- LocalMachine - everyone on the computer, stored under HKLM in 5.1. This is the default scope, and it needs an elevated prompt.
Get-ExecutionPolicy -List shows all five at once. Read it top down. If CurrentUser says RemoteSigned and LocalMachine says AllSigned, you get RemoteSigned.
This is why a command can succeed and still change nothing. Set LocalMachine to Restricted while Group Policy says AllSigned, and PowerShell tells you your preference was saved but "overridden by the Group Policy applied to your system."
This January 2026 thread asks how to stop typing -Scope Process at the top of every run. The replies land on the right answers: set CurrentUser once, launch with -ExecutionPolicy for a single script, or sign your scripts.
How to Set the Execution Policy
For one user, no admin rights:
powershellSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
For the whole computer, from an elevated prompt:
powershellSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
For a single script, without changing anything saved:
powershellpowershell.exe -ExecutionPolicy RemoteSigned -File .\script.ps1
Changes take effect immediately. You don't need to restart PowerShell. To clear a scope, set it to Undefined with the same -Scope.
Across a fleet, use Group Policy rather than a script that runs Set-ExecutionPolicy on every machine. The setting is Turn on Script Execution under Administrative Templates, Windows Components, Windows PowerShell, on both the computer and user side. "Allow local scripts and remote signed scripts" maps to RemoteSigned, "Allow only signed scripts" maps to AllSigned, and "Allow all scripts" maps to Unrestricted. Disabling the setting blocks scripts entirely. Computer settings win over user settings.
In Intune, platform scripts have an Enforce script signature check option. Turn it on and the script has to be signed by a trusted publisher. When a script behaves differently under Intune than it does on your desk, compare the policy the agent sees with what Get-ExecutionPolicy -List shows you. More remote checks like this live in our PowerShell commands guide.
Fixing "Running Scripts Is Disabled on This System"
The full error reads "cannot be loaded because running scripts is disabled on this system." It means the effective policy is Restricted, or the script was downloaded and isn't signed. Work through it in order:
- Run
Get-ExecutionPolicy -Listand find the highest scope that isn't Undefined. - If MachinePolicy or UserPolicy is set, Group Policy or Intune owns the answer. Fix it there, because anything you set locally is overridden.
- If the script came from the internet, email or a chat app, Windows marked it as downloaded. Read the script, then run
Unblock-File .\script.ps1on that one file.Get-Item .\script.ps1 -Stream Zone.Identifiershows whether the mark is there. - If the machine is simply on the Restricted default, set CurrentUser to RemoteSigned. That fixes it for that user without touching anyone else.
One catch in step 3: Microsoft notes that files fetched with curl.exe, Invoke-WebRequest or Invoke-RestMethod may not get the downloaded mark at all. So RemoteSigned won't stop a script pulled down that way. That's one more reason not to treat the policy as protection.
On Windows Server Core, some PowerShell 6 setups fail with "AuthorizationManager check failed". The zone check needs the desktop shell, which Server Core doesn't have. Microsoft's workaround is Bypass or AllSigned, which skip the zone check.
Why It Isn't a Security Boundary
Lee Holmes, then on the Windows PowerShell team, called execution policies a user feature back in 2008: "Like seatbelts." Nothing since has changed that. Microsoft's PowerShell security features page lists the execution policy under defense-in-depth features, where a bypass isn't treated as a vulnerability.
The -ExecutionPolicy Bypass flag costs nothing to add, so it turns up in install instructions and fake "fix" prompts alike. This July 2026 thread shows the everyday version: an app telling a user to paste powershell -ExecutionPolicy Bypass -c "irm ... | iex".
The top replies make the useful point. The script was fine that day, but piping a web page straight into PowerShell trusts whatever that server returns tomorrow. No execution policy setting changes that.
What to Use Instead
If the goal is stopping untrusted scripts, Microsoft points to application control:
- App Control for Business (formerly Windows Defender Application Control). When a policy is enforced, PowerShell enters System Lockdown mode. Scripts the policy trusts run in full language mode, and everything else runs in Constrained Language mode. Microsoft classes this pairing as a security feature it services, unlike the execution policy. Our App Control for Business guide covers rolling it out in audit mode first.
- Constrained Language mode. It blocks
Add-Typewith arbitrary C#, most .NET types and COM objects outside a short allow list. Setting it by hand is only for testing. It holds up only when App Control enforces it. - AMSI. Since PowerShell 5.1 on Windows 10, every script block goes to the Antimalware Scan Interface, so tools like Microsoft Defender see the script, however it was launched.
- Script block logging. It records the commands, functions and scripts that ran in the Microsoft-Windows-PowerShell/Operational log, which is what you'll want during an investigation.
AppLocker can also force Constrained Language mode, but Microsoft lists that combination as defense in depth, not a serviced security feature. The same thinking shows up in Smart App Control, which gives unmanaged PCs a lighter version of the same allowlisting idea.
A Sensible Baseline
For a typical business fleet, set RemoteSigned through Group Policy or Intune so nobody can drift away from it locally. Sign the scripts you deploy, so moving to AllSigned later is a small step. Keep Bypass for single runs launched by tools that have their own controls, never as a machine-wide setting. And if you need to know which machines still carry an old Unrestricted setting, Get-ExecutionPolicy -List answers it per device. OpenFrame can run that line as a script across a client's devices and collect the output in one place.
The Short Version
The execution policy in PowerShell stops accidental script runs, not attackers. Check Get-ExecutionPolicy -List before changing anything, fix Group Policy-owned settings at the source, unblock single files rather than loosening the machine, and set RemoteSigned centrally. For real control over which scripts run, use App Control for Business with Constrained Language mode, plus AMSI and script block logging.
If you're running scripts on remote machines, WinRM and PowerShell remoting is the next piece to get right.
Dmytro Koval
Head of Product Engineering
Hi! My name is Dmytro, but everyone calls me Dima. I’m a Software Developer and together with the development team, I help bring Flamingo to life — putting it on its feet from a technical perspective. Originally from Lviv, Ukraine 🇺🇦, but currently based in Spain, where I’ve been enjoying the blend of great weather, culture, and nature. I’m passionate about the mountains and love traveling — exploring new places and cultures really inspires me. These experiences constantly recharge me and give me a fresh perspective, both personally and professionally.
