The execution policy of PowerShell scripts

I. Introduction

What is the purpose of the PowerShell script execution strategy? Which mode to choose? We're going to take a look at this important subject, using two cmdlets: Get-ExecutionPolicy and Set-ExecutionPolicy. The first cmdlet is used to view the current execution policy, while the second cmdlet is used to modify the configuration.

II. What is the purpose of the PowerShell script execution strategy?

The PowerShell execution strategy is a feature that enables you to prevent PowerShell code from being accidentally executed on your Windows computer. This means that the execution strategy does not protect you against attackers who deliberately wish to execute code on your machine. In other words, it will prevent a user from executing a PowerShell script by mistake, whether malicious or not.

Depending on the policy chosen, this execution strategy is more or less strict, meaning that some scripts can be executed, while others cannot. For example, we can block PowerShell scripts downloaded from the Internet, but allow local scripts.

Note: whether it's a Windows 10 (or other) client workstation or a Windows Server server, there's this notion of execution policy.

III. Different execution strategies

PowerShell supports six different modes of script execution strategy.

  • Restricted

Policy that blocks all PowerShell scripts on a machine, but allows the use of the PowerShell console or a tool like Windows Terminal to execute code interactively from the console. However, this means that it is not possible to directly execute a PS1 file. This is the default value on Windows operating systems (Windows 10, Windows 11).

  • AllSigned

For enterprise and production use, this is the most secure execution policy, as it only authorizes the execution of PowerShell scripts signed by a code-signing certificate. This certificate must be known to the local machine, whether issued by your company's certification authority (ADCS, for example) or self-signed.

The constraint is that every time a script is modified, even by a single character, it must be re-signed by the system administrator. If a PowerShell script has been signed by the system administrator, we can consider that its code has been validated and verified.

In a later chapter, we'll look at how to sign a PowerShell script using a self-signed certificate. You can also refer to the article below on how to do this with a certificate obtained from an Active Directory certification authority.

  • RemoteSigned

The default execution policy under Windows Server since Windows Server 2012 R2, it authorizes the execution of local PowerShell scripts, but blocks those from the Internet. How can you tell whether a script is coming from the Internet or not? There are hidden streams and metadata that can be used to identify the origin of the script, which will determine whether it can be executed or not (this refers to the Mark of the Web).

  • Unrestricted

This policy authorizes the execution of all PowerShell scripts, whether local or from the Internet. However, if a script comes from the Internet, a warning message is displayed and you must confirm that you wish it to be executed.

  • Bypass

This is the"open bar" mode: there are no controls, and all scripts, no matter where they come from, will be executed on the machine. This should be avoided in production, as a user will be able to execute any PowerShell script with a few clicks.

  • Undefined

This mode means "undefined" and therefore the default policy will apply, or that of the higher-level scope. You'll gain a better understanding of this concept and the Undefined policy as you continue reading this chapter.

IV. The scope of execution strategies

There are several PowerShell extents on a Windows host, each with its own execution policy. There are three main extents:

  • Process

The execution policy set on the"Process" scope will only apply at the level of the current PowerShell console, i.e. the current session. For example, this means that a script can be launched from this console if it uses the "Unrestricted" policy, but if at system level the policy is "Restricted", the same script cannot be executed directly via the Windows host.

The policy linked to the PowerShell process currently running is stored temporarily in memory.

  • CurrentUser

The policy defined for the"CurrentUser" scope only applies to the Windows session opened on the workstation. If another user logs on, they will potentially have a different policy applied to their account. The value is permanent and is stored in the Windows Registry(HKEY_CURRENT_USER).

  • LocalMachine

This policy is defined for the local machine and affects all users on the machine. This is the highest-level policy. Note that if the "CurrentUser" scope policy is not defined, it will be set to "Undefined", so the user will inherit the policy defined for the "LocalMachine" scope.

The value is permanent and also stored in the register(HKEY_CURRENT_MACHINE).

In addition to these three scopes, there are two further scopes corresponding to group policies. In fact, the execution policy can be forced on workstations and servers, at the level of the "LocalMachine" (computer) and "CurrentUser" (user) scopes, thanks to a GPO. This corresponds to the MachinePolicy and UserPolicy scopes.

