Of the execution policies allowed by PowerShell, RemoteSigned provides the greatest degree of flexibility while still providing a measure of security. But the implications of RemoteSigned are not well explained by the PowerShell documentation. I will endeavor to explain this setting fully here.
Downloaded Files
Windows XP SP2 and later and Windows Server 2003 SP1 added the Attachment Execution Service. This API makes it easier for applications to write security zone information into an NTFS Alternate Data Stream (ADS) on the file. An Alternate Data Streams is a pseudo-hidden metadata space that can contain standard Unicode characters. ADSs are not widely used in general. When invoked, the Attachment Execution Service writes the file’s originating Security Zone to the Zone.Identifier ADS on the file. For example, a file downloaded from the Internet using Internet Explorer or Firefox 3 will have the following information in the file’s Zone.Identifier ADS:
[ZoneTransfer]
ZoneId=3
You can see this information by opening the Zone.Identifier ADS for a file in Notepad as follows:
notepad c:\folder\filename.ps1:Zone.Identifier
If you are prompted to create the “file”, no Zone.Identifier ADS exists.
PowerShell uses the information written to the Zone.Identifier ADS to determine whether to run a script under the RemoteSigned execution policy. If a script is marked as originating in the Internet or Untrusted security zones, PowerShell will abort execution and display an error similar to the following:
File C:\folder\script.ps1 cannot be loaded. The file C:\folder\script.ps1
is not digitally signed. The script will not execute on the system. Please see
“get-help about_signing” for more details..
At line:1 char:2
+ & <<<< “C:\folder\script.ps1″
If the Zone.Identifier ADS doesn’t exist, or if it shows any ZoneId besides 3 for Internet or 4 for Untrusted, the script will execute.
The table below summarizes how PowerShell handles each ZoneId when a script runs under the RemoteSigned execution policy:
| Zone |
ZoneId |
Result |
| NoZone |
-1 |
Script Runs |
| MyComputer |
0 |
Script Runs |
| Intranet |
1 |
Script Runs |
| Trusted |
2 |
Script Runs |
| Internet |
3 |
Script Aborts |
| Untrusted |
4 |
Script Aborts |
| (Any other value) |
… |
Script Runs |
Various applications use the Attachment Execution Service to set a Zone.Identifier ADS to different values. The following lists a few examples:
| Application |
ZoneId |
| Internet Explorer 6 or newer |
Determined by the Security Zone for the website (Typically 3 for Internet websites) |
| Firefox 3 |
3 |
| Firefox 2 or older |
(Not set) |
| Opera |
(Not Set) |
| Outlook Express/Outlook |
4 |
Note that files that are compressed when downloaded and then extracted typically inherit the Zone.Identifier ADS of the compressed “parent”.
If you download a PowerShell script with an application that writes the Zone.Identifier ADS ZoneId to 3 or 4, and your PowerShell execution policy is RemoteSigned, you have a couple of options to get the script to execute:
- Right click on the file, select Properties, and click the Unblock button. This will delete the Zone.Identifier ADS.
- Open the file and copy the contents to a new file in Notepad or your favorite editor. Then save the new file. The new file won’t have a Zone.Identifier ADS.
- Open the Zone.Identifier ADS directly in Notepad and change the ZoneId (Note: You will need to close PowerShell and reopen it if you already attempted to run the script, as it seems to cache the values in the Zone.Identifier ADS, and changing it via Notepad doesn’t trigger PowerShell to recheck it).
- Run the following command to blast the Zone.Identifier ADS:
echo $null > ./script.ps1:Zone.Identifier
- Run a script that is signed by the publisher and indicate that you trust the publisher when prompted.
- Sign the script using the Set-AuthenticodeSignature cmdlet. But you should only do this if you or your organization wrote the script or you did a strict code review on the script. By signing the file you are saying to the world “My organization and I mark this script as safe and take responsibility for it”. You shouldn’t sign someone else’s script and release it back into the wild.
- Change the PowerShell execution policy to Unrestricted (Note: I place this option in my “Bad Ideas” category. I’ll explain why I think so in a future post).
Naturally you should only run scripts that you have reviewed and deemed trustworthy.
While the Zone.Identifier ADS is a feature that can improve the security of your environment, it has limitations.
- Files without a Zone.Identifier ADS are trusted by default.
- Anyone with write access to a file can modify the Zone.Identifier ADS contents or delete it altogether.
Even with these limitations, using RemoteSigned reduces the likelihood that a worm or a malicious website can use PowerShell to attack your systems.
File Shares and Security Zones
While we usually think of security zones in relation to Internet Explorer, these zones also apply to mapped drives and UNC paths. PowerShell considers the security zone in which the file currently resides and applies the execution policy as defined. By default Windows XP and Vista consider UNC paths part of the Local Intranet, and will allow the execution of scripts on these paths with the RemoteSigned execution policy. Windows Server 2003 (Win2k3) and Windows Server 2008 (Win2k8) on the other hand run under a higher security standard, and by default consider UNC paths to be in the “Internet” Security Zone, even if they are on the local network. Typically this behavior is desirable, as servers should by their very nature run in a more restricted fashion.
| Operating System |
UNC Path Default Zone |
Result |
| Windows XP |
Intranet |
Script Runs |
| Windows Vista |
Intranet |
Script Runs |
| Windows Server 2003 |
Internet |
Script Aborts |
| Windows Server 2008 |
Internet |
Script Aborts |
If a file exists on a remote file share in the Internet or Untrusted security zones, and your PowerShell execution policy is set to RemoteSigned you can do the following to get the script to run:
- Copy the file locally. Unless the file already has a Zone.Identifier ADS, one will not be added.
- Run a script that is signed by the publisher and indicate that you trust the publisher when prompted.
- Sign the script. The same guidance on this process from above still applies.
- Add the server in the UNC path to the Intranet or Trusted security zones (Use Internet Explorer to configure this setting. Add the path as follows: file://servername)
- Change the PowerShell execution policy to Unrestricted (Still a bad idea).
Once again, you should only do this for scripts and paths that you trust.
Be aware that that most restrictive of the Security Zone and Zone.Identifier ADS will apply to the scripts that you run. For example, a script that exists on a trusted file share won’t run if it’s Zone.Identifier ADS marks the file as untrusted.
Using the RemoteSigned Execution Policy
Because it reduces the likelihood that PowerShell can be used by a worm or malicious website to attack your systems, I recommend that you consider the RemoteSigned execution policy the minimum setting for any system. Since it strikes a good balance between usability and security, I recommend this execution policy for servers that aren’t in high security areas or that aren’t intended for non-admin users such as Citrix or Terminal Servers. I also recommend this setting for desktops used to develop PowerShell scripts or that are used by power users that need to create their own PowerShell scripts.
I don’t recommend this setting as the default for general purpose desktops in your organization. For these systems I recommend AllSigned which I will cover in detail in a future blog post.
Conclusion
By allowing us to control the scripts that PowerShell can execute without interaction, Microsoft has made a effort to prevent PowerShell from becoming a target for worms and black hat hackers.
While it might be tempting to set the PowerShell execution policy to Unrestricted, RemoteSigned does a better job of preventing the execution of malicious scripts. Also, since locally created scripts are allowed to run, scripters will find they are unaffected by this setting. And since scripts that are downloaded from a website can be easily “unblocked”, there is no reason to run completely unprotected (Especially since most scripters I know don’t download PowerShell scripts, but rather copy the text of the script from a website and paste it into a local file).
The setting AllSigned is recommended for all other systems that need to run scripts (necessitating the signing of these scripts), and the default Restricted should be maintained for systems that should never execute PowerShell scripts.
You need to give careful consideration for the different PowerShell execution policies, and how you decide to implement them in your organization.
Happy PoSHing,
Mike Hays