Use a certificate with PowerShell DSC to add a server to Active Directory without hard coding a password

A new Windows Server 2012 R2 machine has been brought online and needs to be joined to your Active Directory domain. All machines used in this demonstration are running either Windows Server 2012 R2 or Windows 8.1 with PowerShell version 4.

You've decided to use DSC (Desired State Configuration) to join this new server to the domain because it's a prototype for many more servers to come. You plan to automate their deployment along with the majority of their configuration with DSC.

While this blog article doesn't fully automate all of the process required to add the target node to the domain, it is meant to demonstrate the encryption and decryption of the password for the domain user account that is required to add it to the domain which would otherwise have to be stored in clear text.

The name of the target node has been added to the trusted host list on the machine that is being used to author and apply the DSC configuration:

1Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value 'WIN-U74LBSGF2CA' -Concatenate -Force

dsc-cert6.jpg

The xComputerManagment module which is part of DSC Resource Kit Wave 8, contains the DSC resource that will be used to add our new server to the Active Directory domain. This module has been copied to "C:\Program Files\WindowsPowerShell\Modules" on the target node and the machine that will be used to author and apply the DSC configuration.

Fellow PowerShell MVP Vadims Podans has a PowerShell self-signed certificate generator that was used to create a self-signed certificate on the target node:

1New-SelfSignedCertificateEx -Subject 'CN=WIN-U74LBSGF2CA' -StoreLocation LocalMachine -StoreName My

dsc-cert11.jpg

Export the public key:

1Export-Certificate -Cert Cert:\LocalMachine\My\27375EB88F2B13A20B58180497F5A7917208850A -FilePath C:\tmp\testcert.cer

dsc-cert10.jpg

The public key that was exported in the previous step has been copied to the machine that will be used to author and apply the DSC configuration. The Thumbprint of the certificate has been entered into the DSC configuration as shown in the following example.

I had previously read an article on MSDN titled Deploying using PowerShell Desired State Configuration in Release Management that demonstrates using an initialization script so I thought I would take advantage of that technique here:

 1$ConfigData = @{
 2    AllNodes = @(
 3        @{
 4            NodeName = 'WIN-U74LBSGF2CA'
 5            MachineName = 'DC02'
 6            Domain = 'mikefrobbins'
 7            CertificateFile = 'C:\tmp\testcert.cer'
 8            Thumbprint = '27375EB88F2B13A20B58180497F5A7917208850A'
 9        }
10    )
11}

dsc-cert1.jpg

The LCM (Local Configuration Manager) on the target node needs to be made aware of the certificate that will be used to decrypt the password. That portion of the configuration could be split out into a separate configuration. I also set the LCM on the target node to automatically reboot the machine if a restart is required by configuration changes:

 1Configuration MrDscConfiguration {
 2
 3    param (
 4        [pscredential]$Credential
 5    )
 6
 7    Import-DscResource -Module xComputerManagement
 8
 9    Node $AllNodes.NodeName {
10        LocalConfigurationManager {
11            CertificateID = $Node.Thumbprint
12            RebootNodeIfNeeded = $true
13        }
14
15        xComputer JoinDomain {
16            Name = $Node.MachineName
17            DomainName = $Node.Domain
18            Credential = $Credential
19        }
20    }
21}

dsc-cert2.jpg

When the configuration is run, two MOF files are created. One for the LCM and the other for the node configuration that you typically see created with DSC. The credential that is specified with this command is a domain account that has the necessary rights to add the machine to the domain. The password for this credential is what will be encrypted in the MOF file that is created:

1MrDscConfiguration ConfigurationData $ConfigData -Credential (Get-Credential) Verbose

dsc-cert3.jpg

