Skip to content

PowerShell Execution Policy

How PowerShell execution policies work, including the six policy levels (Restricted, RemoteSigned, AllSigned, etc.), how to check and set policies, and bypass or unblock scripts safely.

A PowerShell execution policy is a safety control that determines the conditions under which PowerShell loads configuration profiles and executes script files. Execution policies are designed to prevent administrators from unintentionally running untrusted scripts; they are administrative guardrails rather than strict security boundaries, as users can bypass them through command-line parameters or process-level switches.

Execution Policy Levels

PowerShell defines six distinct execution policy levels that control how local and remote scripts are handled:

Policy Level Scripts Allowed Signed Requirement Downloaded File Handling
Restricted No scripts N/A Blocks all .ps1 files; allows interactive commands only (Default on Windows client editions).
AllSigned Yes Yes (All scripts) Every script (local or remote) must be digitally signed by a trusted publisher.
RemoteSigned Yes Remote only Local scripts run freely; scripts downloaded from the internet must be signed (Default on Windows Server).
Unrestricted Yes No Runs all scripts; displays an interactive warning prompt before running downloaded files.
Bypass Yes No Nothing is blocked; no warning prompts or signatures required.
Undefined Inherited Inherited No explicit policy set at the current scope; falls back to lower-precedence scopes or defaults.
check-execution-policy.ps1powershell
$effectivePolicy = Get-ExecutionPolicy

Write-Output "Effective Execution Policy: $effectivePolicy"
Outputplaintext
Effective Execution Policy: RemoteSigned

How PowerShell Determines "Downloaded"

A file is considered "downloaded from the internet" based on its Zone.Identifier alternate data stream (also known as the Mark of the Web, or MotW), which Windows attaches automatically to files saved by a browser or email client.

Consolepowershell
Get-Item -Path "C:\Scripts\tool.ps1" -Stream Zone.Identifier
Outputplaintext
FileName: C:\Scripts\tool.ps1
Stream                   Length
------                   ------
Zone.Identifier             26

Under a RemoteSigned execution policy, PowerShell checks for this stream. If present and the file lacks a valid Authenticode digital signature, PowerShell halts execution with an unauthorized access error.

File C:\Scripts\Deploy.ps1 cannot be loaded. The file C:\Scripts\Deploy.ps1 is not 
digitally signed. You cannot run this script on the current system.

Scopes and Evaluation Precedence

PowerShell determines the effective execution policy by evaluating five hierarchical scopes. The policy configured at the highest-precedence scope overrides all scopes below it.

list-policy-scopes.ps1powershell
Get-ExecutionPolicy -List
Outputplaintext
        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process          Bypass
  CurrentUser    RemoteSigned
 LocalMachine      Restricted

Precedence Hierarchy (Highest to Lowest)

  1. MachinePolicy: Set via Active Directory Group Policy (Computer Configuration). Overrides all other settings; stored in registry under HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell.
  2. UserPolicy: Set via Active Directory Group Policy (User Configuration). Overrides local machine configurations; stored in HKCU:\SOFTWARE\Policies\Microsoft\Windows\PowerShell.
  3. Process: Scoped only to the current PowerShell process instance ($env:PSExecutionPolicyPreference). Reverts to default once the session closes.
  4. CurrentUser: Applied to the logged-in user profile; stored in HKCU:\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. Requires no administrative rights to change.
  5. LocalMachine: Applied globally to all users on the computer; stored in HKLM:\Software\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. Requires an elevated administrator session to modify.

Setting Execution Policy with Set-ExecutionPolicy

Consolepowershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

where:

  • -ExecutionPolicy is the policy level to apply.
  • -Scope is the scope to apply it at (defaults to LocalMachine if omitted, which requires admin rights).

Setting Policy for a Single Session Only

Consolepowershell
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

Complete User Scope Example

set-user-policy.ps1powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force

Get-ExecutionPolicy -Scope CurrentUser
Outputplaintext
RemoteSigned

Bypassing Execution Policy

Rather than changing the persistent policy, you can override it for a single script invocation or session.

Command-Line Invocation Bypass

Consolepowershell
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\deploy.ps1"

where:

  • -NoProfile skips loading PowerShell profile files, speeding up startup and avoiding interference from custom user settings.
  • -ExecutionPolicy Bypass overrides the system execution policy strictly for the lifetime of the spawned process, without modifying any stored setting.
  • -File specifies the target script to execute.

In-Session Process Elevation

temporary-bypass.ps1powershell
$previousPolicy = Get-ExecutionPolicy -Scope Process

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
Write-Output "Process execution policy set to: $(Get-ExecutionPolicy)"

& ".\Deploy.ps1"

Set-ExecutionPolicy -ExecutionPolicy $previousPolicy -Scope Process -Force
Write-Output "Process execution policy reverted to: $(Get-ExecutionPolicy)"
Outputplaintext
Process execution policy set to: Bypass
Deployment complete.
Process execution policy reverted to: RemoteSigned

Unblocking Downloaded Scripts with Unblock-File

Rather than changing the execution policy, a more targeted fix for a specific downloaded script is to remove its "downloaded from the internet" flag using Unblock-File. This removes the Zone.Identifier stream, marking the script as a trusted local file.

unblock-script.ps1powershell
Get-Item -Path ".\Deploy.ps1" -Stream "Zone.Identifier" -ErrorAction SilentlyContinue

Unblock-File -Path ".\Deploy.ps1" -Verbose

Get-Item -Path ".\Deploy.ps1" -Stream "Zone.Identifier" -ErrorAction SilentlyContinue
Outputplaintext
FileName                   Stream                   Length
--------                   ------                   ------
C:\Scripts\Deploy.ps1      Zone.Identifier              68

VERBOSE: Performing the operation "Unblock-File" on target "C:\Scripts\Deploy.ps1".

Unblocking Multiple Files at Once

Consolepowershell
Get-ChildItem -Path "C:\Scripts" -Filter "*.ps1" -Recurse | Unblock-File

Practical Usage

Preparing a Downloaded Script Toolkit for Use

A common onboarding task is safely unblocking a set of downloaded automation scripts before distributing them to a team, verifying policy settings along the way.

prepare-script-toolkit.ps1powershell
param([string]$ToolkitPath)

Write-Output "Current execution policy (effective): $(Get-ExecutionPolicy)"

$blockedFiles = Get-ChildItem -Path $ToolkitPath -Filter "*.ps1" -Recurse |
    Where-Object { Get-Item -Path $_.FullName -Stream Zone.Identifier -ErrorAction SilentlyContinue }

if ($blockedFiles) {
    Write-Output "Unblocking $($blockedFiles.Count) script(s)..."
    $blockedFiles | Unblock-File
} else {
    Write-Output "No blocked scripts found."
}

Write-Output "Toolkit ready for use."
Outputplaintext
Current execution policy (effective): RemoteSigned
Unblocking 4 script(s)...
Toolkit ready for use.
Navigation