Creating Code-Signing Certificates

by May 8, 2019

Windows 10 and Server 2016 (and better) ship with an enhanced New-SelfSignedCert cmdlet that finally can create code-signing certificates. With code-signing certificates, you can digitally sign PowerShell scripts and use the signature to detect when people tamper with your script content.

Here is a function that you can use to create a code-signing certificate:

function New-CodeSigningCert
{
    param
    (
        [Parameter(Mandatory, Position=0)]
        [System.String]
        $FriendlyName,
        
        [Parameter(Mandatory, Position=1)]
        [System.String]
        $Name
    )
    
    # Create a certificate:
    New-SelfSignedCertificate -KeyUsage DigitalSignature -KeySpec Signature -FriendlyName $FriendlyName -Subject "CN=$Name" -KeyExportPolicy ExportableEncrypted -CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(5) -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.3')
}

To create a new certificate, run this command:

 
PS> New-CodeSigningCert -FriendlyName TobiasWeltner -Name TWeltner 


   PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My

Thumbprint                                Subject
----------                                -------                                                                                                                        
2350D77A4CACAF17136B94D297DEB1A5E413655D  CN=TWeltner  
 

With your new code-signing certificate, you can now digitally sign your scripts. Your code-signing certificate resides in your personal certificate store. To use it, you need to read it from there first:

$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert |
          Out-GridView -Title 'Select Certificate' -OutputMode Single 

To sign a single script, run this line:

$Path = "C:\path\to\your\script.ps1"

Set-AuthenticodeSignature -Certificate $cert -FilePath $Path 

If you want to sign with a timestamped signature, use this line instead:

Set-AuthenticodeSignature -Certificate $cert -TimestampServer http://timestamp.digicert.com -FilePath $Path  

Timestamped signatures remain valid even when the certificate used for signing has expired.

To sign many scripts, use Get-ChildItem and pipe the files into Set-AuthenticodeSignature. This line would sign all PowerShell scripts stored in your user profile:

Get-ChildItem -Path "$home\Documents" -Filter *.ps1 -Include *.ps1 -Recurse |
Set-AuthenticodeSignature -Certificate $cert 

Once you have signed scripts, use Get-AuthenticodeSignature anytime you want to check the integrity of the signature:

Get-ChildItem -Path "$home\Documents" -Filter *.ps1 -Include *.ps1 -Recurse |
Get-AuthenticodeSignature 

psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!