Chapter 4: Code Signing


1 2 Page 2
Page 2 of 2

The PVK Digital Certificate Files Importer

When a digital certificate is generated, sometimes the private key is stored in a PVK (private key) file, and the corresponding digital certificate is stored in a Software Publishing Certificate (SPC) file. When a code-signing certificate has been obtained from Verisign or Thawte, for example, the digital certificate is issued to you as a SPC and PVK file combination. If you want to use the code-signing certificate to digitally sign PowerShell scripts or configuration files, you must import the SPC and PVK file combination into your personal certificate store.

A certificate store is a location that resides on a computer or device that is used to store certificate information. In Windows, you can use the Certificates MMC snap-in to display the certificate store for a user, a computer, or a service according. Your personal certificate store is referring to your own "user" certificate store.

To import the SPC+PVK, you use the Microsoft utility called PVK Digital Certificate Files Importer. You can download it from the Microsoft Download Web site at

Next, enter the following command to import the SPC+PVK, substituting your own filenames:

pvkimprt -IMPORT "mycertificate.spc" "myprivatekey.pvk"

Signing PowerShell Scripts

When signing a PowerShell script, you use the Set-AuthenticodeSignature cmdlet, which takes two required parameters. The first parameter, filePath, is the path and filename for the script or file to be digitally signed. The second parameter, certificate, is the X.509 certificate used to sign the script or file. To obtain the X.509 certificate in a format the Set-AuthenticodeSignature cmdlet understands, you retrieve the certificate as an object with the Get-ChildItem cmdlet, as shown in this example:

PS C:\ > set-authenticodesignature –filePath signed.ps1 -certificate @(get-childitem cert:\ CurrentUser\ My -codeSigningCert)[0] -includeChain "All"

 Directory: C:\ 

SignerCertificate                        Status      Path
-----------------                        ------      ----
5CBCE258711676061836BC45C1B4ACA6F6C7D09E Valid       signed.ps1

PS C:\ > 

To retrieve the certificate you want from your own "user" certificate store, you use the Get-ChildItem cmdlet with the codeSigningCert SwitchParameter. This SwitchParameter can be used only with the PowerShell Certificate provider and acts as a filter to force the Get-ChildItem cmdlet to retrieve only code-signing certificates. Last, to ensure that the entire certificate chain is included in the digital signature, the includeChain parameter is used.

After the Set-AuthenticodeSignature cmdlet has been executed successfully, the signed file has a valid digital signature block containing the digital signature. A signature block in a PowerShell script or configuration file is always the last item in the file and can be found easily because it's enclosed between SIG # Begin signature block and SIG # End signature block, as shown here:

write-host ("This is a signed script!") -Foregroundcolor Green
# SIG # Begin signature block
# 9hinxULa3s0urQi362qa+NQ7yV3XczQOAPl0/kBIrEcwFN6YyS7PPm0wkCAPnfib
# 4J3uKxZK+4l9iHTiEVmp1ZO5G+P3KrqUS9ktFs7v9yTgqc8JLznxsRLvMwZpAMBO
# R2792YGWH5Jy4AwDYeljQ6Y=
# SIG # End signature block

This process for digitally signing scripts also applies to PowerShell configuration files. As discussed in Chapter 3, configuration files, depending on the execution policy setting, might also need to be signed before they are loaded into a PowerShell session.

Verifying Digital Signatures

To verify the digital signature of PowerShell scripts and configuration files, you use the Get-AuthentiCodeSignature cmdlet. It returns a valid status or an invalid status, such as HashMismatch, indicating a problem with the file.

Valid status:

PS C:\ > get-authenticodesignature signed.ps1

 Directory: C:\ 

SignerCertificate                        Status      Path
-----------------                        ------      ----
5CBCE258711676061836BC45C1B4ACA6F6C7D09E Valid       signed.ps1

PS C:\ > .\ signed.ps1
This is a signed script!
PS C:\ > 

Invalid status:

PS C:\ > Get-AuthenticodeSignature signed.ps1

 Directory: C:\ 

SignerCertificate                        Status          Path
-----------------                        ------          ----
5CBCE258711676061836BC45C1B4ACA6F6C7D09E HashMismatch    signed.ps1

PS C:\ .\ signed.ps1
File C:\ signed.ps1 cannot be loaded. The contents of file D:\ signed.ps1 may have been tampered because the hash of the file does not match the hash stored in the digital signature. The script will not execute on the system. Please see "get-help about_signing" for more details.
At line:1 char:12
+ .\ signed.ps1 <<<<
PS C:\ > 

