Code signature for PowerShell script files

Below is a description of the options available for executing PowerShell script files, and what is possible by signing them.

For testing, a simple PowerShell script was created and run on a freshly installed Windows 10 client.

By default, a Windows 10 client is prevented from running because the execution policy for Windows PowerShell is set to "Restricted", which means that scripts are generally not allowed to run.

File C:\Users\rudi.INTRA\Desktop\HelloWorld.ps1 cannot be loaded because running scripts is disabled on this system.

The PowerShell Execution Policy

Do you know TameMyCerts? TameMyCerts is an add-on for the Microsoft certification authority (Active Directory Certificate Services). It extends the function of the certification authority and enables the Application of regulationsto realize the secure automation of certificate issuance. TameMyCerts is unique in the Microsoft ecosystem and is available under a free license. It can downloaded via GitHub and can be used free of charge.

Windows PowerShell has an execution policy that defines the behavior regarding the execution of scripts. This policy differs depending on the operating system variant:

Operating system variantExecution policy set by default
Windows clientsRestricted
Windows ServerRemoteSigned

The settings relevant for the further procedure briefly explained:

SettingDescription
RestrictedNo PowerShell scripts of any kind may be executed.
RemoteSignedLocally stored PowerShell scripts are allowed to run even if they are not signed. PowerShell scripts that reside on network locations are allowed to run only if they are signed.
AllSignedPowerShell scripts, whether stored locally or on network locations, must not be executed unless they are signed.

Manually configure execution policy

Our goal is to allow only signed scripts to be executed. Therefore, the execution policy is set to "AllSigned" with the following command.

Set-ExecutionPolicy AllSigned

Configure execution policy via group policy

The same effect can be achieved via group policies using the following setting: Computer Configuration" - "Administrative Templates" - "Windows Components" - "Windows PowerShell" - "Turn on Script Execution" - "Allow only signed scripts".

Digitally sign the script

The execution of the script will still not succeed because it does not have a digital signature yet.

File C:\Users\rudi.INTRA\Desktop\HelloWorld.ps1 cannot be loaded. The file C:\Users\rudi.INTRA\Desktop\HelloWorld.ps1 is not digitally signed. You cannot run this script on the current system.

Code signing certificate

To sign a script file you need a certificate with the Extended Key Usage (EKU) for code signature. This circumstance is taken for granted for the rest of the article and will not be discussed in more detail.

Perform the signature

To digitally sign PowerShell scripts, the Set-AuthenticodeSignature command can be used.

First, the code signing certificate is identified in the local certificate store and loaded into a variable.

$SigningCertificate = (Get-ChildItem -Path Cert:\CurrentUser\My\26716942D0BDBB2D3825C2469C611C59AAE11DE6)

Optional but very useful is the use of a timestamp according to RFC 3161. If the code signature is time-stamped, the signature continues to be recognized as valid even after the signature certificate has expired. In this example, the publicly accessible time stamp server from Sectigo is used.

$TimeStampingAuthority = 'http://timestamp.sectigo.com'

Now all information is available and the script can be signed.

Set-AuthenticodeSignature `
-FilePath .\HelloWorld.ps1 `
-Certificate $SigningCertificate `
-TimestampServer $TimeStampingAuthority

If you now look at the properties of the script file, you can see that it now has a digital signature.

A look at the details of the sigature also reveals that there is also a countersignature (time stamp).

If you open the script with a text editor, you will see that the digital signature has been appended to the script code in BASE64 encoded form.

Enter in the memory for "trusted publishers" (or not)

One would now think that the script could finally be executed. However, it is now noted that the editor is not trusted.

Do you want to run software from this untrusted publisher?
File C:\Users\rudi.INTRA\Desktop\HelloWorld.ps1 is published by CN=Rudi Ratlos, OU=User Accounts, OU=ADCSLabor Users, DC=intra, DC=adcslabor, DC=en and is not trusted on your system. Only run scripts from trusted publishers.

Now you have the option not to execute it, to execute it once, to execute it always, or to never execute it.

Selecting Always run causes the signing certificate to be imported into the Trusted Issuer store in the user's certificate store.

Leveraging the protection

However, the fact that the execution policy accepts only signed scripts is in no way a guarantee that unsigned scripts cannot be executed. There are many ways to subvert the execution policy and still run unsigned scripts.

Here is a simple example:

type .\HelloWorld.ps1 | powershell -

Related links

External sources

One thought on “Codesignatur für PowerShell Scriptdateien”

Comments are closed.

en_USEnglish