This is a Follow-up on the previous Blog Post here, on a new Dev machine
If you’re running PowerShell scripts like npm.ps1
and encounter this error:
A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
You’re not alone. This issue is common in environments where PowerShell’s execution policy is set to AllSigned
. Fortunately, you can fix it by signing PowerShell scripts locally using a self-signed certificate.
In this guide, I’ll walk you through the entire process — from generating a certificate to signing and trusting the script — all without requiring internet access or external tools.
🔍 What Causes the “Untrusted Certificate” PowerShell Error?
PowerShell’s execution policies (such as AllSigned
or RemoteSigned
) are designed to prevent untrusted or unsigned scripts from running. If a script is digitally signed, but the signing certificate isn’t trusted by your machine, PowerShell will block it — even if the file is from a trusted source like Node.js.
This is common with files like:
C:\Program Files\nodejs\npm.ps1
You can check your current execution policy with:
Get-ExecutionPolicy -List
If it’s set to AllSigned
, all scripts must have a trusted digital signature.
🔐 Step-by-Step: Sign PowerShell Scripts Locally (and Make Them Trusted)
✅ Step 1: Create a Self-Signed Code-Signing Certificate
Run this PowerShell command to create a certificate for local script signing:
New-SelfSignedCertificate `
-CertStoreLocation Cert:\CurrentUser\My `
-Subject "CN=Local Code Signing" `
-KeyUsage DigitalSignature `
-Type CodeSigningCert
This creates a code-signing certificate in your Current User certificate store.
🏢 Step 2: Trust the Certificate on Your Local Machine
To avoid trust errors when running signed scripts, you must add the certificate to both:
- Trusted Root Certification Authorities
- Trusted Publishers
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Where-Object {
$_.Subject -like "*Local Code Signing*"
}
# Add to Trusted Root
$storeRoot = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "CurrentUser"
$storeRoot.Open("ReadWrite")
$storeRoot.Add($cert)
$storeRoot.Close()
# Add to Trusted Publishers
$storeTrusted = New-Object System.Security.Cryptography.X509Certificates.X509Store "TrustedPublisher", "CurrentUser"
$storeTrusted.Open("ReadWrite")
$storeTrusted.Add($cert)
$storeTrusted.Close()
🖊️ Step 3: Sign the PowerShell Script File
Use Set-AuthenticodeSignature
to sign the .ps1
file you want to trust.
For example, to sign npm.ps1
:
# Unblock the file first (if needed)
Unblock-File "C:\Program Files\nodejs\npm.ps1"
# Sign it using the local certificate
Set-AuthenticodeSignature `
-FilePath "C:\Program Files\nodejs\npm.ps1" `
-Certificate $cert
You should see a result like:
Status : Valid
StatusMessage : Signature verified.
🧪 Step 4: Test the Script
Run the script to ensure it executes without any trust issues:
npm -v
If everything is configured correctly, PowerShell will now allow the signed script to run even under strict policies.
🧯 Optional: Trust the Certificate for All Users (Machine-Wide)
If you want all users on the machine to trust your signing certificate:
- Export the certificate:
Export-Certificate -Cert $cert -FilePath "C:\Temp\LocalCodeSigning.cer"
- Open certlm.msc (Local Machine Certificates).
- Import the
.cer
file into:- Trusted Root Certification Authorities
- Trusted Publishers
This ensures that your signed scripts are trusted system-wide.
🚀 Benefits of Locally Signed PowerShell Scripts
- ✅ Run signed scripts without policy errors.
- ✅ Maintain compliance with
AllSigned
orRemoteSigned
execution policies. - ✅ Avoid bypassing execution policy with insecure workarounds.
- ✅ Increase trust and traceability in automation environments.
🧠 Final Thoughts
Strict PowerShell execution policies are there to protect you — but they don’t have to be a roadblock. With a local code-signing certificate and a few simple steps, you can securely run trusted PowerShell scripts on your machine or across your organization.