Based on the error in the preceding example, the script has been modified or tampered with or is corrupt. If the script has been modified by its owner, it must be signed again before it can be used. If the script has been tampered with or is corrupt, it should be discarded because its validity and authenticity can no longer be trusted.

Signed Code Distribution

Distributing signed PowerShell scripts and configuration files requires the user to determine whether to trust code from a particular publisher. The first step is to validate the publisher's identity based on a chain of trust. To establish a chain of trust, the user uses the publisher's code-signing certificate associated with the digital signature to verify that the certificate owner is indeed the publisher. For example, Figure 4.5 shows an unbroken path (or chain) of valid certificates from the publisher's certificate to a trusted root certificate (or trust anchor).

Figure 4.5

Figure 4.5

The certificate path

When a well-known trusted public root CA or internally trusted root CA is the trust anchor for the publisher's certificate, the user explicitly trusts that the publisher's identity claims are true.

For Windows users, if a root CA is considered trusted, that CA's certificate resides in the Trusted Root Certification Authorities certificate store (see Figure 4.6).

Figure 4.6

Figure 4.6

Trusted Root Certification Authorities certificate store

When a root CA is not a valid trust anchor or the certificate is self-signed, the user needs to decide whether to trust a publisher's identity claim. If the user determines the identity claim to be valid, the root CA's certificate or the self-signed certificate should be added to the Trusted Root Certification Authorities certificate store to establish a valid chain of trust.

After the publisher's identity has been verified or trusted, the next step is deciding whether the signed code is safe for execution. If a user has previously decided that code from a publisher is safe for execution, the code (PowerShell script or configuration file) runs without further user action.

For Windows users, if a publisher is considered trusted, their code-signing certificate resides in the Trusted Publishers certificate store (see Figure 4.7).

Figure 4.7

Figure 4.7

Trusted Publishers certificate store

If a publisher is not trusted, PowerShell prompts the user to decide whether to run signed code from that publisher, as shown in this example:

PS C:\ > .\ signed.ps1

Do you want to run software from this untrusted publisher?
File C:\ signed.ps1 is published by, OU=IT,, L=Oakland, S=California, C=US and is not trusted on your
system. Only run scripts from trusted publishers.
[V] Never run [D] Do not run [R] Run once [A] Always run [?] Help
(default is "D"): 

The following list explains the available options:

  • [V] Never run—This option places the publisher's certificate in the user's Untrusted Certificates certificate store. After a publisher's certificate has been determined to be untrusted, PowerShell never allows code from that publisher to run unless the certificate is removed from the Untrusted Certificates certificate store or the execution policy is set to Unrestricted or RemoteSigned.

  • [D] Do not run—This option, which is the default, halts execution of the untrusted code.

  • [R] Run once—This option allows one-time execution of the untrusted code.

  • [A] Always run—This option places the publisher's certificate in the user's Trusted Publishers certificate store. Also, the root CA's certificate is placed in the Trusted Root Certification Authorities certificate store, if it isn't already there.

Enterprise Code Distribution

You might be wondering how to control what code is considered trusted in your organization. Obviously, having users or machines decide what to trust defeats the purpose of distributing signed code in a managed environment. If your environment is managed, your PKI deployment should have methods for controlling what's trusted in an organization. If your organization is a Windows environment, the most common method is through GPO. For example, you can define trusted publishers by using a Certificate Trust List (CTL) or manage them through the Internet Explorer Maintenance extension.

Public Code Distribution

Determining trust in the public realm is entirely different. When establishing trust between two private entities, they are able to define what is and isn't trusted. When dealing with public entities, you don't have this level of control. It is up to those public entities to determine what they do or do not trust.


In summary, this chapter, as its name suggested, was an in-depth exploration into code signing. Based on the information that you have gleaned from this chapter, you should now have an understanding for just how important code signing is to PowerShell security and how to use it. If you haven't come to this realization, then it is again stressed that code signing be understood and used in conjunction with your script development activities.

In addition to stressing the use of code signing, you should also now have a better understanding for the infrastructure that is required to make code signing a viable method for trusting code within an organization. Granted, while PKI can be difficult to understand, one of the main goals of this chapter was to explain PKI from the perspective that was related to your scripting activities—an approach that was taken in an effort to reduce the amount of bewilderment, on your part, by relating PKI to something that is applicable to how it would be used with PowerShell. With this knowledge, you should now be able to determine, or at least convey, a PKI need and hopefully move a project forward such that the scripts you developed can be trusted at your organization.

Copyright © 2007 Pearson Education. All rights reserved.

Join the Network World communities on Facebook and LinkedIn to comment on topics that are top of mind.

Copyright © 2007 IDG Communications, Inc.

1 2 Page 2
Page 2 of 2