As I've been delivering Powershell training I often get asked how to use an enterprise PKI to sign Powershell scripts. It seems like almost all the articles out there shows how to use a self-signed certificate created with tools like makecert.exe from the .NET SDK.
In this article I will show you how to make the codesigning template available, and how to use it. As a prerequisite you need to have an Certificate Server available in your environment. My certificate server is an Windows Server 2008, and my client for this article is running Windows 7.
My PKI root is called pki.harper.labs, and is already trusted by my domain members.
My steps will be like this:
- Make the codesigning certificate template available on my issuing certificate server
- Request a codesigning certificate for my use.
- Sign my Powershell script and run it.
- Deploy the codesigning certificate as an trusted publisher through Active Directory
Step 1: Make the codesigning certificate available in my PKI environment
Let’s start with makeing the codesigning certificate available on the issuing Certificate Server, so that our certificate server will issue codesigning certificates. I do this at the issuing certificate server, and I start the Server Manager console, and open the Active Directory Certificate Services node.
We will start with a look at the code signing certificate template. You find the template in the Certificate Templates node right under the Enterprise PKI node. This is called the Certificate Templates snapin. (and if you want you can open it up as a standalone snap-in in Microsoft Management Console (mmc.exe).
I will not discuss how to create copies of the template here, so I will just use the existing certificate template. If you double click the code signing template, you will get another window with a few tabs.
As we are not creating a duplicate copy, we cannot change any of the values at the General tab. If we created a duplicate we could change those, for example, how long the certificate should be valid. The same goes for Request Handling, Subject Name and Extensions. If we wanted to change those, we had to create a duplicate.
What we will look at is the Security tab. We are interested in the permission to Enroll – who should be able to enroll for a code signing certificate.
I create a group in Active Directory called Codesigners, and I grant them the Enroll and Read permission
Then I make the users that should be able to get a code signing certificate member of this group.
I click OK, and continue to the make the certificate template available on my issuing certificate server.
Next I open up my Certificate Authority console (the node is named pki.harper.labs in my environment, and is found under the Certificate Templates node in the Server Manager, as show in the image below).
In the Certificate Authority console you also see a Certificate Templates node.
If you want to check if the code signing certificate template is available for enrollment, see if it is listed in the list.
If the code signing template does not show up, we will add it. Right click on the Certificate Templates node, and choose New –> Certificate Template to Issue .
From the list that appears select the code signing template, and click OK. This list is read from active directory, and if you just created the template, you might have to wait until it is replicated to all domain controllers.
We are now able to request a code signing certificate, and enroll the users we gave enroll permissions on the template.
Step 2: Request a codesigning certificate for my user
This step is done from my client computer, as a user that is member of the Codesigning group. I open the certificates snap-in through Microsoft Management Console (mmc.exe). Then I add the Certificates snapin through File->Add/Remove Snap-in:
Select Certificates from the list, and click Add, then click OK.
You want the snap-in to manage your user account, so select “My user account”:
Now you have loaded the snapin, let’s request a code signing certificate. Right click on Personal and choose All Tasks-> Request a new Certificate.
Just click Next on the first dialog box,
As we are requesting a certificate from our enterprise PKI, just make sure your select the Active Directory Enrollment Policy, and click Next.
Because we made the code signing template available in step 1, you should see the template for code signing available for enrollment. You only see the certificates you have permissions for in the list, so if the code signing template does not show up, have a closer look at the permissions. Go ahead and select the Code Signing certificate.
If you look at the details, you will see the validity period of the certificate (the default template is one year – or 365 days as the details says)
All the information that is needed to create the certificate is automatically configured, but if you want, you can change some of it if you click Properties.
For example. if you want to make the private key exportable so that you can export/import the private keys to other computers, you can configure this by clicking Properties, and on the “Private key” tab:
This is necessary if you want to use the same certificate on multiple computers.
When you are ready, you select click Enroll.
Just wait while the certificate is being generated and issued. If nothing went wrong, you should see a dialog box like this .
Just click Finish – you have now created a certificate for code signing!
Let’s continue with firing up Powershell, and signing our script!
Step 3: Sign my Powershell script and run it
In this step we will be inside Powershell, and we will sign our script. For this purpose I have a simple script named demoscript.ps1
demoscript.ps1
$yourName=Read-Host "What is your name?" Write-Host "Hello $yourName"
Just a quick recall that your requirements for signed scripts is set using the Set-ExecutionPolicy cmdlet (or by group policy.
| Setting | Description |
| Unrestricted | No requirements – all scripts allowed |
| RemoteSigned | All local scripts allowed – only signed remote scripts |
| AllSigned | All scripts needs to be signed |
| Restricted | No scripts allowed |
For this demonstration, my executionpolicy is set to AllSigned.
If I just try to run my script, it will fail:
We will use the cmdlet Set-AuthenticodeSignature to sign the script. I will start storing the code signing certificate in a variable named $cert.
$cert=(dir cert:currentuser\my\ -CodeSigningCert)
Then I am ready to sign my script with the Set-AuthenticodeSignature cmdlet.
As you see, the status is valid, so the signing was successfully done. Please note that I recommend that you supply the TimeStampServer parameter. This will make sure the script works even though the certificate that signed it is expired. It will tell the system that the code signing certificate was valid at the time of signing. (Ok, I could imagine there is some situations where this might not be correct, but I also guess it will be good enough for most of us). If you do not use the TimeStampServer parameter, then the script will stop to work when the certificate used for signing expires. There is multiple sources for timestamping out there, please use one that suites you.
So, let us try to run the scripts again, and see what happens:
We get a question if we want to run the script or not. The question says that this is a script from an untrusted publisher. In step 4 I will show you how to make the publisher (code signing certificate) trusted for your domain.
As for this computer you can now make this publisher trusted by choosing A for Always run. If you choose V for Never Run, you will explicitly make this publisher untrusted, and scripts signed by this certificate will not run.
Lets stop and see what exactly is happening here. If you make any choice persistent (like Always run or Never Run) the code signing certificate is stored as a Trusted or untrusted publisher on your computer. You can see this through the GUI if you open MMC.exe and load the Certificates snap-in.
Or, you could also do this from Powershell of course
dir cert:\CurrentUser\TrustedPublisher dir cert:\CurrentUser\Disallowed
As you will see in step 4 you can also control this setting through group policy.
For now, you can just click Run Once, and the script is allowed to execute.
If you open the script, you will see that the signature is attached at the bottom.
You can also use validate the signature using Get-Authenticode cmdlet:
In this step, I showed you how to sign a Powershell script, and also how to make it trusted or untrusted on your computer. In the next step we will make the code signing certificate used trusted in our domain using group policy.
Step 4: Make the codesigning certificate trusted in my domain
If you were to deploy this in your domain, you will probably use group policy to make sure the code signing certificate in use is a trusted publisher.
To do this there a two steps:
- Export the code signing certificate
- Create a policy and import the code signing certificate into trusted publishers
Export the code signing certificate
Let’s start with exporting the code signing certificate from the client computer where we requested the certificate.
Start the certificates snapin as shown in step 2 (start mmc.exe, add the certificates snap-in, and choose My User Account.
Open the personal node, and then certificates. In the content pane,you will now see your certificate. (The one with intended purpose set to Code Signing). Right Click the certificate, choose All Tasks, and then Export…
At the first dialog box just hit Next
At the second dialog box just hit Next (to make the certificate a trusted publisher we do not need the private key – only the public key).
Also hit Next on the third dialog box. We do not need to change this.
Make sure that you save the certificate somewhere you can access it from the computer you are going to run Group Policy Management on. There is no security risk making the public part of this certificate available, so you can store it wherever you want.
At the last dialog box, just hit Finish.
This finishes the export part from the client. Now we need to open up Group Policy Management. This is a part of the Server Administration tools, and is usually found if you have installed RSAT ( Remote Server Administration Tools) on your client, or on your domain controller. For this demonstration, I will run this from one of my domain controllers.
Create a policy and import the code signing certificate into trusted publishers
As I start the Group Policy Management tool, I start by creating a new policy. I open up my domain (harper.labs), and right click:
Choose Create a GPO in this domain, and link it here…
Please make sure that you create this GPO where you want it in your own domain. For this demonstration, I create it at the domain level.
I give the policy the name Certificates Policy, and I click OK.
Select the policy (Certificates Policy) in the navigation pane, and then right click and select Edit
Wait for the Group Policy Editor to start, and then open Computer Configuration->Policies->Windows Settings->Public Key Policies
You are now ready to start the import. Right click on Trusted Publishers, and choose Import…
At the dialog box that asks you for the certificate to import, please select the certificate you exported earlier. Then hit Next.
Make sure the certificate is placed in the Trusted Publishers store, and hit Next
Now finish the wizard by clicking Finish. You have imported the certificate as an trusted publisher.
You can confirm this by looking inside the Trusted Publisher node in the Group Policy Editor:
So, the next time the policy is updated on computers in your domain, they will add this certificate as a trusted publisher. You can now run scripts signed by this certificate without being asked if the certificate is trusted or not. You can also do the same with untrusted certificates is you want.
I will test this from my client computer. I will first make sure that the certificate is not in my trusted publishers list. This should be done through the certificates snap-in on my client.
Then I run gpupdate /force from my Powershell window:
When the update is finished successfully, I refresh the Trusted Publishers list in my Certificates snap-in. My certificate should now be listed as trusted.
I hope this helps – and have fun with Powershell!!
Thank you very much for your very thoughtful and considered comment. I approach the journey in very much the same way as you've described yours.
Posted by: Coach outlet | 09/07/2011 at 08:29 AM
A few of our testers told us that it was taking an unusually long time to do the initial installation of the app — up to four and half minutes.
Posted by: north face outlet | 12/16/2011 at 08:21 AM
Was totally stuck until I read this, now back up and rnuning.
Posted by: Reno | 12/26/2011 at 09:24 AM
TYVM you've svoled all my problems
Posted by: Adelie | 12/26/2011 at 10:08 AM
MRNUX9 ujxivxmttlwm
Posted by: ffldxt | 12/27/2011 at 09:52 AM