≡ Menu

Obtaining a Code Signing Certificate and Signing PowerShell Scripts

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:

Signing Scripts

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!

16 comments… add one

  • James Booth May 31, 2010, 11:06 am

    Exactly what I was looking for, nicely explained. Thanks, I’ve subscribed to your RSS feed.

    jhb

  • Mike Pfeiffer May 31, 2010, 12:04 pm

    Great! Thanks for the feedback.

  • Michael Heath June 21, 2010, 11:22 am

    I’m attempting to sign my scripts so I can run them under a scheduled task manager. However, everytime I execute the code that signs the script, I get the following error:

    SignerCertificate Status Path
    ——————- ——- ——

    UnknownError Sort-Test.ps1

    I don’t know where to begin to even check for what the issue may be. I’ve followed all the steps and can not get the signing to happen. The only thing I did differently is request the certificate from the CA using the Certificate snap in. For some reason we are unable to use the web access to request a certificate. I’m open to believe that this may be the issue but it is kind of tough to accept it since the certificate is exportable/importable to other machines without errors. If anyone knows what may be the issue here or how to troubleshoot it, I’d be grateful.

    Thank you.

  • Abu Zacharia August 30, 2010, 1:57 pm

    I searched the web looking for how to sign a PowerShell script using AD certificate services and I found a lot of sites with instruction on how to do it using makecert. I am glad I found your site. Thanks for the clear instructions and the screen shots were a nice bonus.

    Great Job!

    AZ

  • Mike Pfeiffer August 30, 2010, 5:40 pm

    Great, glad it helped! Thanks for your comment.

  • CypherBit December 8, 2010, 11:27 pm

    Excellent article, really helped me. I now sign all my PowerShell scripts and have also started using the certificate to sign Office 2010 macros. Two questions:

    - how do you deal with the expiration of the cert (1 or 2 years). Do you issue a new one and sign all your code again…hopefully not missing any of scripts. I know Verising has a timestamping server, but am unsure if this could somehow be used and without cost.
    - how could I sign an entire folder of scripts instead of one at a time. I tried (change directory to that particular folder beforehand): Set-AuthenticodeSignature -Certificate $cert -FilePath *.ps1 but that doesn’t do it.

    Any assistance would be appreciated.

  • Mike Pfeiffer December 14, 2010, 4:39 pm

    I just tested renewing my code signing certificate through my enterprise CA. I did this by loading the Certificates snapin on my Windows 7 machine with MMC, then simply right clicked on the certificate and selected ‘renew’. I verified that the certificate thumbprint was indeed updated afterward, and sure enough, my scripts signed previously still run just fine.

    Here’s some code that will sign all of the .ps1 files in the c:\scripts directory:

    $cert = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert

    Get-ChildItem -path C:\scripts -filter *.ps1 | %{
    Set-AuthenticodeSignature -Certificate $cert -FilePath $_.fullname
    }

  • CypherBit December 23, 2010, 4:03 am

    Thank you so much for this, great site and assistance.

  • chax8 January 7, 2011, 10:30 am

    Clear and easy to follow. Very much appreciated.

  • Mike Pfeiffer January 7, 2011, 5:25 pm

    Thanks for the comment chax8 :) glad it helped

  • Looney January 28, 2011, 12:08 pm

    Status Path
    ——————- ——- ——

    UnknownError Sort-Test.ps1
    ***********************************************
    FIX: This is cause by the Powershell ISE. Just open your script in NOTEPAD and save it. Then :
    Set-AuthenticodeSignature -Certificate $cert -FilePath C:\myScript.ps1
    and all should be well!

  • liquid khaos November 17, 2013, 10:07 am

    THIS! Thanks so much. Also, make sure you save as UTF-8. Avoid the endian issues.

  • Ben Toms February 21, 2012, 12:37 pm

    Hi Mike,

    I require a code signing cert from my internal CA for one of my Mac servers Profile Manager service.

    However, i followed the above & created a CSR on my mac server. But the cert is only for the user that authenticates to the CA certsrv webpage?? Ideas?

    (on a mac you’re prompted to authenticate using your AD creds when you go to the certsrv URL).

  • Remco March 29, 2012, 4:25 am

    Hi Mike,

    Great article. All goes well, until I run the script. A “File … is publised by CN=Administr…. and is not trusted on your system. Only run scripts from trusted publishers. ” error message appears and I’m prompted to choose from never run/run once/ etc. This happens on the domain server itself as well as on a client. Could you shed some light on what I’m doing wrong or fotgot to configure? (I’m new to certificates).

    Thanks for any idea…

  • Marco Z. April 20, 2012, 3:29 am

    Nice article!
    A short note: the script need to be save in UTF-8 if not PowerShell will REFUSE to sign it giving out only a Generic error (UnknownError status)
    Regards,
    Marco – StockTrader

  • Mike P. August 6, 2013, 10:37 am

    Mike,
    When I get to the point to click on “advanced certificate request,” the next screen does not give me the option to “Create and submit a request to this CA.” I get a box that states this above: “To submit a saved request to the CA, paste a base-64-encoded CMC or PKCS #10 certificate request or PKCS #7 renewal request generated by an external source (such as a Web server) in the Saved Request box.”

    What am I doing wrong?
    Thanks, Mike

Leave a Comment