Using a certificate to encrypt credentials in automated PowerShell scripts – An Update!

Early last year I wrote a post about encrypting script credentials using certificates. At the time, someone (thanks Dave Wyatt!) commented on the post suggesting a couple of alternative methods to encrypt and decrypt the data, in particular I was interested in the Protect-CmsMessage and Unprotect-CmsMessage cmdlets included in PowerShell 5.0. Now that PowerShell 5.0 is more widespread I wanted to post a quick update about how these cmdlets can help simplify the process. The process is similar, but there are less steps and it is important to note that the certificate must contain the Data Encipherment or Key Encipherment key usage, and include the Document Encryption Enhanced Key Usage (1.3.6.1.4.1.311.80.1).

Capture

Let’s start by first locating our certificate using the Get-ChildItem cmdlet:

$Cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -like "CN=PowerShell Automation*"}

Next we encrypt our password using that certificate:

$Password = 'MyPassword'
Protect-CmsMessage -To $Cert -Content $Password

Capture

You’ll notice that the encrypted password is presented a little differently. You will need to include the entire block in your script.

Unencrypting the password in your script basically involves repeating this process in reverse:

$Cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -like 'CN=PowerShell Automation*'}
$EncryptedPwd = @'
-----BEGIN CMS-----
MIIBqAYJKoZIhvcNAQcDoIIBmTCCAZUCAQAxggFQMIIBTAIBADA0MCAxHjAcBgNVBAMMFVBvd2Vy
U2hlbGwgQXV0b21hdGlvbgIQOEd4fYDturxF77V7lEytlDANBgkqhkiG9w0BAQcwAASCAQB0z92N
HrgQ84JxSV7RYpwSMPJRuSXlgVubOIew8KsYXr/E8kd/wOyT/2NPi3d+4xb67CLUM4infqOrt9Q+
ReAtINvfVB5EPc9wU8yDpdz+WKProT4RJ94nzGH5qW5SK4O1Siu0VSPJZaCNb+CmYNFNNvLu6MN4
pDqOiqZnv+j/rUxhrHX+U3E+eJq5P0gsZUwRaXZoAgGyV6SvZdUsbPYZ+hMPG0DruF/83SK6MOZM
yVnGOmeP8e8/b/Rk2Y24JvDcROwRvK2+uj2Oy3ukw1WS4TxMy2V4lkjTYvwIO+bukjFCCtaR4Q63
C6fx9OArx+uMbPmzkFgmG0w3jFVNnjjMMDwGCSqGSIb3DQEHATAdBglghkgBZQMEASoEEPdMffTC
N+IvYDNFmuWKgZqAELsAZyE9I0POh/j64DNTsLI=
-----END CMS-----
'@
$DecryptedPwd = $EncryptedPwd | Unprotect-CmsMessage -To $Cert | ConvertTo-SecureString -AsPlainText -Force

You can now use $DecryptedPwd to generate your credentials similar to the following:

$MSOLUsername = 'serviceAcc@tenant.onmicrosoft.com'
$MSOLCredentials = New-Object System.Management.Automation.PSCredential ($MSOLUsername,$DecryptedPwd)
Connect-MSOLService -Credential $MSOLCredentials

Post navigation


Comments

  • Marc Terblanche

    Nice post Chris. This is more portable than my usual method of saving the encrypted password to disk with ‘ConvertFrom-SecureString | Set-Content $CredFile -force’ which only works with that user profile. To generate a self signed cert for use with Protect-CmsMessage you can run:

    New-SelfSignedCertificate -Type Custom -Subject “CN=Firstname Lastname – Script” -TextExtension @(“2.5.29.37={text}1.3.6.1.4.1.311.80.1”) -KeyUsage DataEncipherment -KeyAlgorithm RSA -KeyLength 2048 -SmimeCapabilities -CertStoreLocation “Cert:\CurrentUser\My”

  • Chris

    Hey Marc,

    I hope you are well – yeah, portability is often a key requirement for me which is what inspired this. Thanks for the info about generating a self-signed cert!

    Cheers,

    Chris

  • Nathan Alden, Sr.

    Excellent post. I was clueless as to how to pass my X509Certificate2 instance to Protect-CmsMessage; the cmdlet documentation is not helpful in that regard. Your post cleared it right up for me and works perfectly.

  • Chris

    Great! Thanks for the feedback Nathan, glad the post helped.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>