So you received the dreaded:
npm : File C:\Program Files\nodejs\npm.ps1 cannot be loaded. The file C:\Program Files\nodejs\npm.ps1 is not digitally signed. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
how do we properly fix the issue?
Signing PowerShell scripts is a crucial step for ensuring their authenticity and integrity, particularly in environments that enforce execution policies like AllSigned
or RemoteSigned
. This guide covers both the older method using MakeCert
and the modern approach using New-SelfSignedCertificate
.
Why Sign PowerShell Scripts?
Signing scripts is essential for:
- Authenticity: Ensures the script originates from a trusted source.
- Integrity: Detects tampering or unauthorized modifications.
- Execution Policy Compliance: Scripts must be signed in environments with restrictive policies like
AllSigned
.
PowerShell Script Signing Overview
To sign a PowerShell script:
- Obtain or generate a code-signing certificate.
- Use
Set-AuthenticodeSignature
to sign the script with the certificate.
The key difference between the old and modern methods lies in how the certificate is generated.
The Old Method: Using MakeCert
MakeCert
was a widely used tool for generating certificates, but it has since been deprecated. Here’s how to use it to create a self-signed certificate and sign a PowerShell script.
Step 1: Generate a Self-Signed Certificate
Run the following MakeCert
command to create a certificate:
cmd codemakecert -r -pe -n "CN=PowerShell Local Certificate Root" -ss My -eku 1.3.6.1.5.5.7.3.3 -sky signature -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24
-r
: Creates a self-signed certificate.-pe
: Marks the private key as exportable.-n
: Specifies the subject name (e.g., “PowerShell Local Certificate Root”).-ss My
: Stores the certificate in the current user’s Personal store.-eku 1.3.6.1.5.5.7.3.3
: Sets the certificate usage to code signing.
Step 2: Find the Certificate – by Testing
Use the following PowerShell command to locate the certificate:
powershell codeGet-ChildItem Cert:\CurrentUser\My -CodeSigningCert
Once run you should see a response similar to this:
PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My
Thumbprint Subject
---------- -------
59C259FFAE7EB79297CB7AB11F72EF1E04FC5425 CN=PowerShell User
Step 3: Sign the Script
Run this command to sign the script:
powershell codeSet-AuthenticodeSignature -FilePath "C:\Path\To\YourScript.ps1" -Certificate @(Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0]
The New Method: Using New-SelfSignedCertificate
New-SelfSignedCertificate
is the modern replacement for MakeCert
. It simplifies the certificate creation process and integrates directly with PowerShell.
Step 1: Generate a Self-Signed Certificate
Run the following PowerShell command:
powershell codeNew-SelfSignedCertificate -DnsName "PowerShell Local Certificate Root" -CertStoreLocation Cert:\CurrentUser\My -Type CodeSigningCert
-DnsName
: Specifies the subject name for the certificate.-CertStoreLocation
: Defines the store where the certificate will be saved (e.g.,Cert:\CurrentUser\My
).-Type CodeSigningCert
: Indicates the certificate is for code signing.
Step 2: Find the Certificate
Locate the certificate with:
powershell codeGet-ChildItem Cert:\CurrentUser\My -CodeSigningCert
Step 3: Sign the Script
Sign the script using the certificate:
powershell codeSet-AuthenticodeSignature -FilePath "C:\Path\To\YourScript.ps1" -Certificate @(Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0]
Verifying the Script Signature
To verify the signature of a signed script:
powershell codeGet-AuthenticodeSignature -FilePath "C:\Path\To\YourScript.ps1"
This command returns the signature status:
- Valid: The script is signed and trusted.
- UnknownError: The script is signed but not trusted.
- NotSigned: The script has no signature.
Configuring Execution Policies
PowerShell’s execution policies determine how scripts are executed:
- Unrestricted: No signing required.
- RemoteSigned: Only remote scripts must be signed.
- AllSigned: All scripts must be signed.
To set the policy:
powershellCopy codeSet-ExecutionPolicy -ExecutionPolicy AllSigned -Scope CurrentUser
Check the current policy with:
powershellCopy codeGet-ExecutionPolicy -List
Exporting Certificates for Distribution
If the signed script will be shared, the recipient must trust the signing certificate. This is not necessary if this is only to be used locally, else the domain admin would issue a certificate.
Export the Certificate:
- Open the Certificates MMC (
certmgr.msc
). - Navigate to Personal > Certificates.
- Right-click the certificate and select Export.
- Export as a
.CER
file (without the private key).
Import the Certificate:
The recipient can import the certificate using:
powershellCopy codeImport-Certificate -FilePath "C:\Path\To\Certificate.cer" -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
Migrating from MakeCert to New-SelfSignedCertificate
Since MakeCert
is deprecated, transitioning to New-SelfSignedCertificate
is strongly recommended. The modern cmdlet is easier to use, integrates seamlessly with PowerShell, and offers robust options for certificate management.
Common Issues and Troubleshooting
1. Error: “Certificate not trusted”
Ensure the certificate is imported into the TrustedPublisher
store:
powershellCopy codeImport-Certificate -FilePath "C:\Path\To\Certificate.cer" -CertStoreLocation Cert:\CurrentUser\TrustedPublisher
2. Error: “Execution Policy does not allow this script to run”
Adjust the execution policy:
powershellCopy codeSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
3. Error: “Cannot resolve certificate path”
Ensure the certificate exists in the store:
powershellCopy codeGet-ChildItem Cert:\CurrentUser\My -CodeSigningCert
Conclusion
Script signing is an essential practice for securing PowerShell scripts in production environments, but even just for us developers. The modern New-SelfSignedCertificate
cmdlet provides a streamlined and powerful alternative to the deprecated MakeCert
. By following this guide, you can sign your scripts securely, comply with execution policies, and enhance trustworthiness in your PowerShell environment. Sadly there is more to this all then meets the eye, but this will enable you as developer to continue working without much a do.