How to fix PowerShell “file is not digitally signed” error

Attempting to execute a PowerShell script copied from a different machine throws “the file is not digitally signed. You cannot run this script on the current system.”

Screenshot - PowerShell - the file is not digitally signed.  You cannot run this script on the current system

Fix 1 – change the execution policy

The fix is to use Set-ExecutionPolicy to set the ExecutionPolicy to suppress all messages and allow execution of copied scripts for this session only.  Of course this requires Administrator privileges.

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

PowerShell supports a concept called “execution policies” in order to provide a more secure command line administration experience.  Execution policies define the restrictions under which PowerShell loads files for execution and configuration.  By default, the mode is set to Restricted which prohibits PowerShell from loading configuration files or running scripts.

The Scope parameter specifies the scope of the execution policy.  Possible values are:

  • Process: The execution policy affects only the current Windows PowerShell process.
  • CurrentUser: The execution policy affects only the current user.
  • LocalMachine: The execution policy affects all users of the computer.

Possible values for the -ExecutionPolicy parameter:

  • Restricted: The default setting which does not load configuration files or run scripts.
  • AllSigned: Requires that all scripts and configuration files be signed by a trusted publisher, including scripts that you write on the local computer.
  • RemoteSigned: Requires that all scripts and configuration files downloaded from the Internet be signed by a trusted remote publisher.
  • Unrestricted: Loads all configuration files and runs all scripts. If you run an unsigned script that was downloaded from the Internet, you are prompted for permission before it runs.
  • Bypass: Nothing is blocked and there are no warnings or prompts.
  • Undefined: Removes the currently assigned execution policy from the current scope, returning the session to the default.  This parameter will not remove an execution policy that is set in a Active Directory Group Policy.

Fix 2 – sign the PowerShell script with a self-signed certificate

For production environments, AllSigned is best which means you’ll need to add a digital signature to the script.  You can create and use a self-signed certificate (use makecert.exe to create the certificate) which will then need to be installed on the machine you copy the script to.

Begin by opening MMC and adding the Certificates Snap-in (add the Snap-in for your account only).

Next, start an Administrator command line.  Run makecert (part of the Windows SDK and Visual Studio toolkits) from the command line using the following options.  You won’t be able to create the root.pvk private key file in the directory unless you run the command line ad Administrator (nor will makecert be able to add the cert to the store).

makecert -n “CN=PowerShell Local Root Certificate” -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv root.pvk root.cer -ss Root -sr localMachine

The options specified in the makecert command are:

-n The certificate name.  It must conform to the X.500 standard so “CN=” is required.

-a The signature algorithm. sha1 is the default but you may also specify md5, sha256, sha384, or sha512.

-eku inserts a OID (enhanced key usage object identifier) into the certificate.  An OID is a dotted decimal string that uniquely identifies an object class or attribute.

-r Creates a self-signed cert

-sv the .pvk private key file (it is created if it does not exist)

-ss The certificate store name that will store the output certificate.

-sr The certificate store location (can be “currentuser” or “localmachine”).

You will be prompted to create a private key password.  Make up a password and remember it.

makecert.exe - enter private key password

 

 

Next you will be prompted to re-enter the private key password from above.

makecert.exe - re-enter private key password

 

You should receive a “Succeeded” response. If you receive an error stating that the cert could not be added to the key store, it is likely that you did not start the Command prompt as an Administrator user.

Go back to MMC and check under Certificates –> Trusted Root Certification Authorities –> Certificates.  You should see the new PowerShell Local Root Certificate.

PowerShell Local Root Certificate in the Trusted Root Certification Authorities (for code signing)

 

Next we need to create a certificate in the Personal store.  From the Command line, run makecert using the following parameters:

makecert -pe -n “CN=PowerShell User” -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv root.pvk -ic root.cer

The options provided in this instance are:

-pe Marks the private key as exportable so it can be included in the certificate.

