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:

  1. Authenticity: Ensures the script originates from a trusted source.
  2. Integrity: Detects tampering or unauthorized modifications.
  3. Execution Policy Compliance: Scripts must be signed in environments with restrictive policies like AllSigned.

PowerShell Script Signing Overview

To sign a PowerShell script:

  1. Obtain or generate a code-signing certificate.
  2. 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:

  1. Unrestricted: No signing required.
  2. RemoteSigned: Only remote scripts must be signed.
  3. 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:

  1. Open the Certificates MMC (certmgr.msc).
  2. Navigate to Personal > Certificates.
  3. Right-click the certificate and select Export.
  4. 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.

Leave a Reply