Set-ExecutionPolicy – Mastering PowerShell Execution Policy

PowerShell

PowerShell is considered secure by default due to various design principles and features that Microsoft incorporated into its architecture. These measures aim to ensure that PowerShell provides a robust, yet safe, scripting environment for system administration tasks. One feature of PowerShell that contributes to this are known as execution policies, which can be set using the Set-ExecutionPolicy cmdlet.

What is a PowerShell execution policy?

Execution policies in Windows PowerShell are not all-out security safeguards. Instead, envision them as protective switch covers. Their purpose is to prevent unintended script runs, especially from unverified sources. Let’s first look at and get a good understanding of what each policy can do.

Execution Policies are not intended to be your only security protection when using PowerShell scripts. Cyber security experts and PowerShell pros will tell you that execution policies alone are not foolproof. It’s quite literally the option to remove the guardrails and safety nets. With great power comes great responsibility and all that.

Understanding PowerShell execution policies

There are 7 execution policies that Windows PowreShell can apply. Each one provides a very specific set of rules that determine what Windows PowerShell can do when trying to run a script.

Default

All Windows clients are set to the restricted policy, and all Windows servers are set to remote signed by default. It’s important to consider this default setting when you are developing scripts on each Windows OS.

AllSigned

  • Only runs scripts signed by a trusted publisher.
    • If the source isn’t already trusted, you’re prompted before script execution.
    • This policy guards against rash decisions.

In the example below, you can easily set execution policy you want to enforce in your session:

# Example of running a script under AllSigned policy
Set-ExecutionPolicy AllSigned
Set-ExecutionPolicy AllSigned
Figure 1 – Set-ExecutionPolicy AllSigned (Image Credit: Petri/Bill Kindle)

With your policy set to AllSigned:

# This will prompt you if the script isn't trusted.
.\YourScript.ps1
Your PowerShell script isn't trusted
Figure 2 – Your PowerShell script isn’t trusted (Image Credit: Petri/Bill Kindle)

Just Because a script is signed… While running only signed scripts provides multiple benefits, it’s important to note that signing a script does not mean the script is safe in terms of its functionality. It ensures the script’s source and integrity, but the actions the script performs still need to be understood and vetted.

ByPass

  • Ignores execution policies, offering no warnings or prompts.
    • Caution: Use only when you’re confident about the script’s safety.

In the example below, you are setting the execution policy to be in ByPass mode for the process scope:

# Example: Temporarily bypassing the policy for a session.
Set-ExecutionPolicy ByPass -Scope Process

RemoteSigned

  • Allows locally written scripts without a signature.
    • Scripts from the internet need a signature.
    • To unblock unsigned scripts, use Unblock-File. However, do so cautiously.

Let’s try it out assuming you have already set your computer to use the RemoteSigned policy. Download PowerShell/Scripts/play-happy-birthday.ps1 at master · fleschutz/PowerShell · GitHub and save it to a path your computer.

In the example below, assume you are using C:\Temp. When RemoteSigned is enabled, you will see the error below:

Your PowerShell script was blocked
Figure 3 – Your PowerShell script was blocked (Image Credit: Petri/Bill Kindle)

Assume you have inspected the script and found nothing nefarious about it. Simply unblock the file and then try running the script again.

# Example of unblocking a downloaded script
Unblock-File -Path .\play-happy-birthday.ps1
PowerShell Unblock-File
Figure 4 – PowerShell Unblock-File (Image Credit: Petri/Bill Kindle)

You should hear “Happy Birthday” playing on your computer.

RemoteSigned is what you will encounter most often real-world scenarios, especially in environments where PowerShell has been adopted as the go-to automation tool by sysadmins. It’s best for when you run downloaded scripts or have mixed sources, development, and testing.

There are some benefits with using this mode as the default on servers. Using remote signed helps prevent potentially malicious scripts downloaded from the internet from running on your system unless it is signed by a trusted publisher. It’s also flexible in that you are still allowed to run scripts that you have developed locally.

You also need to know that there are some pitfalls to RemoteSigned. Local scripts as you just learned can be run without being signed. What that means is that you could inadvertently create a harmful script, and if you can, so could a malicious actor that has local access to your machine. Don’t let this policy give you a false sense of security, because execution policies themselves are not meant to be a sole security boundary.

Restricted:

  • Default for client computers.
    • Allows individual commands but blocks scripts.

Restricted is a great default setting for Windows client computers. You don’t want to have your users accidentally running scripts that you have not vetted yet yourself. But if you need to do basic commands and one liners, you can still do those tasks unimpeded.

Undefined:

  • No policy for the current scope.
    • If all scopes are undefined, defaults apply.

Unrestricted:

  • For non-Windows, it’s the default and unchangeable.
    • On Windows, it runs everything but warns about external or intranet scripts.


