Signing Powershell scripts

Published 16 February 11 10:08 PM | MartinBell

I wanted to write a post on signing Powershell scripts, but doing a few internet searches found this article. Which is great if you have a certificate store, and this is the recommended method, but using a certificate store is not always an available option. There are several alternate methods to create a certificate and I found this method that used makecert. Makecert should be available if you have installed the Windows SDK, or it can be downloaded with the SDK at http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx. I noticed a couple of issues with the code snippet; it has the wrong algorithm (sh1 instead of sha1) and the certificate file should be specified as the –ic  option and not –c. This was reported and hopefully it will be corrected. Another issue running the script is that it assumes that makecert.exe is on the PATH or in the current directory. I came up with the following script that will search for an instance of makecert.exe and then run it.

$pvk = "C:\powershell\root.pvk"
$cer = "C:\powershell\root.cer"
Remove-Item $pvk, $cer -ErrorAction:SilentlyContinue
$file = @(get-psdrive -p "FileSystem" | % {get-childitem $_.Root -include makecert.exe -r -ErrorAction:SilentlyContinue })[0]
& $file.fullName -n "CN=MyRoot" -a sha1 -eku 1.3.6.1.5.5.7.3.3 -r -sv $pvk $cer -ss Root -sr CURRENTUSER
& $file.fullName -pe -n "CN=MyCertificate" -ss MY -a sha1 -eku 1.3.6.1.5.5.7.3.3 -iv $pvk -ic $cer

Another change I made was to the Subject's certificate store location (-sr option) from localhost to CURRENTUSER. Without this change I got permissions errors that gave the error:

Error: Save encoded certificate to store failed => 0x5 (5)
Failed

when the command was run. The certificate will still be installed, but it won’t be trusted and so can’t be used to sign scripts.

When the script works correctly you will be prompted with three dialogs for various passwords. You will also be asked to confirm that you wish to install the certificate as the certification authority can not be confirmed: 

 

To see if the certificate installed correctly use the command:

get-childitem cert:\CurrentUser\My -codesigning

You should see something like:

Directory: Microsoft.PowerShell.Security\Certificate::CurrentUser\My

Thumbprint                                                        Subject
----------                                                              -------
2950019745D88A46C94B46A06571EA3E4522F4B4 CN=MyCertificate 

You can also view the certificate with certmgr




By ckicking on the certificate you can view the details:



To sign the script you can run something like:

$cert = @(gci cert:\currentuser\my -codesigning)[0]
$script = "C:\powershell\script.ps1"
Set-AuthenticodeSignature $script $cert

When this script is run the output will be something like:

    Directory: C:\powershell


SignerCertificate                                                   Status Path
-----------------                                                        ------    ----
3DE67752A34AB7980FAF4AE58A2788DE511C8801  Valid   script.ps1

If the look at script.ps1 file you will see the signature appended to the file. To test the script change the execution policy to allsigned. To check the execution policy use the command:

Get-ExecutionPolicy

If the policy needs setting use the command:

Set-ExecutionPolicy –executionpolicy AllSigned –Force

Scripts will then only execute if they are signed (so do this AFTER after signing the script!). If you don’t sign the script you will get an error message like:

File C:\powershell\script.ps1 cannot be loaded. The file C:\powershell\script.ps1 is not digitally signed. The script will not exec
ute on the system. Please see "get-help about_signing" for more details..
At line:1 char:25
+ C:\powershell\script.ps1 <<<<
    + CategoryInfo          : NotSpecified: (:) [], PSSecurityException
    + FullyQualifiedErrorId : RuntimeException

Because this is a self-signed certificate you will be prompted when the script is run as to whether it is trustworthy e.g.



or for Powershell ISE



If you reply to Always run scripts with this certificate, then any script that is signed using this certificate will run without re-prompting the user.

Filed under:

Comments

# Dew Drop – February 17, 2011 | Alvin Ashcraft's Morning Dew said on February 17, 2011 12:39 PM:

Pingback from  Dew Drop &ndash; February 17, 2011 | Alvin Ashcraft&#039;s Morning Dew

# Martin Bell (MartinBell) posts Signing Powershell scripts | sqlmashup said on February 18, 2011 03:04 PM:

Pingback from  Martin Bell (MartinBell) posts Signing Powershell scripts | sqlmashup

This Blog

SQL Blogs

Syndication