How to Manage Certificates with PowerShell on Windows Server 2012 R2
Certificate management is a critical administrative task on Windows Server 2012 R2 — SSL/TLS certificates secure IIS websites, SMTP relay, LDAPS, Remote Desktop, PowerShell Remoting, and many other services. Without proactive certificate lifecycle management, expired certificates cause service outages, authentication failures, and security warnings that impact both operations and user trust. PowerShell provides comprehensive certificate management capabilities through the PKI module and direct certificate store access via the cert: PSDrive, enabling scripted certificate inventory, monitoring, request, and renewal operations.
This guide covers the complete certificate management lifecycle on Windows Server 2012 R2 using PowerShell: browsing certificate stores, checking expiry dates, generating certificate signing requests, importing and exporting certificates, managing the certificate revocation list, and automating expiry monitoring across server environments.
Prerequisites
– Windows Server 2012 R2 with PowerShell 4.0
– Administrative credentials (certificate management requires elevation)
– Access to a Certificate Authority (enterprise CA via Active Directory Certificate Services, or public CA)
– The PKI module is included with WS2012 R2 (no additional installation required)
– OpenSSL (optional, for cross-platform certificate operations)
Step 1: Browse Certificate Stores
The cert: PSDrive provides a file-system-like interface for navigating Windows certificate stores:
# List all certificate store locations
Get-PSDrive cert | Format-List
# Navigate certificate stores like a filesystem
Get-ChildItem cert:LocalMachine | Select-Object Name # Store containers (My, Root, CA, etc.)
Get-ChildItem cert:CurrentUser | Select-Object Name
# List certificates in the Personal (My) store
Get-ChildItem cert:LocalMachineMy | Select-Object Subject, Thumbprint, NotBefore, NotAfter, HasPrivateKey
# List trusted root certificates
Get-ChildItem cert:LocalMachineRoot | Select-Object Subject, Thumbprint, NotAfter | Sort-Object NotAfter
# Pipe to filter expired roots
Get-ChildItem cert:LocalMachineRoot | Where-Object NotAfter -lt (Get-Date) |
Select-Object Subject, NotAfter
Step 2: Certificate Expiry Monitoring
One of the most important certificate management tasks is proactively monitoring for upcoming expirations:
# Find all certificates expiring within 60 days on the local machine
$warningDays = 60
$expiringSoon = Get-ChildItem -Path "cert:LocalMachine" -Recurse |
Where-Object { $_ -is [System.Security.Cryptography.X509Certificates.X509Certificate2] } |
Where-Object { $_.NotAfter -lt (Get-Date).AddDays($warningDays) -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, Thumbprint, NotAfter,
@{N="Store"; E={ $_.PSParentPath -replace ".*::", "" }},
@{N="DaysLeft"; E={ ($_.NotAfter - (Get-Date)).Days }}
$expiringSoon | Sort-Object DaysLeft | Format-Table -AutoSize
# Script for multi-server certificate expiry audit
$servers = @("WebServer01","AppServer01","DBServer01")
$certReport = Invoke-Command -ComputerName $servers -ScriptBlock {
Get-ChildItem cert:LocalMachineMy |
Select-Object Subject, Thumbprint,
@{N="NotAfter"; E={$_.NotAfter}},
@{N="DaysLeft"; E={($_.NotAfter-(Get-Date)).Days}},
HasPrivateKey
} | Where-Object DaysLeft -lt 90 | Sort-Object DaysLeft
$certReport | Export-Csv "C:ReportsCertExpiry_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Step 3: Generate a Certificate Signing Request (CSR)
Use PowerShell to generate a CSR for submission to an internal or public Certificate Authority:
# Generate a CSR using certreq and a configuration INF file
$infContent = @"
[NewRequest]
Subject = "CN=webserver.domain.com, O=My Company, L=New York, S=NY, C=US"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = False
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
HashAlgorithm = SHA256
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.7.3.1 ; Server Authentication
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "dns=webserver.domain.com&"
_continue_ = "dns=webserver&"
_continue_ = "dns=192.168.1.50&"
"@
$infFile = "C:Tempcertrequest.inf"
$csrFile = "C:Tempcertrequest.csr"
$infContent | Out-File $infFile -Encoding ASCII
certreq -new $infFile $csrFile
Write-Host "CSR generated at $csrFile"
Write-Host "Submit this CSR to your Certificate Authority"
Step 4: Request a Certificate from an Enterprise CA
For domain environments with Active Directory Certificate Services, use PowerShell to request certificates directly from the enterprise CA:
# Request a certificate using a certificate template from enterprise CA
# Requires: Active Directory Certificate Services with appropriate templates
# Method 1: Using Get-Certificate (Windows 8.1/2012 R2 and later)
$cert = Get-Certificate `
-Template "WebServer" `
-DnsName "webserver.domain.com","webserver","192.168.1.50" `
-CertStoreLocation cert:LocalMachineMy
Write-Host "Certificate issued with thumbprint: $($cert.Certificate.Thumbprint)"
# Method 2: Using certreq to submit to a CA
# After receiving .cer file from CA:
certreq -accept "C:Tempissued_cert.cer"
# Verify the cert is in the personal store with private key
Get-ChildItem cert:LocalMachineMy | Where-Object Subject -like "*webserver*" |
Select-Object Subject, Thumbprint, NotAfter, HasPrivateKey
Step 5: Create a Self-Signed Certificate
For internal testing or services that cannot use a CA-issued certificate, create self-signed certificates:
# Create a self-signed certificate for TLS (valid 2 years)
$selfSigned = New-SelfSignedCertificate `
-DnsName "internalserver.domain.com","internalserver","10.0.0.50" `
-CertStoreLocation "cert:LocalMachineMy" `
-NotAfter (Get-Date).AddYears(2) `
-KeyUsage DigitalSignature, KeyEncipherment `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1") `
-HashAlgorithm SHA256 `
-KeyLength 2048 `
-FriendlyName "Internal Server TLS"
Write-Host "Self-signed certificate created:"
Write-Host " Thumbprint: $($selfSigned.Thumbprint)"
Write-Host " Subject: $($selfSigned.Subject)"
Write-Host " Valid until: $($selfSigned.NotAfter)"
Step 6: Export Certificates
Export certificates for backup, deployment to other servers, or submission to services:
# Export certificate WITH private key to PFX (requires private key access)
$cert = Get-ChildItem cert:LocalMachineMy | Where-Object Thumbprint -eq "ABCDEF1234567890..."
$password = ConvertTo-SecureString -String "ExportP@ssword123" -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath "C:Certsserver_cert.pfx" -Password $password
# Export certificate WITHOUT private key to CER (public certificate only)
Export-Certificate -Cert $cert -FilePath "C:Certsserver_cert.cer" -Type CERT
# Export to Base64 DER format (for web server config or CSR submission)
Export-Certificate -Cert $cert -FilePath "C:Certsserver_cert.cer" -Type CERT
certutil -encode "C:Certsserver_cert.cer" "C:Certsserver_cert.pem"
Step 7: Import Certificates
# Import a PFX certificate to the Personal store
$password = ConvertTo-SecureString "ImportP@ssword" -AsPlainText -Force
$imported = Import-PfxCertificate `
-FilePath "C:Certsserver_cert.pfx" `
-CertStoreLocation "cert:LocalMachineMy" `
-Password $password `
-Exportable
Write-Host "Imported: $($imported.Thumbprint)"
# Import a CER (public certificate only) to Trusted Root
Import-Certificate -FilePath "C:CertsRootCA.cer" -CertStoreLocation "cert:LocalMachineRoot"
# Import a CER to Intermediate Certification Authorities
Import-Certificate -FilePath "C:CertsIntermediateCA.cer" -CertStoreLocation "cert:LocalMachineCA"
Step 8: Bind Certificates to Services
After importing a certificate, bind it to the appropriate services:
# Bind an SSL certificate to IIS website port 443
Import-Module WebAdministration
$thumbprint = "ABCDEF1234567890ABCDEF1234567890..."
$siteName = "Default Web Site"
# Remove existing HTTPS binding
Remove-WebBinding -Name $siteName -Protocol https -Port 443 -ErrorAction SilentlyContinue
# Create new HTTPS binding
New-WebBinding -Name $siteName -Protocol https -Port 443 -IPAddress "*" -SslFlags 0
# Assign the certificate to the binding
$binding = Get-WebBinding -Name $siteName -Protocol https
$binding.AddSslCertificate($thumbprint, "my")
Write-Host "SSL certificate bound to IIS site $siteName"
# Bind a certificate to WinRM HTTPS (port 5986)
New-Item -Path WSMan:localhostListener -Transport HTTPS -Address * -CertificateThumbprint $thumbprint -Force
Step 9: Remove and Clean Up Certificates
# Remove a specific certificate by thumbprint
Get-ChildItem cert:LocalMachineMy |
Where-Object Thumbprint -eq "ABCDEF1234567890..." |
Remove-Item
# Remove all expired certificates from all local machine stores
Get-ChildItem cert:LocalMachine -Recurse |
Where-Object { $_ -is [System.Security.Cryptography.X509Certificates.X509Certificate2] } |
Where-Object { $_.NotAfter -lt (Get-Date) } |
ForEach-Object {
Write-Host "Removing expired cert: $($_.Subject) (expired $($_.NotAfter.ToShortDateString()))"
Remove-Item -Path $_.PSPath
}
Step 10: Automate Certificate Expiry Alerts
# Scheduled script for daily certificate expiry email alerts
function Send-CertExpiryAlert {
param(
[string[]]$Servers,
[int]$WarnDays = 30,
[string]$EmailTo = "[email protected]",
[string]$SmtpServer = "smtp.domain.com"
)
$expiring = Invoke-Command -ComputerName $Servers -ScriptBlock {
param($warn)
Get-ChildItem cert:LocalMachineMy |
Where-Object { $_.NotAfter -lt (Get-Date).AddDays($warn) -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, Thumbprint, NotAfter,
@{N="DaysLeft"; E={($_.NotAfter-(Get-Date)).Days}}
} -ArgumentList $WarnDays | Where-Object DaysLeft -lt $WarnDays
if ($expiring.Count -gt 0) {
$body = $expiring | ConvertTo-Html -Title "Certificate Expiry Alert" | Out-String
Send-MailMessage -To $EmailTo -From "[email protected]" -Subject "Certificate Expiry Warning" `
-Body $body -BodyAsHtml -SmtpServer $SmtpServer
}
}
Send-CertExpiryAlert -Servers @("WebServer01","AppServer01") -WarnDays 30
Summary
PowerShell provides a comprehensive certificate management platform for Windows Server 2012 R2, covering every phase of the certificate lifecycle from initial generation and CSR creation through import, service binding, and eventual removal. The cert: PSDrive’s file-system-like navigation, combined with cmdlets like Get-Certificate, Export-PfxCertificate, and Import-Certificate, enables fully scriptable certificate management that can be automated through scheduled tasks and PowerShell Remoting to manage certificates across entire server estates. Proactive expiry monitoring through scheduled scripts eliminates the operational risk of certificate-caused outages, which is one of the most preventable yet frequently occurring disruptions in enterprise server environments.