Unrestricted might as well be the Wild West policy. Think of unrestricted as bypass without being told to bypass. It’s equally dangerous, and arguably more so because you no longer must specify that you do or do not want the guardrails and safety nets based on the script you are running. Now it’s the wild west, and anything goes.

Understanding PowerShell execution policy scopes

Now that you understand the different policies and their use cases, it’s time to look at the different policy scopes to which execution policies can be applied.

MachinePolicy

Applied via Group Policy for all computer users. Great for enforcing system-wide standards.

UserPolicy

Set through Group Policy for a computer’s current user.

Process

Lasts only for a single PowerShell session and any child processes from that session. On closure, $env:PSExecutionPolicyPreference is deleted.

CurrentUser

Settings reside in the registry for the current user under HKEY_CURRENT_USER.

LocalMachine

Affects all users on a computer with registry settings in HKEY_LOCAL_MACHINE.

LocalMachine is the default scope, which affects every user on an endpoint. Changing this scope requires you to start PowerShell with Run As Administrator.

These policy scopes also follow a hierarchy. This can be useful when troubleshooting your PowerShell scripts on a host where execution policies are in effect. Remember that scope values are ordered in precedence.

Using Set-ExecutionPolicy to manage PowerShell execution policy

In the following examples, you will see how to leverage execution policy cmdlets and parameters in a specific scenario. Get-ExecutionPolicy and Set-ExecutionPolicy are the two cmdlets you need to use when manipulating execution policies.

How to list execution policies

You may be wondering how you would quickly get the execution policy for all scopes on a host. The quickest way to view available execution policies is to use the following command:

# List All Execution Policies applied to All Scopes
Get-ExecutionPolicy -List
Get-ExecutionPolicy
Figure 5 – Get-ExecutionPolicy (Image Credit: Petri/Bill Kindle)

Recall that execution policy scopes are listed in order of precedence. In the above example, the effective policy for the host is LocalMachine > RemoteSigned because the policies above were Undefined. Consider for a moment that MachinePolicy was RemoteSigned and CurrentUser was AllSigned. Machine policy is higher in precedence and therefor takes effect.

How to check current policy

Use Get-ExecutionPolicy. For specific scope details, use the -Scope parameter.

# Example: How to get current Exeuction Policy for Current User
Get-ExecutionPolicy -Scope CurrentUser
Get-ExecutionPolicy with scope
Figure 6 – Get-ExecutionPolicy with scope (Image Credit: Petri/Bill Kindle)

Knowing the existing policy in effect can help in troubleshooting scripts that are not running or producing the expected results.

How to change execution policy using Set-ExecutionPolicy

On Windows, you might occasionally need to adjust policies. The below example would allow a script to run only in the current PowerShell session. When you close the session and reopen a new one, the policy no longer applies. Using Set-ExecutionPolicy allows you to be explicit in how scopes are affected by policy.

# Example: Temporarily bypassing the policy for a session.
Set-ExecutionPolicy ByPass -Scope Process

If a policy is defined at a more specific scope above the scope you are adjusting, you may see an error message like the one below:

Using PowerShell Set-ExecutionPolicy
Figure 7 – Using PowerShell Set-ExecutionPolicy (Image Credit: Petri/Bill Kindle)

Manage Powershell execution policy with Group Policy

Using the option Turn on Script Execution is a great way to manage execution policy on computers in your organization if Group Policy is an option. Turning on this option and applying it to computers is the same as setting Restricted execution policy locally.

You can adjust these policies using Group Policy Management and creating a new policy. Once a new Group Policy Object has been created, find and edit the following setting:

Computer Configuration > Policies > Administrative Templates Policy > Windows Components > Windows PowerShell > Turn on Script Execution

Set PowerShell execution policy with Group Policy
Figure 8 – Set PowerShell execution policy with Group Policy (Image Credit: Petri/Bill Kindle)

By Default, the state is set to Not Configured. You can begin to change it by double-clicking the setting:

Turn on script execution
Figure 9 – Turn on script execution (Image Credit: Petri/Bill Kindle)

To change the policy to something more secure such as AllSigned or RemoteSigned, simply select Enabled and then choose either Allow only signed scripts (AllSigned), or Allow local scripts and remote signed scripts (RemoteSigned):

Set the execution policy using PowerShell
Figure 10 – Set the execution policy using PowerShell (Image Credit: Petri/Bill Kindle)

Once you are satisfied with your change, click OK to exit the configuration and close the Group Policy Management Editor. All that’s left is to place the policy in the correct Active Directory OU or site to begin applying to your endpoints.    

Bolster PowerShell security with execution policy

PowerShell execution policies bolster your security framework, especially when combined with other protective measures. They allow PowerShell’s automation prowess to shine without compromising safety. Nevertheless, don’t lean on them as the sole security pillar. They’re more like gatekeepers, ensuring you act with caution.