-n The certificate name.  It must conform to the X.500 standard so “CN=” is required.

-ss The certificate store name that will store the output certificate.

-a The signature algorithm. sha1 is the default but you may also specify md5, sha256, sha384, or sha512.

-eku inserts a OID (enhanced key usage object identifier) into the certificate.  An OID is a dotted decimal string that uniquely identifies an object class or attribute.

-iv Specified the .pvk private key file

-ic Specifies the issuer’s certificate file

You will be prompted for the private key password again (created above).

makecert.exe - re-enter private key password

 

You should receive a “Succeeded” response.

Go back to MMC and ensure the PowerShell User certificate was created in the Personal store (you may have to right-click and choose Refresh).

PowerShell User certificate in the Personal store

 

From a PowerShell console, you can issue the following command to see the certificate (certificate information is stored in C:\Documents and Settings\[username]\Application Data\Microsoft\SystemCertificates\My\).

Get-ChildItem cert:\CurrentUser\My -codesign

Here’s a screenshot of the result.

Result of Get-ChildItem cert:\CurrentUser\My -codesign command in PowerShell console

 

Since the certificate information is stored in C:\Documents and Settings\[username]\Application Data\Microsoft\SystemCertificates\My\, you can delete the root.pvk and root.cer files that were created from makecert.

Sign and test the newly signed PowerShell script

Begin by making sure the PowerShell execution policy requires all scripts be signed.  From a PowerShell command line (must be run as Administrator in order to change the system execution policy), run the following to set the execution policy to AllSigned.

Set-ExecutionPolicy AllSigned

Respond to the warning about changing the execution policy.

Attempt to run your unsigned script.  You should receive an error stating the script was not digitally signed and the script will not run.

File C:\PATH\FILENAME.ps1 cannot be loaded. The file

C:\PATH\FILENAME.ps1 is not digitally signed. You cannot run this script on

the current system. For more information about running scripts and setting execution policy, see

about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.

+ CategoryInfo          : SecurityError: (:) [], ParentContainsErrorRecordException

+ FullyQualifiedErrorId : UnauthorizedAccess

Next, from the PowerShell command line, sign the script using the following command.

Set-AuthenticodeSignature “C:\PATH\FILENAME.ps1” @(Get-ChildItem cert:\CurrentUser\My -codesign)[0]

PowerShell will respond with details about the certificate.

Directory: C:\PATH

SignerCertificate                         Status                               Path
—————–                         ——                               —-
CD1C8A995487758C0752437BDAA97A383E1A27B5  Valid                                Capture machine status.ps1

The command will modify the script and append the signature block to the end of the script.  If the script is already loaded in PowerShell, reload the script and examine the last lines of the file.  It will look simliar to this:

# SIG # Begin signature block

# MIIEMwYJKoZIhvcNAQcCoIIEJDCCBCACAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB

# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR

# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU6vQAn5sf2qIxQqwWUDwTZnJj

…snip…

# m5ugggI9MIICOTCCAaagAwIBAgIQyLeyGZcGA4ZOGqK7VF45GDAJBgUrDgMCHQUA

# Dxoj+2keS9sRR6XPl/ASs68LeF8o9cM=

# SIG # End signature block

Attempt to run the script again.  You will be prompted whether to run once, run always, or not run.  If you select Always run, you will not be prompted again for this script (on this machine).

Powershell prompting whether or not to run the signed PowerShell script

 

 

Note that any changes made to the file after it was signed will require that you re-sign the file.

File C:\PATH\FILE.ps1 cannot be loaded. The contents of file
C:\PATH\FILE.ps1 might have been changed by an unauthorized user or
process, because the hash of the file does not match the hash stored in the digital signature. The script cannot
run on the specified system. For more information, run Get-Help about_Signing..
+ CategoryInfo : SecurityError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnauthorizedAccess

 

Print Friendly, PDF & Email

Leave a Reply