Setting up a code signing certificate and signing PowerShell scripts may sound like a complicated process, but I assure you it is not. The truth is, the script signing process if very simple and even though it requires a little extra effort on our part, the security benefits are well worth it.
There are several articles online that discuss the process of generating a self signed code signing certificate using the makecert utility. In this post, I am going to take another route and show you how to obtain a code signing certificate from a certificate authority and use it to sign your PowerShell scripts.
Obtaining a Certificate
I’ll assume you already have Active Directory Certificate Services available in your environment and that you have administrative rights to the CA server. If you need to set this up, it’s pretty straight forward. Check out this TechNet article for details.
You’ll probably need to issue the code signing template, this is not done by default. To add it to the server, run the Certificate Authority management snapin and connect to your CA. Right click on “Certificate Templates” then go to “New” and select “Certificate Template to Issue”:
This will bring you to the “Enable Certificate Templates” screen. Select the “Code Signing” template and click “Ok”:
Now that the code signing template is available, navigate to the certificate web enrollment page. This will be located at https://your server name/certsrv. Once you reach the welcome screen, click on “Request a Certificate”:
Click on “Advanced Request”:
Click on “Create and submit a request to this CA”:
Select “Code Signing” as the certificate template. Keep the remaining default settings:
And finally, install the certificate:
Now that you’ve got a certificate installed, you’ll want to make sure your execution policy requires signed scripts. By default the execution policy is set to Restricted. Set the execution policy to either AllSigned or RemoteSigned.
Set-ExecutionPolicy AllSigned -Force
The difference between AllSigned and RemoteSigned is that RemoteSigned will only require script signing on remote scripts (those that have been downloaded from the internet). When using AllSigned, scripts will always require a digital signature.
At this point, you should be ready to sign PowerShell scripts. This first thing you want to do is create an object that will store the code signing cert:
$cert = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert
The Get-ChildItem cmdlet retrieves the code signing certificate using the certificate provider from the current user certificate store and assigns it to the $cert variable. The next step is to actually sign a script:
Set-AuthenticodeSignature -Certificate $cert -FilePath C:\myScript.ps1
The Set-AuthenticodeSignature signs the myScript.ps1 script in the root of the c:\ drive using the code signing cert we obtained from the certificate authority.
Here’s what you’ see running the above code to sign the script:
After the script has been signed, there will be a signature block at the end of the script that looks something like this:
If you modify this script and attempt to run it again, you’ll get a nasty error that looks like this:
If you need to modify your script once it has been signed, you will need to resign it after it has been updated.
That’s all that needs to be done. I hope that if you haven’t considered signing your scripts that you will give it a try after reading this post. Happy scripting!