The PowerShell execution policy was developed with a vision to be friendly to administrators, and at the same time, be accessible to end users. More than the former, the latter goal was a little challenging to pull off, considering that convenience is, more often than not, inversely proportional to security.
PowerShell scripts do not run out of the box
There have been times when malicious VBS (Visual Basic Script) files, disguised as helpful pieces of software were shared around as emails. Unsuspecting users double-clicked the script files, and fell victims to scams as small as letting the creator of the script know you ran the script, to as disastrous as giving the creator of the script complete control over your computer.
There were two major flaws in the aforementioned model:
- Double-clicking the script would run the script. There was no need to open the script to read it before running it
- All scripts from anywhere could run
The PowerShell execution policy addresses the first by not loading the PowerShell engine to run the script. The script, under default configuration, opens in Notepad—not even in PowerShell Integrated Scripting Environment. (If the script opened in the PowerShell ISE, it is still easy to run the script by hitting the F5 key.) Opening the script in Notepad is benign; to run the script, the user would have to make considerable effort.
Even if the user manages to right-click on the script and selects Run with PowerShell, or loads up PowerShell ISE and hits the F5 key, you would get an error:
File C:\Users\Prashanth\Downloads\RandomInternetScript.ps1 cannot be loaded because the execution of scripts is disabled on this system. Please see “get-help about_signing” for more details.
Introducing PowerShell Execution Policies
You may hear that the PowerShell execution policies are a security feature; it is not. The PowerShell Execution Policies are a safety belt in PowerShell, like a child lock in cars. The PowerShell Execution Policies are the child lock on your computer, that protects the non-PowerShell-savvy end users from inadvertently harming themselves. It does not necessarily protect the system, but makes one jump through a few hoops to do something potentially dangerous.
PowerShell is very powerful. Its access goes straight into the computer. From the system administration standpoint—starting from fetching/setting the date and installing/uninstalling applications—there is hardly anything that PowerShell cannot do. Apart from managing Windows workstations and servers, PowerShell is extensively used with other applications and systems as well, such as Microsoft Exchange, Citrix XenApp and Nutanix HCI, to name a few.
The different PowerShell Execution Policies
PowerShell execution policies are several. They are set at different levels to control how the computer behaves with PowerShell scripts. Microsoft’s own documentation will give you a good picture of the different execution policies (or you can run Get-Help about_Execution_Policies to know more about these policies).
Note: At the moment of writing this article, PowerShell Execution Policies can be set only on Windows computers. PowerShell on non-Windows computers will still show the Execution-Policy-related cmdlets, but the policies set on non-Windows computers will have no effect on how PowerShell behaves on those computers.
Here is a gist of the different PowerShell execution policies and what they mean:
Restricted
PowerShell ships with Restricted set as the default execution policy, starting Windows Server 2012 (or Windows 8). Therefore, you cannot run a script right out of the box, unless you change the policy to something else before.
You can run individual commands on the PowerShell console, though. Even scripts written by you cannot run with this policy set on your computer.
AllSigned
This is the safest policy available, in case running scripts is permitted on the computer. With this policy set, your computer will run those PowerShell scripts that are accompanied by a valid signed with a valid digital signature (signed using a code signing certificate).
The certificate used to sign the script should be trusted by your computer. Otherwise, the script will not run. It also means that scripts that are tampered with after being digitally signed will not run either.
This condition also applies to scripts that you wrote, even on the computer that you are trying to run the script on.
This is a safe PowerShell Execution policy to set in any enterprise environment. The certificate could have been issued by your domain’s certification authority, or from an external certification authority like Verisign or Thawte.
RemoteSigned
This is also a safe PowerShell Execution policy to set in an enterprise environment. This policy dictates that any script that was not created on the system that the script is running on, should be signed. Therefore, this will allow you to write your own script and execute it. You would not be able to run a script that was downloaded from the Internet, or got from a friend who wrote it under his account or on a different computer. PowerShell differentiates between script you wrote on that computer, and a script that came from elsewhere using the file metadata.
Unrestricted
This policy is unsafe in any environment, and should be applied only when you know what you are doing. Also, keep in mind the scope at which you set this policy. More on this later in the post.
The Unrestricted Execution Policy lets you run PowerShell scripts without any restrictions.
Bypass
This policy is best avoided. This policy should be used only in those cases where you have an alternative authorization mechanism already in place, and you do not want PowerShell to interfere with the execution.
Undefined
Setting the Execution Policy to Undefined will remove policy restriction at the scope/level in/at which you run Set-ExecutionPolicy Undefined. However, remember that setting the Execution Policy to Undefined at all levels would lead PowerShell to set the machine policy as Restricted, which is the default.
Precedence of Execution Policies
A very important point to remember with PowerShell Execution Policies is the scopes at which the policies can be set. Here are the different scopes at which you can set an Execution Policy:
- Process
- CurrentUser
- LocalMachine
The Execution Policies set at CurrentUser and LocalMachine levels are stored in the registry. Let’s take a look at how applying a PowerShell Execution Policy at the local machine level changes the values in the registry. First, here is what the status is when the Execution Policy is Undefined:
Now, we set the PowerShell Execution Policy at the local machine level, to AllSigned.
And now, we reset the PowerShell Execution Policy.
The PowerShell Execution Policy set on Process is stored in the memory (RAM), and is valid for as long as the PowerShell process on which the policy was set, is active. On a newly-opened PowerShell session, the resultant policy will be that set on CurrentUser.
The Execution Policy set on Process has the highest precedence. Therefore, the policy you set on Process will override those policies set at the CurrentUser and LocalMachine levels. By default, the PowerShell Execution Policy set on Process is Undefined. Therefore, the policy set on CurrentUser is applied to the process.
If the CurrentUser does not have any policy set (in other words, the PowerShell Execution Policy set on CurrentUser is Undefined), the policy set on LocalMachine will be applied to CurrentUser, which will subsequently flow to Process, unless there is an override at the Process level.
If there is no policy set at CurrentUser, LocalMachine or Process, the default PowerShell Execution Policy of Restricted will apply from PowerShell itself.
Getting a list of scopes
To get a list of the available scopes at which you can set PowerShell Execution Policy levels, run the following command:
1 |
Get-ExecutionPolicy -List |
You would see an output similar to the following (also, as said before, notice the resultant PowerShell execution policy in spite of the policy being Undefined at all scopes):
You see two additional scopes compared to those mentioned in Precedence of Execution Policies. These are based on the Execution Policies set using Group Policies. We will get to that in the section, Setting an appropriate Execution Policy. The scopes shown here also indicate the precedence.
The policy set at the MachinePolicy level using a group policy will take ultimate precedence. Therefore, if a user tries to override the Execution Policy of AllSigned set at MachinePolicy level, the policy he sets would be applied to CurrentUser, which will be overridden by MachinePolicy.
PowerShell Execution Policies cannot be set at MachinePolicy or UserPolicy levels from the console; they have to be done using Group Policies. If you try to set an execution policy at these scopes from the PowerShell console, you would get an error:
Set-ExecutionPolicy : Cannot set execution policy. Execution policies at the MachinePolicy or UserPolicy scopes must be set through Group Policy.
Setting an appropriate PowerShell Execution Policy
Now that we know the different execution policies, the different scopes that they can be set at, and how PowerShell determines the resultant execution policy, we should be able to set an PowerShell Execution Policy appropriate for our environment.
If I were to share my recommendation, I would set, on an environment that has adequate security measures applied to it at the perimeter and within the environment itself, the following:
- Set up Active Directories Organisational Units appropriately; separate administrators from end users
- Generate a code signing certificate (from your Internal CA, preferably) for those who write PowerShell scripts in your environment
- Ensure the certificates you generate for these script-writers is trusted in your environment
- Implement a process in place that every script that will be used for administration must be signed by the respective script-writer
- Apply the AllSigned policy at the UserPolicy level using Group Policy
- Apply an appropriate policy at the MachinePolicy level for the computers that will be used to test scripts. This should preferably be a separate, sandboxed environment
- Ensure that only those trusted individuals, who know what they’re doing, have access to log into these test computers in the sandboxed environment
Of course, this is a recommendation. As an Enterprise Administrator, you should have a good understanding of what is best for your environment. The goal of this article is to explain what the group policies are, and explain what the scopes are, by means of a deep-dive look at the different aspects concerning Execution Policies in PowerShell.
I hope this article helps you with your decision-making on setting an appropriate PowerShell Execution Policy in your enterprise environment. If you have any questions or would like to share your thoughts or experiences with respect to PowerShell Execution Policy, post your comments below!
Table of contents
DBATools PowerShell Module for SQL Server | |
PowerShell SQL Server Validation Utility – DBAChecks | |
Choosing and Setting a PowerShell Execution Policy |
- Stairway to SQL essentials - April 7, 2021
- A quick overview of database audit in SQL - January 28, 2021
- How to set up Azure Data Sync between Azure SQL databases and on-premises SQL Server - January 20, 2021