PowerShell has become one of the most ubiquitous scripting and automation platforms on Windows. Over 300,000 IT professionals now use PowerShell, according to various surveys. Its flexibility makes it the perfect choice for DevOps automation.
However, many encounter a nasty error when first attempting to run PowerShell scripts:
"File C:\scripts\myscript.ps1 cannot be loaded because running scripts is disabled on this system."
This error occurs due to PowerShell‘s default execution policy that restricts running unsigned code and scripts. In this comprehensive guide, you‘ll learn how PowerShell execution policies work and how to confidently resolve script errors.
The Critical Importance of PowerShell Security
With great scripting power comes increased responsibility. Allowing arbitrary PowerShell code execution exposes massive risk. One miswritten script can destroy datasets or corrupt business critical systems.
Malicious PowerShell-based attacks are also on the rise. Attackers utilize obfuscated scripts in social engineering campaigns to infiltrate systems and exfiltrate data. Security researchers have seen over a 1000% increase in PowerShell malware over the past years.
Therefore, PowerShell script signing and execution policies provide the front line of security and prevent catastrophe. Understanding these protections is imperative for any Windows-based IT admin or full-stack engineer.
What are PowerShell Execution Policies?
Execution policies determine what kind of PowerShell scripts and commands can be invoked. Their goal is mitigating risk from unauthorized code execution.
Here are the primary execution policies available:
Policy | Description |
---|---|
Restricted | Default policy, prevents running all scripts |
AllSigned | Scripts must be signed by trusted publisher to run |
RemoteSigned | Downloaded scripts must be signed but local unsigned scripts allowed |
Unrestricted | Runs all scripts without any restrictions |
Bypass | Bypasses execution policy check for the session |
By default, PowerShell ships with the Restricted policy in client Windows SKUs like desktop OSs. Server OSs often utilize the more flexible RemoteSigned policy.
Each increase in permission leads to higher risk if malicious scripts run. But higher restrictions inhibit automation capabilities. There is always a balance between security and productivity at scale.
Security Implications of Execution Policy Choices
Choosing the right execution policy depends on your risk appetite and automation needs:
- Restricted offers maximum safety for high-security environments like payment processors or medical devices. But makes scripting impossible.
- RemoteSigned strikes a good balance for some server environments, requiring signatures on downloaded scripts while allowing freedom with in-house code.
- Unrestricted unleashes full scripting potential but opens the door for malware and malicious activities. Recommended only for developer sandboxes.
- Bypass gives temporary reprieve from policy errors, but should never be used permanently as disables critical protections.
Overall the RemoteSigned policy makes a sensible choice for general server infrastructure, assuming signed in-house scripts. Security-sensitive client machines should stick with Restricted outside of managed environments. Let‘s explore now how to configure these policies.
Viewing Your Current PowerShell Execution Policy
The first step is understanding your current execution policy context. Run the Get-ExecutionPolicy
cmdlet to check the current system-wide policy:
PS C:\> Get-ExecutionPolicy
Restricted
This shows that the policy is Restricted, leading to script failures.
We can also view execution policy status across different scope levels:
PS C:\> Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine RemoteSigned
This PowerShell instance has inherited the RemoteSigned policy from the local machine scope. User and process scope policies are undefined.
Setting PowerShell Execution Policy
To allow successful script execution, you need to set an execution policy that authorizes running unsigned or signed scripts properly.
The most common choice is RemoteSigned which blocks unsigned remote scripts but allows local unsigned scripts to provide flexibility:
PS C:\> Set-ExecutionPolicy RemoteSigned
PowerShell will prompt for confirmation before changing the policy. Specify the -Force flag to force change without prompting:
Set-ExecutionPolicy RemoteSigned -Force
Targeting Specific Execution Policy Scopes
By default Set-ExecutionPolicy
modifies the policy at the LocalMachine level, requiring admin permissions.
You can apply execution policies selectively at different scope levels:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Scope Options:
- MachinePolicy – Default for all users
- UserPolicy – Only the current user
- Process – Applies to current session only
- CurrentUser – Sets default for current user
- LocalMachine – Requires admin permissions
This allows for fine-grained policy tuning depending on context. For example, full access for administrators but restricted use for standard users.
Bypassing Execution Policy
An alternative to permanently changing system policy is temporary bypassing for a session or script invocation:
powershell -ExecutionPolicy ByPass -File .\myscript.ps1
While convenient, this method opens significant security holes as the script has no protections. It also needs to be specified every time you run scripts.
Execution Policy Precedence Hierarchy
In complex environments with different policy scopes set, the following precedence order determines what policy takes effect:
- Group Policy / AD Domain Policy
- User Policy
- Machine Policy
- Local Machine Scope Policy
- Current User Scope Policy
- Process Scope Policy
So for example, if both LocalMachine and CurrentUser policies differ, the LocalMachine policy wins. Understand this order when troubleshooting unexpected script outcomes in layered policy environments.
Managing Execution Policy Via Group Policy
In on-premise Active Directory environments, Group Policy provides centralized control over many systems‘ execution policy configuration:
Figure: Configuring PowerShell execution policies via Group Policy admin center
Group Policy settings override individual machine and user policies. This allows centralized administration compliance and security baselines. If machines stop running scripts after being healthy, Group Policy likely recently changed.
Ideally organizations bake approved exceptions into Group Policy rules automatically allowing authorized teams like DevOps to utilize PowerShell remotings and automation.
Why Sign PowerShell Scripts?
We‘ve focused a lot so far on PowerShell execution policies that check if code is signed before allowing execution. But what is signing and its purpose?
Code signing applies a digital signature validating the publisher and ensuring the code/script hasn‘t been tampered with since signing.
Although signatures don‘t block writing malicious code itself, they provide accountability helping mitigate risk. Any signed script that compromises systems can have its signature traced back to the original author.
Therefore, policy choices like AllSigned mandate that all scripts must be signed by a trusted publisher for elevated confidence.
Signing Your Scripts
While beyond the full scope here, it is best practice to digitally sign your PowerShell scripts using certificates when possible.
Here is a brief example:
# Generate cert
$cert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -FriendlyName "My Powershell Signing Cert"
# Sign script
Set-AuthenticodeSignature .\MyScript.ps1 $cert
This allows utilizing more secure execution policies while still enabling automation capabilities.
PowerShell Remoting Security
A common source of PowerShell scripts is retrieving them remotely from other systems via PowerShell remoting. This allows managing many servers at scale through automation.
However, remoting also significantly expands the attack surface. Malicious signed scripts could infect entire fleets of systems.
Therefore, lock down remoting where possible and utilize the most stringent policies. Audit logs via tools like Sysmon can detect suspicious remote script activities. Implement principle of least privilege when assigning remote access.
Comparing to Linux Shell Script Permissions
PowerShell‘s execution policy system provides granular script access management similar to Linux/Unix shell script permissions.
On Linux, scripts have attributed execute permissions dictating what users/systems can invoke them. However, this is based solely on file system permissions. There is no concept of signed scripts or publisher validation.
While Unix environments emphasize permissions isolation, PowerShell execution policies focus more on signing trust and decentralized management.
Both OSes now incorporate role-based access controls, auditing capabilities and sand-boxed automation (e.g. Docker) to compensate for these platform differences.
Resolving "Running Scripts Disabled" Errors
With this context around policies and security, let‘s revisit how to resolve our initial PowerShell script errors.
The exact method depends if you are…
- An end user trying to run your own scripts.
- A system administrator automating many servers.
- A software developer building secure modules.
End User Self-Resolution
As an end user on a locked down Windows machine, you have limited options without admin rights.
Attempting to permanently reset system execution policy will fail. However, you can leverage the Bypass option temporarily:
powershell -ExecutionPolicy ByPass -File .\MyScript.ps1
This isn‘t persistent, but allows bypassing policy while developing and testing scripts.
Get any custom tools vetted through your IT help desk once completed to allow permanent signing and execution freedoms.
System Administrator Resolution
For server and workstation fleet automation, permanently adjusting execution policy is recommended:
- Open PowerShell as admin on target systems
- Set policy via
Set-ExecutionPolicy
cmdlet:Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
- Validate policy change succeeded
- Deploy scripts using remote management and orchestration tools
Double check any domain Group Policy restrictions that may override local policies. Get exceptions added to AD GPO to enable script execution freedoms where required.
Software Developer Resolution
As a developer, leverage scope parameters to limit script testing policies to just your user context and sessions:
Set-ExecutionPolicy ByPass Process
This allows you to build and test code with no restrictions until ready for production.
Implement signing procedures for release code for heightened accountability and audit controls:
Set-AuthenticodeSignature .\MyModule.psm1 -Certificate $signingCert
Have internal certificate policies in place for trusted secure code distribution leveraging AllSigned execution policies where possible.
Expert Recommendations for PowerShell Code Security
Here are some best practice recommendations for balancing security and productivity with PowerShell automation:
- Require all user-generated scripts to be reviewed and signed by central IT teams prior to use in production
- Mandate code review approval processes for PowerShell code within CI/CD pipelines
- Follow least privilege principles and constrain script permissions through precise scoping
- Shift towards domain Group Policy centralized execution policies over individually managed servers
- Utilize application whitelisting and script allowing/blocking via Windows AppLocker permissions
- Enforce sandboxed PowerShell execution contexts (e.g. containers, ephemeral tooling)
Audit logging via PowerShell transcription logging and monitoring tools provides oversight for when bypassing policies on rare occasions makes sense.
Ongoing security awareness education helps reduce risky ad-hoc script practices that bypass governance.
Conclusion
The "running scripts disabled" error arises due to the default Restricted execution policy shipped with PowerShell environments. This prevents all unsigned code from executing, reducing risk but blocking automation capabilities.
Use the Set-ExecutionPolicy
cmdlet to resolve this permanently by configuring more permissive policies like RemoteSigned. Or leverage -ExecutionPolicy Bypass
for temporary troubleshooting.
Understand the security trade-offs involved when opening execution rights. Implement compensating controls like script signing, logging, and scoping to strike the right balance.
Now you can unlock the immense automation power of PowerShell confidently while keeping systems secured.