To allow a PowerShell .ps1 script to run safely on Windows 10, Windows 11, or Windows Server, first inspect every policy scope with Get-ExecutionPolicy -List. If no Group Policy controls the device, use the narrowest justified change: Process for one session, CurrentUser for one user, or Unblock-File for one reviewed download. Do not make Bypass or Unrestricted the default answer.
Get-ExecutionPolicy
Get-ExecutionPolicy -List
Run these commands in the same PowerShell edition that produced the error. Windows PowerShell 5.1 uses powershell.exe; modern PowerShell 7 uses pwsh.exe. Their local settings are stored separately, and changing one does not necessarily change the other.
Choose the narrowest change that solves the real problem
| Situation | Appropriate starting point | Persistence |
|---|---|---|
| Run a trusted script during one controlled session | RemoteSigned at Process scope |
Ends with that PowerShell process |
| Run reviewed local scripts for one user | RemoteSigned at CurrentUser scope |
Persists for that user |
| Run one reviewed file marked as downloaded | Inspect signature and origin, then unblock only that file | Removes that file's zone marker |
| Require every script, including local scripts, to be signed | Organization-managed AllSigned |
Depends on policy scope |
| A domain or device policy controls execution | Change the owning Group Policy, not a local scope | Organization-managed |
| Prevent unapproved code rather than discourage accidental execution | App Control for Business, or an existing AppLocker policy | Enforced by application-control policy |
Every Set-ExecutionPolicy, Unblock-File, Group Policy, signing, application-control, and logging change modifies system or file state. Obtain the required approval, record the previous state, and verify the effective result.
PowerShell's execution policy documentation is explicit: execution policy is defense in depth, not a security boundary. It can prevent accidental script execution and enforce signing expectations, but a user permitted to run commands can use other ways to execute equivalent instructions. Use Windows application control when the requirement is enforceable allowlisting.
Understand scope and precedence before changing anything
PowerShell evaluates execution policy scopes in this order, from highest to lowest precedence:
MachinePolicy— Group Policy for the computer.UserPolicy— Group Policy for the current user.Process— the current PowerShell process and its child processes.CurrentUser— the current Windows user.LocalMachine— every user on the computer.
Get-ExecutionPolicy shows the effective policy. Get-ExecutionPolicy -List shows the values participating in the decision:
Get-ExecutionPolicy -List | Format-Table -AutoSize
If MachinePolicy or UserPolicy is defined, it outranks every locally configured scope. A Set-ExecutionPolicy command can update a lower scope successfully without changing the effective result. A session-level setting cannot override Group Policy.
LocalMachine is the default scope when -Scope is omitted, and modifying it requires an elevated PowerShell session. Always specify the scope so the blast radius is visible in the command and its change record.
Allow scripts for only the current session
For a reviewed script needed during one controlled session, Process scope is the narrowest policy change:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -WhatIf
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
Get-ExecutionPolicy -List
The first command previews the action. The second is state-changing, but its value is stored only for the current PowerShell process. It disappears when that process and its child processes close. It does not override MachinePolicy or UserPolicy.
Run the script with an explicit relative or absolute path:
.\Maintenance.ps1
Using RemoteSigned here still requires a trusted-publisher signature for files Windows identifies as downloaded from the internet, unless that specific file is reviewed and unblocked.
Do not substitute this pattern with powershell.exe -ExecutionPolicy Bypass or pwsh.exe -ExecutionPolicy Bypass as routine advice. Bypass blocks nothing and produces no warnings or prompts. If an approved automation product requires it, that product must provide the surrounding trust and application-control model.
Allow reviewed scripts for the current user
When one user regularly runs locally created scripts and no Group Policy owns the setting, preview and set RemoteSigned at CurrentUser:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -WhatIf
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Get-ExecutionPolicy -List
Get-ExecutionPolicy
This is a persistent state change for that user. It does not require changing every user's policy and normally does not require elevation. The change takes effect immediately; restarting PowerShell is not required.
RemoteSigned permits unsigned scripts created locally. Scripts and configuration files marked as downloaded from the internet must be signed by a trusted publisher, unless their internet-origin marker is deliberately removed. It does not prove that an unsigned local script is safe.
Only use LocalMachine when policy must apply to every user and the device owner has approved that scope:
Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned -WhatIf
The actual LocalMachine change requires an elevated session. Do not proceed merely because -WhatIf succeeded; confirm Group Policy ownership and the impact on services, scheduled tasks, and other users first.
Inspect a downloaded PS1 before unblocking it
Under RemoteSigned, a file can be blocked because Windows attached a Zone.Identifier alternate data stream, commonly called Mark of the Web. Inspect the file before removing that metadata:
$scriptPath = '.\Maintenance.ps1'
Get-Item -LiteralPath $scriptPath -Stream Zone.Identifier -ErrorAction SilentlyContinue
Get-AuthenticodeSignature -LiteralPath $scriptPath |
Format-List Status, StatusMessage, SignerCertificate, TimeStamperCertificate
Get-FileHash -LiteralPath $scriptPath -Algorithm SHA256
A SHA-256 value is useful only when you compare it with an expected value obtained through a separate trusted channel. A valid signature identifies the signer and detects post-signing changes; it does not guarantee that the script's behavior is benign. Review the code, dependencies, download source, expected hash, and requested privileges.
If the exact file is approved and the internet-origin restriction is the only problem, preview and apply the file-level change:
Unblock-File -LiteralPath '.\Maintenance.ps1' -WhatIf
Unblock-File -LiteralPath '.\Maintenance.ps1'
Unblock-File is state-changing. On Windows it removes the Zone.Identifier stream; it does not change the execution policy and does not make the script trustworthy. Microsoft's Unblock-File reference warns against unblocking groups of files before verifying that all are safe.
Avoid recursive commands such as unblocking an entire Downloads directory or extracted repository. Review the exact artifact. When a ZIP or installer is involved, also verify which extracted files inherited origin metadata rather than assuming all or none did.
Some Windows systems classify UNC network paths as internet paths. An unsigned script on a file share can therefore be blocked under RemoteSigned even when the share is internal. Do not weaken policy to work around that ambiguity. Confirm Windows zone classification, use a trusted signing process, or deploy through an organization-managed path.
Know what each execution policy actually permits
Restricted
Individual PowerShell commands can run, but script files, module scripts, profiles, and formatting or configuration script files do not. This explains why an interactive command can work while the equivalent .ps1 file fails.
RemoteSigned
Local unsigned scripts can run. Internet-origin scripts require a trusted-publisher signature unless the file has been reviewed and unblocked. This is a practical safety policy, not an allowlist.
AllSigned
Every script and configuration file must be signed by a trusted publisher, including locally authored files. Users can still be prompted to classify an unfamiliar publisher. A signed malicious script remains malicious.
Unrestricted and Bypass
Unrestricted permits unsigned scripts and warns for files outside the local intranet zone. Bypass blocks nothing and shows no warning. Neither should be a default troubleshooting fix. A controlled host product may use Bypass only when its own security model and application control supply the missing boundary.
Undefined
Undefined removes the value from one local scope, allowing the next scope in precedence order to determine the effective policy. It does not mean unrestricted execution. When all scopes are undefined, current Microsoft documentation describes the effective fallback as Restricted on Windows clients and RemoteSigned on Windows Server.
Remove a local policy cleanly
To remove a previously assigned current-user preference, set that scope to Undefined:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Undefined -WhatIf
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Undefined
Get-ExecutionPolicy -List
Get-ExecutionPolicy
This is a persistent state change. It does not restore a hard-coded value; it exposes the policy selected by the next defined scope. Record both the scope list and effective result after removal.
Use the same pattern for Process or LocalMachine only when that is the setting you own. MachinePolicy and UserPolicy cannot be removed with Set-ExecutionPolicy; they belong to Group Policy.
Respect Windows PowerShell and PowerShell 7 boundaries
Windows PowerShell 5.1 and PowerShell 7 are separate products on the same Windows machine:
- Windows PowerShell runs as
powershell.exeand uses Windows PowerShell policy locations. - PowerShell 7 runs as
pwsh.exeand uses PowerShell Core configuration locations. - Their
CurrentUserandLocalMachinesettings are managed separately. - PowerShell 7 ships its own Group Policy templates in
$PSHOME. - PowerShell 7 policy settings can optionally be configured to use a corresponding Windows PowerShell policy value.
Open the executable that fails and run Get-ExecutionPolicy -List there. Do not diagnose pwsh.exe by checking only powershell.exe.
Execution-policy enforcement is Windows-specific. On non-Windows systems, Get-ExecutionPolicy reports Unrestricted, but Microsoft says behavior effectively matches Bypass because Windows Security Zones are unavailable. Set-ExecutionPolicy is present but reports that the operation is unsupported. Use Unix file permissions, ownership, package trust, sudo policy, and platform application controls instead.
Let Group Policy owners make organization-wide changes
The Turn on Script Execution setting can define execution policy for computers or users. Computer Configuration takes precedence over User Configuration, and Group Policy overrides local PowerShell scopes.
Windows PowerShell policy is normally under:
Administrative Templates\Windows Components\Windows PowerShell
PowerShell 7's installed administrative templates expose policy under the PowerShell Core paths. Microsoft documents the templates and their installation in about_Group_Policy_Settings.
If MachinePolicy or UserPolicy is defined, do not hunt for a local bypass. Capture Get-ExecutionPolicy -List, the failing executable and version, the script origin, and the exact error. Send that evidence to the Group Policy or endpoint-management owner. A policy exception should identify the script, publisher, device group, purpose, and review period.
Treat code signing as identity and integrity, not safety
Signing supports AllSigned and internet-origin execution under RemoteSigned, but it requires a maintained trust process:
- issue a certificate valid for code signing from a certification authority trusted by target devices;
- protect the private key, preferably using controlled signing infrastructure;
- verify publisher trust and certificate chain on target devices;
- timestamp signatures so validation can establish that signing occurred while the certificate was valid;
- plan renewal, revocation, incident response, and re-signing before certificates expire;
- understand that editing a signed script invalidates its signature.
Microsoft's about_Signing guidance notes that a signature remains valid until the signing certificate expires, or longer when a timestamp service verifies it was signed while the certificate was valid. Renewal does not repair a compromised old private key. If a signing key is exposed, stop trusting new artifacts from it, invoke the certificate incident process, revoke where applicable, and redistribute clean signed artifacts.
Get-AuthenticodeSignature reports signature state, but a valid signature does not review code or dependencies. A trusted publisher can make a mistake or sign harmful content. Combine signing with source review, protected build and release systems, least privilege, and enforceable application control.
Use application control when policy must be enforced
Execution policy is designed to reduce accidental execution. For system-wide code control, Microsoft identifies App Control for Business as the preferred Windows application-control system. PowerShell detects an enforced system policy and applies System Lockdown behavior, including language-mode restrictions, to scripts, modules, and script blocks.
AppLocker remains supported but is a legacy application-control system with different security-servicing status. Do not deploy either control from a generic script-running guide. Design and test rules in audit mode, include operating-system and management dependencies, define publisher or file rules carefully, and maintain a recovery path. See Microsoft's PowerShell security features and organization-specific App Control guidance.
If App Control or AppLocker blocks a script, changing execution policy will not override that decision. Collect the corresponding application-control event, policy identity, file hash, signer, and requested path, then work with the policy owner.
Diagnose the exact error instead of lowering policy
“Running scripts is disabled on this system”
The effective policy commonly prevents script files. Run:
$PSVersionTable.PSEdition
$PSVersionTable.PSVersion
Get-ExecutionPolicy
Get-ExecutionPolicy -List
If Group Policy is defined, stop at the policy owner. Otherwise choose Process or CurrentUser only after the script and need are approved.
“The file is not digitally signed”
This can mean AllSigned applies, or RemoteSigned identified internet-origin metadata. Inspect Get-AuthenticodeSignature and Zone.Identifier. Prefer a valid trusted-publisher signature for managed scripts. Unblock only a reviewed file when removing its origin marker is the approved choice.
“AuthorizationManager check failed”
Capture the full exception, PowerShell edition, OS edition, policy list, file path, and origin. Microsoft documents zone-check limitations on some Server Core and Nano Server scenarios, but the same text can have other causes. Do not jump directly to Bypass from the generic message.
A local change succeeds but the effective policy does not change
Compare all scopes. A higher-precedence Group Policy, process value, or current-user value is winning. Remove only the local value you own with Undefined; do not edit policy registry locations directly.
The script runs in one shell but fails in another
Compare powershell.exe with pwsh.exe, 32-bit with 64-bit launch context when relevant, interactive user with service account, and local path with UNC path. Also check whether the task host applies App Control, AppLocker, or constrained language.
For command invocation mechanics after policy is resolved, see how to run a PowerShell command.
Log script execution without collecting secrets blindly
Script Block Logging records processed commands, script blocks, functions, and scripts. Event ID 4104 appears in Microsoft-Windows-PowerShell/Operational for Windows PowerShell and PowerShellCore/Operational for PowerShell 7. Enabling the policy is a state-changing administrative action and can substantially increase event volume.
Read a bounded recent window without modifying policy:
$start = (Get-Date).AddMinutes(-30)
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-PowerShell/Operational'
Id = 4104
StartTime = $start
} -MaxEvents 100 |
Select-Object TimeCreated, Id, MachineName, Message
For PowerShell 7, substitute PowerShellCore/Operational. See the Windows Event Log command guide for safe filtering and EVTX preservation.
Script content can contain credentials, tokens, customer data, and sensitive paths. Define access controls, retention, forwarding, and deletion around that risk before enabling broad logging. Invocation logging creates still more events and should not be enabled without capacity planning.
Microsoft's PowerShell logging guidance for Windows recommends Protected Event Logging when Script Block Logging is used beyond short diagnostics. It encrypts participating event content with a deployed public encryption certificate; the private key stays in a more secure location for authorized decryption. Certificate deployment, key custody, decryption availability, collector behavior, retention, and incident access must be tested before rollout. Encryption does not replace minimization: scripts should not embed secrets in the first place.
Centralize approved PowerShell evidence carefully
Local operational logs can rotate or disappear with a host. A Windows-capable collector can forward approved PowerShell event channels to a central destination, but its parser and field mapping determine what becomes searchable. Validate event ID, channel, computer, timestamp, message, and any structured fields with a non-sensitive test script before relying on a filter.
Fluxtail log management is a paid, self-service destination with Starter and Pro plans. After a separately configured Windows-capable collector sends logs through a documented receiver, Fluxtail provides named streams, Live Tail, and search filters for the fields actually delivered. Fluxtail does not set Windows execution policy or supply the Windows collector in this workflow.
Fluxtail's built-in AI chat and hosted MCP endpoint are separate investigation interfaces. Hosted MCP uses account-bound OAuth with PKCE. Its operator changes are proposed first and require a short-lived confirmation before application. Keep the original Windows event record as evidence, scope agent queries to an approved stream and time window, and verify conclusions against the raw event.
If centralized PowerShell log review fits the operating model, create a Fluxtail account, configure a supported receiver and collector, and confirm one non-sensitive 4104 test event end to end.
Safe PowerShell script checklist
- Run
Get-ExecutionPolicy -Listin the exact PowerShell edition that failed. - Treat execution policy as defense in depth, not an application-control boundary.
- Let
MachinePolicyandUserPolicyowners make Group Policy changes. - Prefer
ProcessoverCurrentUser, andCurrentUseroverLocalMachine, when the narrower scope meets the requirement. - Inspect code, source, hash, signature, privileges, and
Zone.Identifierbefore unblocking one file. - Do not normalize
Bypass,Unrestricted, recursive unblocking, or direct policy-registry edits. - Use
Undefinedto remove a local scope, then verify the next effective value. - Manage signing certificates, timestamps, publisher trust, renewal, and compromise response as one system.
- Use App Control for Business when the requirement is enforceable application control.
- Protect 4104 content with least access, deliberate retention, and Protected Event Logging where appropriate.
- Verify collector mappings and AI or agent conclusions against the original event evidence.