I was trying to figure out how to sign PowerShell scripts with a self-signed certificate. This is a simple step-by-step guide on how you can provision your own certificate for testing and sign and verify PowerShell scripts.
If you plan to use a publicly trusted code signing certificate, this is however not the exact process as you should be using an HSM to secure your certificate.
Step by Step Guide
- First, create a private key (in bash):
openssl genrsa -out codesign.key 4096
- Create a configuration file named
codesign.cnf
with the certificate details:
[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = YourState
L = YourCity
O = YourOrganization
OU = YourDepartment
CN = YourName
[v3_req]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
Remember to adjust the certificate details in the configuration file (codesign.cnf) to match your information.
- Generate private key and certificate (in bash):
# Generate private key
openssl genrsa -out codesign.key 4096
# Create certificate with extensions
openssl req -new -x509 -key codesign.key -out codesign.crt -config codesign.cnf -days 365 -extensions v3_req
# Create PFX with private key (you'll be prompted for a password - remember it!)
openssl pkcs12 -export -out codesign.pfx -inkey codesign.key -in codesign.crt
- Import certificate (in PowerShell):
# Import the certificate (replace "pass" with the password you set)
Import-PfxCertificate -FilePath codesign.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String "pass" -Force -AsPlainText)
# Verify it's imported and shows as a code signing cert
Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
- Export public certificate and add to root store:
# Export public certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object {$_.Subject -like "*Unic AG*"} | Select-Object -First 1
Export-Certificate -Cert $cert -FilePath "codesign_public.cer"
# Import to root store (requires admin privileges)
Import-Certificate -FilePath "codesign_public.cer" -CertStoreLocation Cert:\LocalMachine\Root
- Now you can sign PowerShell scripts. Here’s an example:
# Script path
$scriptPath = "D:\codesign\signme.ps1"
# Get the certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object {$_.Subject -like "*YourName*"} | Select-Object -First 1
# Sign the script
Set-AuthenticodeSignature -FilePath $scriptPath -Certificate $cert
Example
Set-AuthenticodeSignature -FilePath $scriptPath -Certificate $cert
Directory: D:\codesign
SignerCertificate Status StatusMessage Path
----------------- ------ ------------- ----
22B58180A93B5062C97258A382646741604F8BAA Valid Signature verified. signme.ps1
To verify the signature on a script:
Get-AuthenticodeSignature -FilePath "D:\codesign\signme.ps1"
Directory: D:\codesign
SignerCertificate Status StatusMessage Path
----------------- ------ ------------- ----
22B58180A93B5062C97258A382646741604F8BAA Valid Signature verified. signme.ps1