How to Sign PowerShell Script?

Have you opened a PowerShell script and seen random gibberish near the bottom? That seemingly useless chunk of code is not for nothing. Instead, that shows a PowerShell digitally-signed script.

A PowerShell digitally signed script is a script that contains the identity of the source that signed it. What are the benefits when you digitally sign a PowerShell script?

For example, before you publish a script to the internet, it is a good idea to digitally sign your scripts so that the original code is marked and can be identified. Any changes to the original code invalidate the existing signature, which would clearly indicate the code has been modified.

Also, PowerShell has a set of Execution Policies. In Windows Servers, the default is Remote Signed, which only permits running scripts obtained from the internet that are digitally signed. In some security-conscious organizations, administrators set the execution policy to All Signed on all client computers, which means you can only run signed scripts and nothing else.

In these cases, if the PowerShell script is not digitally signed, you’re in a pickle. But not all hope is lost. Look at this situation as the opportunity to better protect your scripts by digitally signing them yourself, and this post will teach you how.

Requirements

  • A computer running any recent version of the Windows Server or Desktop operating system.
  • Windows PowerShell 5.1 or the latest version of PowerShell Core, 7.3.0, as of this writing.
  • A sample PowerShell script is not digitally signed. A simple Hello World script should suffice for this demo.

Get a Code Signing Certificate

Before signing a certificate, you must have a code signing certificate (Authenticode). There are three Authenticode certificates you can get depending on how you plan to deploy your scripts.

  • A public or global digital certificate — This type of Authenticode certificate is not free, and you must purchase them from a well-known digital certificate provider, like DigiCert.com, Comodo, or SSL.com.
  • A certificate issued by an internal certificate authority — This certificate type is usually found in a network setting where the organization issues certificates from the CA server. As such, this certificate has no additional cost as long as the CA infrastructure is already in place.
  • A self-signed Authenticode — This certificate is free but the least trusted since no other party verifies its validity and identity. But for this demo, a self-sign certificate should be enough.

Let’s create the self-signed certificate. Open PowerShell as admin and run the below command. This command generates a digital certificate called MyDigitalCertificate, and the type is CodeSigningCert. The certificate store location in this example is Cert:\LocalMachine\My, a system-wide store. The only other valid certificate store location is Cert:\CurrentUser\My.

# Create the authenticode certificate 
$certSplat = @{ 
Subject = 'MyDigitalCertificate' 
CertStoreLocation = 'Cert:\LocalMachine\My' 
Type = 'CodeSigningCert' 
} 
$authenticode = New-SelfSignedCertificate @certSplat 
$authenticode

Make sure to copy the certificate thumbprint value. You’ll need this later when signing.

how to sign powershell script

Next, open the Certificates management console by running the below command.

certlm.msc

Go to Personal → Certificates and locate the certificate you created. Once you find the certificate, copy it to the following location.

  • Trusted Publishers → Personal.
  • Trusted Certification Authorities Authorities → Personal.

how to digitally sign a powershell script

The above step ensures that the computer trusts the code-signing certificate from end to end.

You now have a valid, trusted code signing certificate.

powershell how to sign a script

Sign PowerShell Scripts

So now you have the code signing certificate, let’s use it to sign a PowerShell script. For this, we’ll use a simple PowerShell script to sign. In this example, the PowerShell script is named hello-world.ps1.

First, retrieve the code signing certificate and store it in the $certificate variable. Replace the 8455C4AC6F3D8B5C81AEB61DBCC31E520284B687 with your certificate’s thumbprint.

$certificate = Get-Item Cert:\LocalMachine\My\8455C4AC6F3D8B5C81AEB61DBCC31E520284B687

Next, take the below code and replace the FilePath value with your script’s file path. The TimeStampServer in this example points to the DigiCert timestamp URL.

*A timestamp server adds a verified timestamp to the digital signature. This ensures that the code does not expire even when the code signing certificate expires.

Other timestamp servers exist, one from Comodo, which is http://timestamp.comodoca.com.*

$signSplat = @{ 
FilePath = ".\hello-world.ps1" 
Certificate = $certificate 
TimeStampServer = 'http://timestamp.digicert.com' 
} 
Set-AuthenticodeSignature @signSplat

how to sign powershell script windows 10

And that’s it! Your script is now digitally signed.

Verify the Script Digital Signature

How do you verify that that PowerShell script has a digital signature? There are a few ways.

First, you can open the script and confirm that the digital signature exists. The signature block starts with # SIG # Begin signature block.

powershell how to digitally sign script

Second, you can open the script’s file properties and go the Digital Signatures tab.

how to digitally sign a script

Third, run the Get-AuthenticodeSignature cmdlet against the PowerShell script file.

Get-AuthenticodeSignature -FilePath .\hello-world.ps1

As you can see below, the script’s signature is valid and verified.

powershell how to sign scripts

Conclusion

If a PowerShell script is not digitally signed, it may be modified and passed on as the original. Digitally signing your scripts helps comply with system policies and ensure that your scripts have verified publisher identities.

Cyril Kardashevsky

Leave a Reply

Your email address will not be published. Required fields are marked *