Skip to main content
Microsoftbeginner

"running scripts is disabled on this system" - PowerShell Fix

Fix the "cannot be loaded because running scripts is disabled on this system" error in PowerShell. Learn the safest execution policy scope to change, how to unblock downloaded scripts, and how to verify the fix.

6 min readUpdated August 2026

Trying to run a PowerShell script and getting "cannot be loaded because running scripts is disabled on this system"? Here is the exact error, why it happens, and the narrowest fix that actually solves it.

The Error

.\deploy.ps1 : File C:\Users\sean\deploy.ps1 cannot be loaded because running
scripts is disabled on this system. For more information, see
about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\deploy.ps1
+ ~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

PowerShell 7 prints the same sentence in a more compact form, without the CategoryInfo block. The FullyQualifiedErrorId : UnauthorizedAccess line is the giveaway that this is an execution policy refusal and not a file permissions problem.


Quick Fix

Open PowerShell and run:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

Answer Y at the confirmation prompt. This does not need an administrator prompt. Now run your script again.


Why This Happens

PowerShell's execution policy decides whether script files are allowed to run at all. On Windows client editions - Windows 10 and Windows 11 - the default is Restricted, which permits interactive commands but blocks every .ps1 file. Windows Server editions default to RemoteSigned instead, which is why the same script runs fine on a server and fails on your laptop.

Nothing about your script triggers this. PowerShell refuses before it parses the file, so a one-line script and a thousand-line script fail identically.

The policy is evaluated across five scopes, in this order of precedence:

  1. MachinePolicy - set by Group Policy, machine-wide
  2. UserPolicy - set by Group Policy, per user
  3. Process - this PowerShell process only, gone when it closes
  4. CurrentUser - your account, stored in your registry hive
  5. LocalMachine - all users, requires administrator

The first scope with a value other than Undefined wins. That is why Get-ExecutionPolicy -List is more useful than the bare Get-ExecutionPolicy: it shows you which scope is making the decision.


Fixes, Narrowest First

1. Run one script, change nothing

If you only need this script to run once, override the policy for a single process:

powershell -ExecutionPolicy Bypass -File .\deploy.ps1

Or in PowerShell 7:

pwsh -ExecutionPolicy Bypass -File .\deploy.ps1

The override lives and dies with that process. This is the right choice inside CI pipelines and scheduled tasks, where changing machine state would be a side effect nobody asked for.

2. Allow scripts for this session only

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

Useful when you are about to run several scripts in a row while troubleshooting. Close the window and the setting is gone.

3. Allow scripts for your account (the usual answer)

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

RemoteSigned is the recommended landing spot. Scripts you write locally run without ceremony; scripts that arrived from the internet still require a valid signature or an explicit unblock. You keep a meaningful check on the files most likely to be hostile and lose the friction on the files you wrote yourself.

4. Unblock a downloaded script

If you set RemoteSigned and a specific script still refuses to run, it carries the Mark of the Web - an alternate data stream Windows attaches to files that came from a browser, an email client, or an extracted archive.

Review the script's contents first, then:

Unblock-File -Path .\deploy.ps1

To unblock a whole folder you have already vetted:

Get-ChildItem -Path .\scripts -Filter *.ps1 -Recurse | Unblock-File

Do not make this a reflex. The mark exists precisely so that a script downloaded five minutes ago gets a second of your attention.


Advertisement

What Not to Do

# Don't do this
Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy Bypass

Two problems. It requires elevation, so you are solving a per-user annoyance with a machine-wide change. And Bypass disables the checks entirely and permanently, for every account on the computer, including any future one.

Unrestricted is only marginally better: it runs everything but prompts on internet-sourced files, which trains people to click through the prompt.

It is worth being clear about what execution policy is and is not. Microsoft's own documentation states it is not a security boundary. Anyone determined to run blocked code can read the file and evaluate it directly:

Get-Content .\deploy.ps1 | Invoke-Expression

That is not a reason to disable the policy - it is a reason not to treat it as protection you can trade away casually. The policy's real value is preventing an accidental double-click from executing something, and the narrowest scope preserves that for everyone else on the machine.


Verify the Fix

Get-ExecutionPolicy -List

