Signing Your PowerShell Scripts

Purpose

You receive the following error when attempting to run a custom PowerShell Scanner in PDQ Inventory or a PowerShell step in PDQ Deploy:

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.

Background

Like all PowerShell scripts, the scripts run by PDQ Inventory and PDQ Deploy are subject to your organization's script execution policies. PDQ Inventory will attempt to run scripts with the -Bypass flag, but if your organization has set an execution policy of AllSigned through Group Policy then you will still need to sign your scripts for them to run successfully.

Resolution

If you have an existing certificate authority within Active Directory, you can create and use a certificate there by creating a certificate request to that certificate authority. This requires both Domain Admin and Enterprise Admin access and for the Certification Authority role to be installed and configured on a server within your domain. Although a domain certificate authority offers an extra level of security and manageability to your certificates, doing so may not be available to all administrators and so we have chosen to demonstrate the creation of a self-signed certificate here.

To sign your scripts with a self-signed certificate, you will first need to create the script-signing certificate to sign with. This can be done using PowerShell. The following script will create a certificate and export the .cer file into your Documents folder as Scanner.cer. This certificate will be valid for one year from the moment it is created by default, but you can also use the -NotBefore and -NotAfter parameters in the first line if you'd like to specify a start and end date for the certificate's validity.

$cert = New-SelfSignedCertificate -Subject "CN=CustomScannerCert" -Type CodeSigningCert -CertStoreLocation "Cert:\CurrentUser\My"
Export-Certificate -Cert $cert -FilePath "$env:homepath\Documents\Scanner.cer" -Type CERT

Once this certificate has been created, you can sign you script with the certificate using this line of PowerShell:

Set-AuthenticodeSignature <path to your script's ps1 file> @(Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert)[0]

That line of code will sign your script with the first code signing certificate found in the Cert:\CurrentUser\My certificate store, so if you have created multiple code signing certificates you will want to filter those results to ensure that the correct certificate is being used. If successful, you should see a signature block at the end of your script like this:

mceclip0.png

Now that the script has been signed, the only thing left to do is to install the certificate on your target machines. This is usually best done through Group Policy. You will want to import your certificate into both of the following locations within Group Policy to allow it to run without prompting for confirmation:

Computer Configuration > Policies > Windows Settings > Security Settings > Public Key Policies > Trusted Root Certification Authorities
Computer Configuration > Policies > Windows Settings > Security Settings > Public Key Policies > Trusted Publishers

Here is what the policy should look like:

mceclip1.png

Once the certificate has been imported into both of those locations and the group policy has been applied to your target machines, your custom PowerShell script should run correctly with any configured execution policy other than Restricted.

See Also

Article - All Signed PowerShell Execution Policy

Was this article helpful?
Still have a question or want to share what you have learned? Visit our Community Discord to get help and collaborate with others.