rss logo

Enable and Run Signed PowerShell Scripts in Windows

PowerShell logo

By default, PowerShell can restrict script execution depending on the configured execution policy. While the -ExecutionPolicy Bypass option can temporarily bypass these restrictions, it is not the most secure approach.

In this guide, we will configure Windows to allow only signed PowerShell scripts, create a self-signed code-signing certificate, use it to sign a PowerShell script, import the certificate into the appropriate certificate stores, and verify the script signature before execution.

Group Policy to allow signed scripts only

  • Open the Group Policy editor:
Open the Run dialog and type gpedit.msc to access the Group Policy Editor in Windows.
  • Go to Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell:
View of the Local Group Policy Editor highlighting the 'Turn on Script Execution' setting under Windows PowerShell options.
  • Edit the Turn on Script Execution policy:
Group Policy Editor window with the Turn on Script Execution setting enabled and Allow only signed scripts selected as the execution policy

Create Certificate

To sign our scripts, we need a certificate. Here's how to create a self-signed certificate.

  • Open Windows PowerShell as administrator:
Windows menu showing the Run as administrator option for PowerShell
  • Set a name for your new certificate in the variable $CertificateName:
PS C:\Users\Administrator\Desktop> $CertificateName = "STD Certificate"
  • Define where you want to create your certificate:
PS C:\Users\Administrator\Desktop> $OutPutPFXFilePath = "C:\Users\administrator\Desktop\MyNewSigningCertificate.pfx"
  • Set a password for the PFX file:
PS C:\Users\Administrator\Desktop> $MyStrongPassword = ConvertTo-SecureString -String "MyPassword" -Force -AsPlainText
  • Finally, create the certificate with a lifetime of 10 years and a key size of 4096 bits:
PS C:\Users\Administrator\Desktop> New-SelfSignedCertificate -subject $CertificateName -Type CodeSigning -NotAfter (Get-Date).AddYears(10) -KeyLength 4096 | Export-PfxCertificate -FilePath $OutPutPFXFilePath -password $MyStrongPassword

Sign the script

  • Load the certificate:
PS C:\Users\Administrator\Desktop> $MyCertFromPfx = Get-PfxCertificate -FilePath 'C:\Users\administrator\Desktop\MyNewSigningCertificate.pfx'
Enter password : ********
  • Signing the script:
PS C:\Users\Administrator\Desktop> Set-AuthenticodeSignature -PSPath 'C:\Users\administrator\Desktop\script.ps1' -Certificate $MyCertFromPfx

💡 Note: The Valid status confirms that the script has been successfully signed. The signing certificate must still be trusted on each computer where the script will be executed.

PowerShell command output for signing a script with Set-AuthenticodeSignature

Import the certificate

To be correctly recognized, a self-signed certificate must be imported on the computers on which we want to run the PowerShell scripts. Type the following commands with administrator rights.

Set variables

  • Set the PFX password and certificate path:
PS C:\Users\Administrator\Desktop> $MyStrongPassword = ConvertTo-SecureString -String "MyPassword" -Force -AsPlainText
PS C:\Users\Administrator\Desktop> $CertPath = "C:\Users\administrator\Desktop\MyNewSigningCertificate.pfx"

Import to Trusted Root Certification Authorities store

  • Import the certificate into the Trusted Root Certification Authorities local computer store:
PS C:\Users\Administrator\Desktop> Import-PfxCertificate -FilePath $CertPath "cert:\LocalMachine\Root" -Password $MyStrongPassword
Trusted Root Certification Authorities with a highlighted certificate for code signing

Import to Trusted Publishers store

  • Import the certificate to the Trusted Publishers local computer store:
PS C:\Users\Administrator\Desktop> Import-PfxCertificate -FilePath $CertPath "cert:\LocalMachine\TrustedPublisher" -Password $MyStrongPassword
Trusted Publishers section with a highlighted code signing certificate

Verify the script signature

  • We can check whether the script is correctly signed using the Get-AuthenticodeSignature command:
PS C:\Users\Administrator\Desktop> Get-AuthenticodeSignature 'C:\Users\administrator\Desktop\script.ps1'
PowerShell command to validate script signature with a valid status
  • If the script has been altered after being signed, the HashMismacth status appears and the script cannot be executed:
PowerShell command showing a hash mismatch error while validating script signature

References