In this article, I'm going to show you how to automate the process of creating self-signed certificates on your Desired State Configuration (DSC) nodes.

DSC can be a huge time-saver for system administrators. Admins no longer have to create dozens of lines of code to test for and set various configuration items. If you're set on implementing DSC in your environment, there are a few hurdles you'll have to leap over. One of the biggest is ensuring tightened security, particularly in those instances where you need to store credentials in your MOF files.

Technically, you could use the PsDscAllowPlainTextPassword keyword in your configurations, but this is simply turning off encryption. It's easier, but it's terribly insecure. It's much better to place certificates on each of your DSC nodes and export out the public certificate to your management workstation to encrypt and decrypt credentials in the MOF documents.

I will now show how to automate the process of creating self-signed certificates on your DSC nodes. The code I'll be going over was based on this long-winded MSDN article.

To do this is going to require a few prerequisites, so be sure you have these ready before you begin. First, you'll need the New-SelfSignedCertificateEx function. This is an advanced function that allows you to create self-signed certificates on local computers. We'll be focusing on remote computers in this article, so I'll go over a trick to make this work remotely.

To get the New-SelfSignedCertificateEx function to work remotely over PowerShell remoting, we must package up the function itself and declare it inside of the remote session. This can be done by assigning the function definition to a variable.

$functionDef = "function New-SelfSignedCertificateEx { ${function:New-SelfSignedCertificateEx}}"

Now we need to create our scriptblock to pass to Invoke-Command to run this function on a remote computer. To do that, I'll need to define a parameter on the scriptblock to pass the definition I just created to it. Once I do that, I then have to "re-create" the function definition inside of the session by creating a scriptblock.

$ScriptBlock = {
     param ($functionDef)
     
     . ([ScriptBlock]::Create($functionDef))
 }

At this point, we can now call the function just as if it was local. DSC encryption certificates require specific attributes that need to be placed in the appropriate location. Below, you'll find all of the parameters that need to be passed to New-SelfSignedCertificateEx in order to satisfy all of those requirements.

$signedCertParams = @{
       'Subject' = "CN=$env:COMPUTERNAME"
       'SAN' = $env:COMPUTERNAME
       'EnhancedKeyUsage' = 'Document Encryption'
       'KeyUsage' = 'KeyEncipherment', 'DataEncipherment'
       'FriendlyName' = $using:Defaults.CertificateFriendlyName
       'StoreLocation' = 'LocalMachine'
       'StoreName' = 'My'
       'ProviderName' = 'Microsoft Enhanced Cryptographic Provider v1.0'
       'PassThru' = $true
       'KeyLength' = 2048
       'AlgorithmName' = 'RSA'
       'SignatureAlgorithm' = 'SHA256'
}

All of this code eventually creates a scriptblock that looks like this:

$ScriptBlock = {
     param ($functionDef)
     
     . ([ScriptBlock]::Create($functionDef))
     $signedCertParams = @{
         'Subject' = "CN=$env:COMPUTERNAME"
         'SAN' = $env:COMPUTERNAME
         'EnhancedKeyUsage' = 'Document Encryption'
         'KeyUsage' = 'KeyEncipherment', 'DataEncipherment'
         'FriendlyName' = $using:Defaults.CertificateFriendlyName
         'StoreLocation' = 'LocalMachine'
         'StoreName' = 'My'
         'ProviderName' = 'Microsoft Enhanced Cryptographic Provider v1.0'
         'PassThru' = $true
         'KeyLength' = 2048
         'AlgorithmName' = 'RSA'
         'SignatureAlgorithm' = 'SHA256'
     }
     New-SelfSignedCertificateEx @signedCertParams
 }

Now that we have the scriptblock defined, we need to run Invoke-Command to execute this scriptblock on the remote computer.

$cert = Invoke-Command –ComputerName REMOTECOMPUTER –ScriptBlock $ScriptBlock –ArgumentList $functionDef

Don't forget to use the ArgumentList parameter. This passes the function definition into the scriptblock.

At this point, your self-signed certificate should be installed in the LocalMachine certificate store on the remote computer, with the subject "CN=<COMPUTERNAME>". You can verify this by querying for the certificate using the certificate store.

Invoke-Command –ComputerName REMOTECOMPUTER –ScriptBlock {Get-ChildItem –Path Cert:\LocalMachine\My | where {$_.Subject –like 'CN=REMOTECOMPUTER*' | Select *}}

You can see that my remote computer name is bapp07gen02.bdt007.local.

Verifying that the remote computer name is bapp07gen02.bdt007.local by querying for the certificate using the certificate store.

Verifying that the remote computer name is bapp07gen02.bdt007.local by querying for the certificate using the certificate store.

The hard part is over! You'll now just need to export the public certificate to a file and then you can import it to wherever you plan to manage this node from. As you can see from the code snippet above, I assigned the output of Invoke-Command to $cert. This was because I can now send $cert directly to Export-Certificate, which will create a certificate file anywhere I like.

Subscribe to 4sysops newsletter!

$cert | Export-Certificate -FilePath C:\REMOTECOMPUTER.cer

You should now have a self-signed certificate created with all of the appropriate attributes in the right certificate store location on the remote computer. You should also have the public certificate on your local computer.

3 Comments
  1. Paul Bendall 5 years ago

    Nice, can you do something similar but use AD CS if you have it available? In Azure would be better to use Azure Key Vault for secure secret storage? This are additions to the article which remains very useful.

    Paul

  2. Author

    Yes. You could but the process would be different. This is just for times when you need to either test something or get something done quick. It's not necessarily for production scenarios. I would use AD CS or Azure Key Vault in production environments.

  3. Miguel 1 year ago

    Apparently in newer versions of the script these parameters don´t work:

    - passthru - I got to remove it

    - storename - i got to remove it

    - enhancedkeyusage - the "document encryption" option doesn´t work anymore. Some websites suggest to use type DocumentEncryptionCertLegacyCsp but it doesn´t work either

    Any way to solve this? I have googled around with no luck

Leave a reply

Please enclose code in pre tags

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

*

© 4sysops 2006 - 2021

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account