Automating Certificate Enrollment Policy Configuration and Certificate Requests via PowerShell in Windows Server


2 views

Dealing with manual certificate enrollment in Windows environments can be tedious, especially when you need to:

  • Configure Certificate Enrollment Policy (CEP) through Group Policy
  • Switch authentication methods
  • Handle multiple MMC snap-in operations
  • Repeatedly enter certificate details

Here's how to completely automate the process using PowerShell, tested on both Server 2008 R2 and Server 2012 R2:

# Configure Certificate Enrollment Policy
$policyParams = @{
    PolicyID = [guid]::NewGuid().ToString()
    PolicyName = "CorporateCEP"
    PolicyURL = "https://cep.yourdomain.com/ADPolicyProvider_CEP_UsernamePassword/service.svc/CEP"
    CredentialType = "UsernamePassword"
    EnrollPermission = $true
    AutoEnrollmentEnabled = $true
}

Add-CertificateEnrollmentPolicyServer @policyParams -Force

After configuring the policy, request certificates with this script:

# Certificate Request Parameters
$certParams = @{
    TemplateName = "WebServer"
    SubjectName = "CN=webserver01.yourdomain.com"
    DNSName = "webserver01.yourdomain.com"
    CertStoreLocation = "Cert:\LocalMachine\My"
    Credential = Get-Credential
}

$cert = Get-Certificate @certParams -Url "https://cep.yourdomain.com/ADPolicyProvider_CEP_UsernamePassword/service.svc/CEP"
$cert | Export-Certificate -FilePath "C:\certs\webserver01.cer" -Type CERT

For environments where Group Policy isn't feasible, you can directly modify the registry:

# Create CEP Policy Registry Structure
$regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\PolicyServers"
New-Item -Path $regPath -Name "YourPolicyGUID" -Force | Out-Null

$regValues = @{
    "AuthFlags" = 1
    "Cost" = 0
    "Flags" = 1
    "FriendlyName" = "Corporate CEP"
    "ID" = "YourPolicyGUID"
    "Url" = "https://cep.yourdomain.com/ADPolicyProvider_CEP_UsernamePassword/service.svc/CEP"
}

For bulk certificate requests across multiple servers:

$servers = @("web01","web02","web03")
$template = "WebServer"

$servers | ForEach-Object {
    $certParams = @{
        TemplateName = $template
        SubjectName = "CN=$_.yourdomain.com"
        DNSName = "$_.yourdomain.com"
        CertStoreLocation = "Cert:\LocalMachine\My"
    }
    
    try {
        Get-Certificate @certParams -ErrorAction Stop | 
        Export-Certificate -FilePath "C:\certs\$_.cer"
    }
    catch {
        Write-Warning "Failed to request certificate for $_: $($_.Exception.Message)"
    }
}
  • Always check event logs (Applications and Services Logs > Microsoft > Windows > CEP) for enrollment errors
  • Verify network connectivity to the CEP server on port 443
  • Ensure the certificate template permissions are correctly configured
  • Check that the requesting computer account has enroll permissions

Manually configuring certificate enrollment through GUI tools like gpedit.msc and MMC snap-ins creates significant overhead for administrators, especially when deploying certificates across multiple servers. The current workflow requires:

  • 7+ GUI navigation steps
  • Multiple credential prompts
  • Registry modifications (HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Cryptography)
  • No audit trail of changes

For Server 2008/2012 environments, we can leverage these key components:

# Required modules
Import-Module PKI
Import-Module GroupPolicy
# Define CEP server parameters
$cepUri = "https://cep.yourdomain.com/ADPolicyProvider_CEP_UsernamePassword/service.svc"
$credential = Get-Credential

# Configure enrollment policy
$policy = @{
    URL = $cepUri
    Credential = $credential
    AuthenticationType = "UsernamePassword"
    PolicyID = (New-Guid).Guid
    CacheStoreLocation = "LocalMachine"
}

Set-CertificateEnrollmentPolicyServer @policy -Enable

The complete certificate request process including SAN specification:

$certParams = @{
    Template = "WebServer"
    SubjectName = "CN=server01.yourdomain.com"
    DnsName = "server01.yourdomain.com","altname.yourdomain.com"
    CertStoreLocation = "Cert:\LocalMachine\My"
}

$cert = Get-Certificate @certParams -Url $cepUri -Credential $credential

# Verify installation
Get-ChildItem Cert:\LocalMachine\My | 
    Where-Object { $_.Thumbprint -eq $cert.Certificate.Thumbprint }

For environments where Group Policy isn't available:

# Create registry structure
$regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\CertificateEnrollmentPolicy\"
New-Item -Path $regPath -Force | Out-Null

# Configure policy
$policyReg = @{
    Path = $regPath + (New-Guid).Guid
    PropertyType = "String"
    Value = @"
<PolicyServer>
    <URL>https://cep.yourdomain.com/ADPolicyProvider_CEP_UsernamePassword/service.svc</URL>
    <AuthType>UsernamePassword</AuthType>
    <Enabled>1</Enabled>
</PolicyServer>
"@
}
New-ItemProperty @policyReg -Force

Essential checks for production scripts:

try {
    $testResult = Test-Certificate -Url $cepUri -AuthenticationType UsernamePassword -Credential $credential
    if (-not $testResult.EnrollmentReady) {
        throw "CEP endpoint validation failed"
    }
}
catch {
    Write-Error "CEP configuration failed: $_"
    # Add logging or remediation steps
}
  • Store credentials securely using Export-CliXml/Import-CliXml
  • Implement retry logic for temporary network issues
  • Consider certificate template compatibility across server versions
  • Audit certificate expiration dates in automation scripts