Expected output after fix 3:

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser    RemoteSigned
 LocalMachine       Undefined

Then confirm a script actually runs:

Write-Output 'Set-Content test' > .\test.ps1
.\test.ps1
Remove-Item .\test.ps1

When Group Policy Is Overriding You

If Set-ExecutionPolicy appears to succeed but nothing changes, you will usually see this warning:

Windows PowerShell updated your execution policy successfully, but the setting is
overridden by a policy defined at a more specific scope.

Check the list:

Get-ExecutionPolicy -List

A value at MachinePolicy or UserPolicy means Group Policy is in charge and no local command will beat it. This is deliberate on managed and domain-joined machines. The path forward is a request to whoever administers the policy - located at Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on Script Execution - not a workaround. Note that the Process-scope override in fix 1 also loses to Group Policy, so a -ExecutionPolicy Bypass launch will not rescue you here either.

On Linux and macOS, PowerShell's execution policy is Unrestricted and cannot be changed, so this error is Windows-only.


Prevention

  • Set RemoteSigned at CurrentUser scope once on each machine you work on and forget about it.
  • In pipelines and scheduled tasks, pass -ExecutionPolicy Bypass on the command line rather than changing machine state.
  • Keep scripts in a local repository directory rather than running them out of Downloads, which sidesteps the Mark of the Web entirely.
  • For scripts distributed across a team, sign them with a code-signing certificate. RemoteSigned then accepts them everywhere with no per-machine change at all.

If the failing command is npm, yarn, pnpm or tsc, you may see the same message naming a shim such as npm.ps1. That is this error, and the CurrentUser + RemoteSigned fix resolves it. If instead PowerShell says The term 'npm' is not recognized as the name of a cmdlet, that is a different problem - a PATH issue rather than an execution policy one.


Summary

  1. Most cases: Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
  2. One-off or automation: powershell -ExecutionPolicy Bypass -File .\script.ps1
  3. Still blocked: Unblock-File -Path .\script.ps1 after reviewing the file
  4. Verify: Get-ExecutionPolicy -List

Frequently Asked Questions

Find answers to common questions

It means PowerShell's execution policy is set to Restricted, which blocks all script files (.ps1) from running. This is the default on Windows client editions. It is not a sign that your script is broken or that anything is infected - PowerShell refused to start the file before reading a single line of it.

Run 'Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned'. The CurrentUser scope writes to your own registry hive, so it does not require an elevated prompt and does not affect other accounts on the machine.

RemoteSigned. It allows scripts you wrote locally to run, while still blocking scripts downloaded from the internet unless they are signed or you explicitly unblock them. Avoid Unrestricted, and never set Bypass at the LocalMachine scope.

Run 'powershell -ExecutionPolicy Bypass -File .\yourscript.ps1' from cmd or PowerShell. The override applies only to that one process and disappears when it exits, leaving the machine's policy untouched.

The file is probably marked as downloaded from the internet. Windows adds a Mark of the Web (a Zone.Identifier alternate data stream) to files from a browser or an email attachment. Run 'Unblock-File -Path .\yourscript.ps1' after you have reviewed the script's contents.

Group Policy is enforcing an execution policy at the MachinePolicy or UserPolicy scope, which outranks anything you set locally. Run 'Get-ExecutionPolicy -List' to see which scope wins. Only a domain administrator can change a policy-set value.

Microsoft is explicit that execution policy is not a security boundary - it stops users from running scripts accidentally, not a determined attacker, who can simply pipe a file's contents to Invoke-Expression. The real risk is habit: leaving Bypass set machine-wide removes a useful speed bump for everyone who uses the computer.

Run 'Get-ExecutionPolicy -List' to see the value at every scope, or 'Get-ExecutionPolicy' for the single effective value. The -List form is more useful because it shows which scope is actually deciding the outcome.

Yes. Tools installed through Node.js ship .ps1 shims, so 'npm.ps1 cannot be loaded because running scripts is disabled on this system' is the same error wearing a different filename. Setting RemoteSigned for CurrentUser fixes it.

Run 'Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Undefined'. Clearing the scope makes PowerShell fall back to the next scope in precedence, which returns you to the machine default.