I’m trying to use certificates to embed credentials into a Service resource. I’ve got PKI in the infrastructure and all my test servers are auto-enrolled. I exported their certs locally to work with and have them in my ConfigData as follows:
@{ AllNodes = @( @{ NodeName = "*" NeoConfigDestinationPath = "D:\ServerBox\Servers\JRun4\_build\shared\config" } @{ NodeName = 'DEVOPS' Role = @('DSCPullServer') CertificateFile = "D:\EQ_DSCModule\Certs\DevOps1.cer" Thumbprint = "AE4F10AE4141C8726EEEBE888C69FE7ABB3099A8" } @{ NodeName = 'Server1' Role = @('IIS', 'ServerBox', 'DevInt') CFServices = @("Adobe CF9 1", "Adobe CF9 2", "Adobe CF9 3", "Adobe CF9 4") CertificateFile = "D:\EQ_DSCModule\Certs\Client1.cer" Thumbprint = "4FA343A76AEA2B805850190E9C04AA9E2A82A162" } @{ NodeName = 'Server2' Role = @('IIS', 'ServerBox', 'DevInt') CFServices = @("Adobe CF9 1") CertificateFile = "D:\EQ_DSCModule\Certs\Client2.cer" Thumbprint = "0FCB76684F0C74495DEB54F637B50BDA7182483D" } ) ServerBoxConfig = @{ SourcePath = "\\Share\Path\DevOps\ServerBox" DestinationPath = "D:\ServerBox" } DevIntConfig = @{ SourcePath = "\\Share\Path\DevOps\DevInt" DestinationPath = "D:\ServerBox\IIS\wwwroot" NeoConfigSourcePath = "\\Share\Path\DevOps\ServerConfig\Environments\DevInt\NeoConfig" } }
This this is the config script that I’m running:
$webCFDevCred = Get-Credential -Credential "svc-webcfdev@domain.com" Configuration EqConfig { Import-DSCResource -Module xPSDesiredStateConfiguration Import-DSCResource -Module cChoco Node $AllNodes.NodeName { cChocoInstaller installChoco { InstallDir = "C:\ProgramData\Chocolatey" } } Node $AllNodes.Where({ $_.role -eq 'DSCPullServer' }).NodeName { ... } #DSCPullServer Node $AllNodes.Where({ $_.role -eq 'IIS' }).NodeName { ... } #IIS Node $AllNodes.Where({ $_.role -eq 'ServerBox' }).NodeName { File ServerBox { Ensure = "Present" Type = "Directory" Recurse = $true MatchSource = $true Force = $true Checksum = "modifiedDate" SourcePath = $ConfigurationData.ServerBoxConfig.SourcePath DestinationPath = $ConfigurationData.ServerBoxConfig.DestinationPath } } #ServerBox Node $AllNodes.Where({ $_.role -eq 'DevInt' }).NodeName { File DevInt { Ensure = "Present" Type = "Directory" Recurse = $true MatchSource = $true Force = $true Checksum = "modifiedDate" SourcePath = $ConfigurationData.DevIntConfig.SourcePath DestinationPath = $ConfigurationData.DevIntConfig.DestinationPath DependsOn = "[File]ServerBox" } File DevInt_Config { Ensure = "Present" Type = "Directory" MatchSource = $true Force = $true Checksum = "modifiedDate" SourcePath = $ConfigurationData.DevIntConfig.NeoConfigSourcePath DestinationPath = $Node.NeoConfigDestinationPath DependsOn = "[File]ServerBox" } #This runs a script to build out the ColdFusion cluster/servers #Uses the number of services as the param for serverCount cChocoPackageInstaller installServerBox { Name = "ServerBox.DevInt -params $($Node.CFServices.Length)" DependsOn = @("[cChocoInstaller]installChoco", "[File]DevInt_Config") } #Sets the services generated by the ServerBox script $Node.CFServices.ForEach({ Service "Service-$_" { Name = $_ State = 'Running' Credential = $webCFDevCred DependsOn = "[cChocoPackageInstaller]installServerBox" } }) } #DevInt } #Configuration EqConfig -ConfigurationData .\EQConfigData.psd1 -Output .\EqConfig -Verbose Function Get-ComputerGuid { param ( [Parameter(Mandatory = $true)] [string]$ComputerName ) process { ([guid]([adsisearcher]"(samaccountname=$ComputerName`$)").FindOne().Properties["objectguid"][0]).Guid } } $DSCPullFolder = "C:\Program Files\WindowsPowerShell\DscService\Configuration" Get-ChildItem .\EqConfig\* -Filter *.mof | ForEach-Object { $guidMofFile = "$DSCPullFolder\$(Get-ComputerGuid $_.BaseName).mof" $newMof = copy $_.FullName $guidMofFile -PassThru -Force $newHash = (Get-FileHash $newMof).hash [System.IO.File]::WriteAllText("$newMof.checksum", $newHash) } Configuration EqLocalConfig { Node $AllNodes.NodeName { LocalConfigurationManager { AllowModuleOverwrite = 'True' CertificateID = $Node.Thumbprint ConfigurationID = $(Get-ComputerGuid $nodeName) ConfigurationModeFrequencyMins = 15 ConfigurationMode = 'ApplyAndAutoCorrect' RebootNodeIfNeeded = 'True' RefreshMode = 'PULL' DownloadManagerName = 'WebDownloadManager' DownloadManagerCustomData = (@{ ServerUrl = "https://DEVOPS:443/psdscpullserver.svc" }) } } } EqLocalConfig -ConfigurationData .\EQConfigData.psd1 -Verbose Set-DscLocalConfigurationManager -Path .\EqLocalConfig -Verbose
As far as I can tell it should work. My MOFs get generated with encrypted passwords inside, but when the client servers pick up the config and get to the Service step, it errors out. Checking the event viewer this is the details on the event:
“This event indicates that failure happens when LCM is processing the configuration. ErrorId is 0x1. ErrorDetail is The SendConfigurationApply function did not succeed… ResourceId is [Service]Service-Adobe CF9 1 and SourceInfo is D:\EQ_DSCModule\EqConfig.ps1::285::4::Service. ErrorMessage is PowerShell provider MSFT_ServiceResource failed to execute Set-TargetResource functionality with error message: Failed to change ‘Credential’ property. Message: ‘The ‘Change’ method of ‘Win32_Service’ failed with error code: ‘22’.’ .”
According to MSDN (https://msdn.microsoft.com/en-us/library/aa384901(v=vs.85).aspx) error code 22 on the Change method means “The account under which this service runs is either invalid or lacks the permissions to run the service.” I know the service account works fine and I can add it myself using WMI as follows:
For ($i=0; $i -lt $clusterCount; $i++) { (Get-WmiObject -Query "SELECT * FROM Win32_Service WHERE Name = 'Adobe CF9 $($i+1)'").Change($null,$null,$null,$null,$null,$null,'svc-webcfdev@domain.com','password',$null,$null,$null) }
So if I can add the account using WMI, DSC should be able to as well, right? Ugh!
Ideas?
edit: Note to moderators… you guys really need a preview post option.