Before you can run a PowerShell script, you will need to check the PowerShell Execution Policy setting and possibly change it. Here’s how.
Running PowerShell Scripts
OK, so you’ve written your first script, and it looks something like this:
# Awesome-Script.ps1 Write-Host "My script executed!"
Now you try to run it for the first time. Whether you execute it in Windows PowerShell ISE or attempt to run it from a PowerShell command prompt, you get the same error:
PS C:\Users\aaron> C:\TEMP\Awesome-Script.ps1 File C:\TEMP\Awesome-Script.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170. + CategoryInfo : SecurityError: (:) , ParentContainsErrorRecordException + FullyQualifiedErrorId : UnauthorizedAccess
The script doesn’t run because the PowerShell Execution Policy is set to the default of Restricted.
What’s a PowerShell Execution Policy?
Does anyone remember the Anna Kournikova virus of 2001? It was a Visual Basic Script file (.vbs) that was sent around as an Outlook attachment. If you opened the script, it sent the same malicious attachment to all of your Outlook contacts (I long for the day that is all malicious files did!). Beyond security practices that have changed for allowing executable email attachments (hint: you shouldn’t be allowing them), that virus demonstrated the risk of having a malicious script file downloaded from the Internet and executed on your computer. This is where the PowerShell Execution Policy comes into play.
Windows PowerShell execution policies let you determine the conditions under which Windows PowerShell loads configuration files and runs scripts. The execution policy is not a security system that restricts user actions. For example, users can easily circumvent a policy by typing the script contents at the command line when they cannot run a script. Instead, the execution policy helps users to set basic rules and prevents them from violating them unintentionally.
Restricted by default
Unintentionally is the keyword there. Most users who use Windows would never have a need to run a PowerShell script, so why have it enabled by default to be leveraged by an attacker? Microsoft made a security conscious decision to disable executing scripts out of the box. Execution Policy has five potential values (and a phantom sixth):
- Restricted (DEFAULT for all versions of Windows except for Windows Server 2012 R2)
- Permits individual commands, but will not run scripts.
- Scripts can run, but they must be signed by a trusted publisher with a digital signature, even scripts you wrote on your local computer.
- If you try to run a script that is signed by an unknown publisher, it will prompt you to allow or deny.
- Does not guarantee the script contents aren’t malicious, just that the script file hasn’t been modified since being signed by a trusted publisher.
- RemoteSigned (DEFAULT for Windows Server 2012 R2)
- Scripts can run, however:
- Scripts or config files downloaded from the Internet, including those from emails or IM attachments, must be digitally signed, OR
- the script file is unblocked using the Unblock-File cmdlet (or right-click file, go to Properties > General and select to Unblock the file).
- Scripts that are written on the local computer or within the same Windows AD domain do not require a digital signature or unblocking to run.
- Scripts can run, however:
- Unsigned scripts can run, regardless of origin.
- If a file is from the Internet and hasn’t been unblocked, the user will be warned before executing.
- Nothing is blocked.
- No warnings, no prompts.
- Per Microsoft: “This execution policy is designed for configurations in which a Windows PowerShell script is built in to a a larger application or for configurations in which Windows PowerShell is the foundation for a program that has its own security model.”
- The phantom sixth. It relates to scopes, which will be discussed below.
- If all scopes are set to Undefined, the inherited value is the default for your Windows version, either Restricted or RemoteSigned.
- You can set a scope’s policy to Undefined, and it will remove it from precedence processing (also discussed below).
Policy recommendation? It depends
If you plan on using PowerShell scripts at all, Restricted obviously is out of the running. I personally think RemoteSigned is a good compromise between functionality and security in a Windows AD domain environment. It allows you to write scripts internally and use them on domain systems without any friction, while still preventing unintentional execution of an outside script. AllSigned is a better option, but you need the PKI/certificate infrastructure in place as well as good policies and processes for signing and managing script code, which a lot of organizations are lacking.
Ultimately, only YOU can determine what the best default Execution Policy is for your environment (and prevent forest fires).
Determine your current Execution Policy
OK, now that all of the academic stuff is out of the way, how do you find out what your current Execution Policy is, and how do you change it?
To see your current Execution Policy, run Get-ExecutionPolicy:
PS C:\Users\aaron> Get-ExecutionPolicy Restricted
Pretty straight forward, but I am on a non-domain computer. If you are trying to figure out your Execution Policy in a domain environment where Group Policy can be in play, run the following:
PS C:\Users\aaron> Get-ExecutionPolicy -List Scope ExecutionPolicy ----- --------------- MachinePolicy Undefined UserPolicy Undefined Process Undefined CurrentUser Undefined LocalMachine Undefined
Not very interesting on a non-domain computer, but you can see now why when I run Get-ExecutionPolicy it returns Restricted, because all of the scopes are set to Undefined and the default for Windows 10 is Restricted.
A domain computer’s list could look very different. LocalMachine‘s value is set in the Local Group Policy Editor. MachinePolicy and UserPolicy would come from AD Domain Group Policy objects. The Process value is retained only for the live of the powershell.exe process containing it. The applied policy isn’t determined by the most restrictive, it is determined by scope precedence, which follows the output display order (MachinePolicy gets top precedence, then UserPolicy, etc.)
When there different values set for different scopes, Get-ExecutionPolicy will tell you which value is in effect for the PowerShell session you are in. Your UserPolicy may be set to RemoteSigned, but if the MachinePolicy is set to Restricted you will not be able to run scripts.
Setting Execution Policy using PowerShell
You can set a local computer’s Execution Policy with Set-ExecutionPolicy (Run As Administrator):
PS C:\WINDOWS\system32> Set-ExecutionPolicy RemoteSigned Execution Policy Change The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose you to the security risks described in the about_Execution_Policies help topic at http://go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"): a
Now when I run Get-ExecutionPolicy again:
PS C:\Users\aaron> Get-ExecutionPolicy -List Scope ExecutionPolicy ----- --------------- MachinePolicy Undefined UserPolicy Undefined Process Undefined CurrentUser Undefined LocalMachine RemoteSigned
I can specify the scope as well if I only want to set a policy for my user (Run As Logged In User):
PS C:\Users\aaron> Set-ExecutionPolicy RemoteSigned -Scope CurrentUser Execution Policy Change The execution policy helps protect you from scripts that you do not trust. Changing the execution policy might expose you to the security risks described in the about_Execution_Policies help topic at http://go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the execution policy? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"): a
I run Get-ExecutionPolicy and you will see CurrentUser is now set to RemoteSigned:
PS C:\Users\aaron> Get-ExecutionPolicy -List Scope ExecutionPolicy ----- --------------- MachinePolicy Undefined UserPolicy Undefined Process Undefined CurrentUser RemoteSigned LocalMachine RemoteSigned
Setting Execution Policy with Group Policy
In a Windows domain setting, you likely don’t want to configure Execution Policy one machine at a time. You also don’t want someone with local Administrator rights on a computer to be able to change this setting. Luckily, there is a simple Group Policy setting that can be configured either at the Computer Configuration or User Configuration level.
- Make sure you have PowerShellExecutionPolicy.admx file loaded. This is installed out of the box with Windows Server 2008 R2 or later.
- For computers, in your GPO go to Computer Configuration\Administrative Templates\Windows Components\Windows PowerShell. (Remember, MachinePolicy has overall precedence).
- For users, in your GPO go to User Configuration\Administrative Templates\Windows Components\Windows PowerShell.
- The setting is called Turn on Script Execution. Potential settings and impact:
- Not Configured (default). No effect, PowerShell Execution Policy is set and enforced on the local computer.
- Disabled. Scripts won’t run. (Restricted)
- Enabled. You can choose between three execution policies:
- Allow all scripts. (Unrestricted)
- Allow local scripts and remote signed scripts. (RemoteSigned)
- Allow only signed scripts. (AllSigned)
- Apply the updated GPO to computers or users for the settings to be enforced and run gpupdate for those computers/users.
- Identify your computer’s active Execution Policy as well as any policies configured for different scopes.
- If you are on a computer you administer and want to be able to execute scripts, run Set-ExecutionPolicy RemoteSigned (or whatever Policy you prefer).
- Run your script!
PS C:\temp> .\Awesome-Script.ps1 My script executed!