The old times of batches and VbScript files that everyone can run seems to be gone.

Microsoft is putting more and more attention on the security and now with Microsoft PowerShell we have the ability to run sign our scripts.

I think that every new user of PowerShell that tried to launch his first scrip saw this error:

The file C:\my_script.ps1 cannot be loaded. The execution of scripts is disabled on this system. Please see “Get-Help about_signing” for more details.

The default setting of the PowerShell interpreter is to do not allow you to run unsigned scripts.

This is very secure but very annoying as well so many users tend to disable this setting using the command

Set-ExecutionPolicy -ExecutionPolicy Unrestricted

Problem Solved” then? Yes, but the price we pay is that every script can be run without control.

So if someone maliciously modifies one of your favourite scripts it will be executed regardless.

The web is plenty of articles about how to sign a PowerShell script: the problem is that you need to read all of them and interpolate them to make it work for real.

It is possible to use a self-signed certificate to sign your scripts but this article will focus on how to set up a Certificate Authority and request a Code Signing certificate to it.

If you have already a codesign certificate emitted by a Certification Authority you can jump directly to the PART FOUR of this document.

PART ONE: Set up a Certificate Authority (Active Directory Certificate Services)

To set up an Active Directory Certificate Services you need a Windows 2008 R2 Server or something more modern such as Windows 2016 Server.

  1. Open the Server Manager snap-in
  2. Click on the Roles section and click on Add Roles
  3. Check the Active Directory Certificate Services and press Next twice
  4. Select at least the Certification Authority and the Certification Authority Web Enrollment options and press Next
  5. At this point you can decide if you want and Enterprise or Standalone certification authority: this depends from your needs: if you click on the link in the setup wizard you can read in the help file what are the main differences.
    In this example, we are using the Enterprise one
  6. Leave all the defaults and press next until you reach the end of the wizard.

PART TWO: How to access it

Now that you have a Certification Authority up and running the best way to access it is through the web interface. The URL is:


Check that you are able to browse it using HTTPS as well:


If you are not able to do so you need to follow this simple procedure:

  1. Open the Internet Information Services (IIS) Manager snap-in
  2. Click on your server node
  3. Double click on the Server Certificates icon
  4. Click on Create Self-Signed certificate… (in the right pane)
  5. Enter a name for it and press OK
  6. Explode the node Sites, right-click on the Default Web Site and choose the Edit Bindings… option
  7. Click on the Add button then under Type select HTTPS
  8. Select in the SSL Certificate dropdown the SSL certificate created previously
  9. Press OK and then close
  10. Now you’d be able to access the site in HTTPS mode as well.

PART THREE: Own to obtain the Code Signing certificate

First of all we need to verify that we are allowed to ask the Code Signing certificates to your CA

The procedure is simple:

  1. Open the Server Manager snap-in
  2. Explode the Active Directory Certificate Services
  3. Explode the certification authority (normally it comes immediately after the Certificate Templates icon)
  4. Click on the Certificate Templates folder and verity that Code Signing template is listed.
  5. If is not listed right-click on the Certificate Templates folder and select New -> Certificate Template to Issue
  6. Select the Code Signing one and press OK.

Now finally is the moment to access your Certification Authority via HTTPS and get our certificate

  1. Browse to https://myserver/certsrv
  2. Click on Request a Certificate link
  3. Click on Advanced Certificate Request link
  4. Click on Create and Submit a request to this CA link
  5. Select from the Certificate Template dropdown the Code Signing one
  6. You can leave all the options like that and click on the submit button
  7. If you are the administrator the certificate request is immediately approved: simply click on Install this certificate link to install it.

PART FOUR – Finally Sign it!!

It is the time now to use it to sign your script:

Suppose that you have already a PowerShell script and you want to sign it.

You only need to follow this procedure:

  1. Open the PowerShell console
  2. Issue the following command:

    Set-AuthenticodeSignature c:\foo.ps1 @(Get-ChildItem cert:\CurrentUser\My -codesigning)[0]

    If your certificate was issued by a Certification Authority and they offer the timestamp service the command is the following:

    Set-AuthenticodeSignature c:\foo.ps1 @(Get-ChildItem cert:\CurrentUser\My -codesigning)[0] -TimestampServer

    NOTE: cert:\CurrentUser\My needs to be written as is…do not substitute the name of your real current user to the string!
  3. If everything is ok you’d receive an answer like that:
    SignerCertificate Status Path
    —————– —— —-
    A180F4B81AA81143AD2969114D26A2CC2D2AD65B Valid foo.ps1

But what about if a receive and error and the error is Unspecified ?

Many things can go wrong but 99% of the times the reason is that your script was not saved in UTF-8.

Try to open the script with NOTEPAD and click on File -> Save As and be sure that the ENCODING is set to UTF-8

After you save your script in UTF-8 try the signing procedure again.

PART FIVE: Now test it!

Now that everything let try if really works…

  1. Launch the PowerShell console as administrator (right-click -> Run as Administrator)
  2. issue the command
    Set-ExecutionPolicy -ExecutionPolicy AllSigned
  3. Launch a not signed script:C:\myscripts\notsigned.ps1
  4. You will obtain an error
  5. Launch now your script: C:\myscripts\foo.ps1
  6. Does it work?!?! Yes?? Well DONE!


Q: I noticed that when I request the certificate the option “Mark keys as Exportable is grayed out”..why? what I can do?

A:This is a big mystery to me as well because in a lot of articles I read this option is always selectable but in my labs is grayed out.

To circumvent the problem you need to follow this procedure:

1. Open server manager and select the Certificate Templates node that is under the Active Directory Certificate Services

2. Right click on the Code Signing template and select the option “Duplicate template

3. Give it a name like My Code Sign, in the Request Handling tab check the box Allow private keys to be exported and press ok.

4. Explode your certification authority node (under Active Directory Certificate Services) and right click on the Certificate Templates folder

5. Choose the option New -> Certificate Template to issue

6. Select the newly create template and press ok

The next time you ask for a certificate via the web interface select as template the newly created one.

Q: Now I can sign my scripts but how the others are going to trust them?

A:You need to distribute via GPO or other ways the public part of your signing certificate (THE PUBLIC ONLY!!!!)

This public part of the certificate need to be installed under the Trusted Publishers repository of the certificates.

Be sure that the certificate is valid once imported. If not you need to deploy the ROOT CA certificate of your CA and install it under the Trusted Root Certification Authority repository