V. Get-ExecutionPolicy

Now let's get down to business and use the first cmdlet: Get-ExecutionPolicy. This command is used to obtain the execution policy applied on the machine:

Get-ExecutionPolicy

If we wish to obtain more details, and in particular the execution policy applied to each scope, we must add the "-List" parameter to the command, as follows:

Get-ExecutionPolicy -List

This gives an explicit result:

VI. Set-ExecutionPolicy

We've just seen how to visualize the PowerShell script execution policy applied on a machine, in particular at the level of the various extents. Now we're going to learn how to modify this policy using the "Set-ExecutionPolicy" cmdlet.

To define an execution policy at machine level (LocalMachine), we need to execute this command:

Set-ExecutionPolicy -ExecutionPolicy AllSigned

Using the command above, we'll set the policy to "AllSigned". Confirm with "T" when executing this command.

If we want to change the execution policy for a specific scope, for example, the one named "CurrentUser", we need to add the "-Scope" parameter to the command. Here's an example:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

We can run the Get-ExecutionPolicy cmdlet again to check that our configuration has been taken into account.

Note that if a policy is defined at the "CurrentUser" level and another at the "LocalMachine" level, the one on the CurrentUser scope will apply.

VII. Bypassing the PowerShell execution strategy

As I mentioned in the introduction, the execution strategy is designed to prevent the accidental execution of PowerShell scripts. We can get around it very easily, notably by playing with the "Process" scope.

We'll take a machine running Windows 11, with the default execution policy Restricted, and try to run the script "script.ps1", which simply displays a message in the console. Here's its code:

Write-Output "Script PowerShell - IT-Connect"

If we try to execute the PowerShell script named "script.ps1", we get an error, as script execution is not allowed.

script.ps1

Here is the result obtained:

Windows 11 - PowerShell runtime strategy

Now, from this same PowerShell console, we're going to open another PowerShell console by specifying a particular execution policy. This will alter the policy applied to the"Process" scope, for the duration of the PowerShell session only, and allow us to execute any script.

The following command launches a PowerShell console with the"Bypass" execution strategy:

powershell.exe -ExecutionPolicy Bypass

Next, we'll run our script once again. This time, we can see that the script has been executed, since it has returned a message in the console. What's more, we can see that the execution policy on the "Process" scope is set to "Bypass"!

Windows 11 - Bypass PowerShell execution strategy

Without even needing to open an interactive PowerShell console, we could run our script like this:

powershell.exe -ExecutionPolicy Bypass -File .script.ps1

Alternatively, we could trick the user into retrieving the contents of the script file with the"Get-Content" cmdlet and executing it with the"Invoke-Expression" cmdlet, using the pipeline. In a way, this amounts to copying and pasting the script content into the PowerShell console in order to execute it: the execution strategy does not restrict code execution via the console, but only script files.

Get-Content ".script.ps1" | Invoke-Expression

We can see that it works:

Bypassing PowerShell execution policies with Get-Content

Although the PowerShell execution policy is a security feature, this test proves that its purpose is to prevent accidental script execution. If someone really wants to execute a script, they'll be able to do so, unless they go much further in configuring the machine (to the point of blocking PowerShell, for example).

VIII. Unblocking a PowerShell script

If we retrieve a PowerShell script from the Internet, we can "approve" it so that it can be executed. To do this, we need to use the "Unblock-File" cmdlet and specify the name of the .ps1 file to be unlocked. For example:

Unblock-File "C:\TEMP\script.ps1"

This corresponds to this option in the properties of a :

IX. Conclusion

The PowerShell execution policy, although bypassable, is important and should not be configured any old way. In the enterprise, give priority to using the AllSigned or at least RemoteSigned execution policy, but under no circumstances should you use the Bypass policy on your workstations and servers. On your personal workstations, keep Restricted if you don't use PowerShell, otherwise you can use RemoteSigned.

Finally, it's important to note that Windows PowerShell and PowerShell both have a script execution strategy, but it may be different, as these two versions are independent. To deploy a homogeneous configuration, I recommend using a Group Policy (GPO).


book to learn PowerShell