Digitally Signing PowerShell Scripts

In the previous tips you learned how you can create a self-signed code signing certificate, save it to a PFX file, and read it back into memory.

Today, assuming that you have a PFX file with a code signing certificate by now, we’ll look at how PowerShell scripts can be digitally signed.

The below code searches for all PowerShell scripts in your user profile, and if the scripts do not have a digital signature yet, they get a fresh new digital signature using a certificate read in from a PFX file:

# read in the certificate from a pre-existing PFX file
$cert = Get-PfxCertificate -FilePath "$env:temp\codeSignCert.pfx"

# find all scripts in your user profile...
Get-ChildItem -Path $home -Filter *.ps1 -Include *.ps1 -Recurse -ErrorAction SilentlyContinue |
# ...that do not have a signature yet...
Where-Object {
  ($_ | Get-AuthenticodeSignature).Status -eq 'NotSigned'
  } |
# and apply one
# (note that we added -WhatIf so no signing occurs. Remove this only if you
# really want to add digital signatures!)
Set-AuthenticodeSignature -Certificate $cert -WhatIf

When you look at these scripts in your editor, you’ll see a new comment block at the end of the script. It contains the script hash code, encrypted with the private key of your certificate. It also contains the public part of your certificate.

When you right-click a signed script file and choose “Properties”, you can now see who signed the script. If you really do trust that person, you can install their certificate into your trusted root certificates.

Once scripts are digitally signed, it becomes very easy to audit script status. Signatures tell you who signed a script, and whether or not the content of that script is still untampered. Below code checks all PowerShell scripts in your user profile and displays the signature status:

# find all scripts in your user profile...
Get-ChildItem -Path $home -Filter *.ps1 -Include *.ps1 -Recurse -ErrorAction SilentlyContinue |
# ...and check signature status

If you receive “UnknownError”, then this is not an unknown error. Rather, it indicates that the script is untouched but the signer is unknown (and untrusted) on your system.

Twitter This Tip! ReTweet this Tip!