Posted on January 25, 2017 · Posted in Powershell

How to Sign PowerShell Script with a Code Signing Certificate

A script or an executable with a digital signature allows a user to make sure that a file is original and its code has not been changed by third parties. PowerShell also has an integrated feature to sign a *.ps1 script files.

You can sign a PowerShell script using a special type of certificate – Code Signing. This certificate can be obtained from an external certification authority, an internal enterprise CA or  you can use a self-signed certificate (of course, it is not the best option).

Suppose, PKI services ( Active Directory Certificate Services) are deployed in your domain. Let’s request a new certificate by going to https://CA-server-name/certsrv and requesting a new certificate with the Code Signing template (this template must first be enabled in Certification Authority console).

enterprise ca - create a cert from code signing template

Install this certificate to the local certificate authority (storage) on your computer.

After you got the certificate, let’s configure a PowerShell script execution policy and allow running only signed scripts. The default policy value (Restricted) blocks execution of any scripts. To allow running signed scripts, you can change the policy type to AllSigned or RemoteSigned with the only difference that RemoteSigned requires a signature only for the scripts downloaded from the Internet.

Set-ExecutionPolicy AllSigned –Force

Get a certificate from the local storage as a separate object for the current user:

$cert = (Get-ChildItem cert:\CurrentUser\my –CodeSigningCert)[0]

Then sign the script using this certificate:

Set-AuthenticodeSignature -Certificate $cert -FilePath C:\PS\testscript.ps1

Tip. When creating a self-signed certificate to sign your code using New-SelfSignedCertificate cmdlet, specify the CodeSigning type of the certificate:

New-SelfSignedCertificate -DnsName testPC1 -Type CodeSigning

After the certificate has been generated, move it from Intermediate container to Trusted Root using Certificate Manager console (certmgr.msc).

You can sign a script with this certificate as follows:

Set-AuthenticodeSignature C:\PS\testscript.ps1 @(gci Cert:\LocalMachine\My -DnsName testPC1 -codesigning)[0]

Set-AuthenticodeSignature PowerShell Script

After the PowerShell script has been signed, a signature block is added to the text file of ps1 script:

# SIG # Begin signature block
# SIG # End signature block

SIG Begin signature block

If you select [A] Always run at the first run of the script, the next time you run the script, signed using this certificate, a warning will no longer appear.

Do you want to run software from this untrusted publisher?

File C:\PS\testscript.ps1 is published by CN=testPC1 and is not trusted on your system. Only run scripts from trusted publishers.

File  ps1 is published by CN and is not trusted on your system. Only run scripts from trusted publishers

Tip. The CA root certificate used to sign the script has to be trusted (otherwise, the script won’t run). The certificate used to sign a script also has to be trusted, otherwise a script will run with a prompt. Here is an article to help you:  Deploy Certificates by Using Group Policy

What will happen if you change the code of the signed PowerShell script? The attempt of running it will be blocked with the notification that the contents of the script has been changed.

C:\PS\testscript.ps1 : File C:\PS\testscript.ps1 cannot be loaded. The contents of file C:\PS\testscript.ps1 might  have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system.

because the hash of the file does not match the hash stored in the digital signature

Thus, any modification of a signed script will require to re-signing it.

Related Articles