This content is part of the Essential Guide: The go-to Windows PowerShell guide

Essential Guide

Browse Sections

PKI encryption in PowerShell coming in Windows Server 2016

Administrators can use PowerShell to perform PKI encryption to protect sensitive data, but public or private key certificates need to be created first.

Although Microsoft has introduced several new PowerShell security capabilities in version 5.0, perhaps none are as noteworthy as the newly added support for public key infrastructure encryption. Organizations that are regular users of PowerShell will benefit from this feature to keep sensitive data more secure.

PowerShell 5.0, which is included with Windows Server 2016 and Windows 10, includes three PKI related cmdlets: Get-CmsMessage, Protect-CmsMessage and Unprotect-CmsMessage.

Because PKI encryption is based on the use of public key and private key certificates, you will need to create a certificate and add it to the certificate store before you can encrypt any data using PowerShell. It is best to get a certificate from a well-known commercial certificate authority or from your organization's enterprise certificate authority. However, you can generate your own self-signed certificate. A self-signed certificate isn't suitable for use in a production environment, but it can be used in a lab environment.

There are several ways to generate a self-signed certificate, but Microsoft recommends creating a simple text file that can serve as the certificate contents.


Signature = "$Windows NT$"







Subject = "[email protected]"

MachineKeySet = false

KeyLength = 2048


HashAlgorithm = Sha1

Exportable = true

RequestType = Cert


ValidityPeriod = "Years"

ValidityPeriodUnits = "1000"




The only change you have to make is to include uniquely identifying text in the subject line. The easiest way to accomplish this is to replace the example email address with your own.

Once you have created a certificate file or downloaded a certificate from a certificate authority, import the certificate into your certificate store. Rename the certificate file so that it has a file extension of .INF and run the following command:

certreq -new <your file.inf> DocumentEncryption.cer

You can see an example of how this process works in Figure A.

.INF file imported to certificate store.
Figure A. PowerShell is able to convert the .INF file into a .CER file and then import it into the certificate store.

It is worth noting that although the newly created certificate is added to the computer's certificate store, a copy of the certificate remains on the system's hard disk. Assuming you launch the command above from the root folder on the C: drive, the certificate will be placed in C:\. You can view the certificate file by either using File Explorer, or by entering the DIR or Get-ChildItem cmdlet, followed by the certificate's filename (Figure B).

Get-ChildItem cmdlet confirms DocumentEncryption file.
Figure B. The Get-ChildItem cmdlet reveals the existence of the C:\DocumentEncryption.cer file.

If your certificate file is a self-signed certificate that is intended for use in a lab environment, then the certificate file's existence is not cause for concern. If, however, the certificate was provided by a certificate authority and is intended for production use, then this file needs to be moved to a secure location.

Although Microsoft has introduced several new PowerShell security capabilities in version 5.0, perhaps none are as noteworthy as the newly added support for public key infrastructure encryption.

Regardless of whether you choose to move this certificate or leave it in its original location, you will need to know the certificate file's path and filename. This is because the certificate file is called as part of the encryption process.

To demonstrate the encryption process, I have created a file named C:\Scripts\Hello.txt. This file includes the text Hello World. The following command can be used to encrypt the file:

Protect-CmsMessage –Path C:\Scripts\Hello.txt –To C:\DocumentEncryption.cer –Outfile Hello.cms

Notice the command above uses the –Outfile switch. This switch specifies that the file's contents will be encrypted and written to a new file -- in this case, Hello.cms. The original text file remains unencrypted. Figure C shows the Protect-CmsMessage cmdlet being used. The Type command is then used to confirm that the Hello.txt file remains unencrypted, while the Hello.cms file is encrypted.

Protect-CmsMessage cmdlet.
Figure C. PowerShell creates an encrypted file.

Decrypting the certificate is just as easy. Assuming the computer's certificate store contains the necessary private key, the file can be decrypted with these commands:

$PlainText = Unprotect-CmsMessage –Path C:\Hello.cms


The first line of code uses the Unprotect-CmsMessage cmdlet to decrypt the file's contents. The file itself remains encrypted, but the file's contents are written to a variable named $PlainText. The second line of code displays this variable's contents. You can see the output in Figure D.

Unprotect-CmsMessage decrypts file contents.
Figure D. The $PlainText variable contains the decrypted text.

Command use transcripts

PowerShell can display a history of recent commands. There are a couple of ways of doing this. You can use the Get-History cmdlet to retrieve the 64 commands that were entered most recently into the current PowerShell session. Another option is to record a transcript by using the Start-Transcript cmdlet.

Microsoft has improved the transcription feature in Windows Server 2016 two ways. First, Microsoft now allows transcription to apply to both PowerShell and to PowerShell Integrated Scripting Environment. More importantly, it is now possible to enable transcription at the Group Policy level and to enable a system-wide transcript. Transcription-related Group Policy settings are located at Administrative Templates>Windows Components>Windows PowerShell.

Centralized PowerShell DSC error reporting

Another excellent new PowerShell feature is centralized Desired State Configuration (DSC) error reporting. PowerShell's DSC feature allows administrators to define a desired system configuration and detect configuration drift. But one of thing DSC lacked was centralized logging.

In Windows Server 2016, Microsoft makes it possible to send DSC errors to a centralized location automatically, which will make those errors much easier to review. This new capability can be used regardless of whether a target server is configured to pull DSC configuration information from a pull node. DSC error information is still logged to the server's own event logs.

You can find Microsoft's documentation for other PowerShell security related cmdlets here.

Next Steps

How PowerShell has changed in version 5

Get started with the PowerShell pipeline

Learn to work with PowerShell variables

Four execution policies that secure Powershell against malicious attacks

Dig Deeper on Windows administration tools