The following example shows the contents of the WIN-U74LBSGF2CA.mof file:

 1/*
 2@TargetNode='WIN-U74LBSGF2CA'
 3@GeneratedBy=administrator
 4@GenerationDate=11/27/2014 16:56:46
 5@GenerationHost=PC01
 6*/
 7
 8instance of MSFT_Credential as $MSFT_Credential1ref
 9{
10Password = "MTxMxpE2+pivknezEqvHMGUTCsvENbeRC6AymAW1hDEyW/RCFZElL4tKugzsO2MksyVbUiDbq4xFVReVso2g6KVASDxQfxSK+NsjxlD4r4lvhYXfWAcNJaY748KPuESxYP/bdhb8IcOiLC2+3Zw666yLHGuBhfJuAUSrk2JTG9E=";
11 UserName = "mikefrobbins\\administrator";
12
13};
14
15instance of MSFT_xComputer as $MSFT_xComputer1ref
16{
17ResourceID = "[xComputer]JoinDomain";
18 Credential = $MSFT_Credential1ref;
19 DomainName = "mikefrobbins";
20 SourceInfo = "::11::9::xComputer";
21 Name = "DC02";
22 ModuleName = "xComputerManagement";
23 ModuleVersion = "1.2";
24
25};
26
27instance of OMI_ConfigurationDocument
28{
29 Version="1.0.0";
30 Author="administrator";
31 GenerationDate="11/27/2014 16:56:46";
32 GenerationHost="PC01";
33 ContentType="PasswordEncrypted";
34};

Notice that the password is encrypted in the mof file as shown the previous example. That is the whole point of this blog article. Don't store passwords in plain text .

This example shows the contents of the WIN-U74LBSGF2CA.meta.mof file:

 1/*
 2@TargetNode='WIN-U74LBSGF2CA'
 3@GeneratedBy=administrator
 4@GenerationDate=11/27/2014 16:56:46
 5@GenerationHost=PC01
 6*/
 7
 8instance of MSFT_DSCMetaConfiguration as $MSFT_DSCMetaConfiguration1ref
 9{
10CertificateID = "27375EB88F2B13A20B58180497F5A7917208850A";
11 RebootNodeIfNeeded = True;
12
13};
14
15instance of OMI_ConfigurationDocument
16{
17 Version="1.0.0";
18 Author="administrator";
19 GenerationDate="11/27/2014 16:56:46";
20 GenerationHost="PC01";
21};

Now to apply the changes to the LCM on the target node. The credential that is specified with this command is a local userid and password that has the necessary rights to perform these configuration changes on the target node:

1Set-DscLocalConfigurationManager -Path .\MrDscConfiguration -Credential (Get-Credential) -Verbose

dsc-cert4.jpg

Why didn't I use a domain account in the previous example? Because the machine isn't yet a member of any Active Directory domain. It's a brand new server that's in a workgroup.

Now to apply the DSC configuration to the new server (our target node). Once again, we need to specify a local userid and password on the target node when prompted for credentials with this command. I could have previously stored the credentials in a variable and specified the variable since this is the second time I've had to type them in:

1Start-DscConfiguration -Wait -Path .\MrDscConfiguration -Credential (Get-Credential) -Verbose

dsc-cert5.jpg

If you happen to be signed into the target node when the configuration is applied, you'll receive the following message and about two seconds later the machine will restart:

dsc-cert7.jpg

Once the restart of the target node is complete, it will have been renamed and added to the domain just like magic and all without needing to store any passwords in plain text!

Troubleshooting notes:

If you receive this error, there's a problem with the certificate you're using. I ended up with this error when I used a certificate that was created with New-SelfSignedCertificate.

1The private key could not be acquired.
2+ CategoryInfo : NotSpecified: (root/Microsoft/…gurationManager:String) [], CimException
3+ FullyQualifiedErrorId : MI RESULT 1
4+ PSComputerName : WIN-U74LBSGF2CA

dsc-cert8.jpg

If you receive this error, you could have a certificate mismatch problem:

1Access is denied.
2+ CategoryInfo : PermissionDenied: (root/Microsoft/…gurationManager:String) [], CimException
3+ FullyQualifiedErrorId : HRESULT 0x80070005
4+ PSComputerName : WIN-U74LBSGF2CA

dsc-cert9.jpg

When I encountered the certificate mismatch problem, it was because I had initially used a certificate that wouldn't work and then when I generated another certificate, I hadn't reconfigured the LCM on the target node to use it so the encryption was occurring with one certificate and the decryption was attempting to use a different certificate.

µ