How to Sign PowerShell Scripts
PowerShell can prevent accidental or untrusted script execution by checking whether a script has a valid digital signature. Signing a script sounds complicated, but the basic workflow is small: get a code-signing certificate, sign the .ps1 file, then verify the signature.
This is useful when you run scripts with AllSigned, share internal admin scripts, or want a visible integrity check before execution.
1. Get a Code-Signing Certificate
For production, use a certificate from your company CA or a trusted certificate authority. For local testing, you can create a self-signed certificate:
$cert = New-SelfSignedCertificate `
-Type CodeSigningCert `
-Subject "CN=PowerShell Code Signing" `
-CertStoreLocation Cert:\CurrentUser\My
You can list available code-signing certificates like this:
Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
2. Trust a Self-Signed Certificate Locally
A self-signed certificate is not trusted automatically. For local use, export it and import it into the trusted stores of the current user:
Export-Certificate `
-Cert $cert `
-FilePath "$env:TEMP\PowerShell-CodeSigning.cer"
Import-Certificate `
-FilePath "$env:TEMP\PowerShell-CodeSigning.cer" `
-CertStoreLocation Cert:\CurrentUser\Root
Import-Certificate `
-FilePath "$env:TEMP\PowerShell-CodeSigning.cer" `
-CertStoreLocation Cert:\CurrentUser\TrustedPublisher
For shared scripts, prefer a certificate issued by a real internal CA instead of trusting a self-signed certificate on every machine.
3. Sign the Script
Pick a certificate and sign the script with Set-AuthenticodeSignature:
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert |
Sort-Object NotAfter -Descending |
Select-Object -First 1
Set-AuthenticodeSignature `
-FilePath .\Deploy.ps1 `
-Certificate $cert `
-TimestampServer "http://timestamp.digicert.com"
The timestamp is optional, but recommended. It proves the script was signed while the certificate was still valid.
4. Verify the Signature
After signing, check the result:
Get-AuthenticodeSignature .\Deploy.ps1 | Format-List
A healthy result should show:
Status : Valid
If the script is changed after signing, the signature becomes invalid and the file must be signed again.
5. Require Signed Scripts
To require signatures for all scripts in the current user scope:
Set-ExecutionPolicy -Scope CurrentUser AllSigned
A less strict option is RemoteSigned, which requires downloaded scripts to be signed but allows locally created scripts.
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Complete Example
# Create a local test certificate
$cert = New-SelfSignedCertificate `
-Type CodeSigningCert `
-Subject "CN=PowerShell Code Signing" `
-CertStoreLocation Cert:\CurrentUser\My
# Trust it locally
Export-Certificate -Cert $cert -FilePath "$env:TEMP\PowerShell-CodeSigning.cer"
Import-Certificate -FilePath "$env:TEMP\PowerShell-CodeSigning.cer" -CertStoreLocation Cert:\CurrentUser\Root
Import-Certificate -FilePath "$env:TEMP\PowerShell-CodeSigning.cer" -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
# Sign a script
Set-AuthenticodeSignature `
-FilePath .\Deploy.ps1 `
-Certificate $cert `
-TimestampServer "http://timestamp.digicert.com"
# Verify it
Get-AuthenticodeSignature .\Deploy.ps1 | Format-List
Common Pitfalls
- Editing the script after signing invalidates the signature.
- A self-signed certificate must be trusted on every machine that should run the script.
AllSigneddoes not make unsafe code safe; it only verifies who signed the file and whether it changed.- For team or production use, use an internal CA or a proper code-signing certificate.
Script signing is not about hiding code. It is about trust and integrity: who signed this script, and has it changed since then?