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


23 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