The Windows tools for finding, checking, requesting and installing certificates, organised around four everyday jobs: renewing a server certificate, fixing an untrusted chain, moving a certificate to a new server, and publishing a template on an AD CS issuing CA.
Ask AI about this cheatsheetChatGPT, Claude, or any assistant
These open a new chat with a prompt that points the assistant to this cheatsheet. It only sees the cheatsheet if it can open the link. If it says it can't, use Copy cheatsheet for AI and paste the text into the chat.
Nothing goes to an AI service unless you choose one. AI answers can be wrong: check them against the cheatsheet before you change anything important.
Every example uses made-up people and names: the domain corp.example.com, the server app01.corp.example.com and a CA called Example Issuing CA. <thumbprint> stands for the certificate's SHA-1 thumbprint, which the first job shows you how to find. Everything here was checked against Microsoft Learn, not lab-tested (October 27, 2026).
Microsoft's own caution on certutil: it "isn't recommended to be used in any production code". It's a tool for looking at certificates by hand. For scripts, use the PowerShell Cert: drive.
Before you start: consoles and stores#
| Console | Opens |
|---|---|
certlm.msc | Certificates for the local computer (all users, and services that run as the computer) |
certmgr.msc | Certificates for the current user |
certtmpl.msc | Certificate templates in AD DS (on a CA or a machine with the AD CS tools) |
The certutil page lists the short store names but not the console names. The console names below follow Microsoft's .NET StoreName documentation, which describes My as the store "for personal certificates", Root as the one "for trusted root certificate authorities" and CertificateAuthority (CA in commands) as the one "for intermediate certificate authorities".
| Name in commands | Name in the console | Holds |
|---|---|---|
My | Personal | This computer's (or user's) own certificates, usually with private keys |
Root | Trusted Root Certification Authorities | Trust anchors |
CA | Intermediate Certification Authorities | Intermediate CA certificates |
NTAuth (with -enterprise) | n/a | The forest's NTAuth store, used for certificate-based domain sign-in |
certutil uses the local computer's stores unless you add -user. In PowerShell, the same stores are Cert:\LocalMachine\<name> and Cert:\CurrentUser\<name>.
Certificates on Windows: four everyday jobs#
The next four sections each walk through one common job: renewing a server certificate before it expires, fixing a chain that a client won't trust, moving a certificate and its key to a new server, and publishing a certificate template on an issuing CA. Each one starts with a short situation, finds out what's going on with read-only commands, makes the change (each step labelled, with -WhatIf first wherever the command supports it), confirms it worked, and lists what to try if it didn't. A quick-reference table closes each section.
Renew a server certificate before it expires#
The situation: an expiry warning for app01#
Tuesday morning. Lee Park, who looks after the intranet at corp.example.com, gets a monitoring alert: the HTTPS certificate on app01.corp.example.com expires in 21 days. Staff reach the site as both app01.corp.example.com and app.corp.example.com, and both names have to keep working.
Find out what's going on (read-only)#
Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 30 # expires within 30 days
Get-ChildItem Cert:\LocalMachine\My |
Format-List Subject, Issuer, NotAfter, Thumbprint, HasPrivateKey, DnsNameList, EnhancedKeyUsageList
Get-ChildItem Cert:\LocalMachine\My -SSLServerAuthentication # Server Authentication EKU
Get-ChildItem Cert:\LocalMachine\My -DnsName "*.corp.example.com"
Get-ChildItem Cert:\LocalMachine -Recurse -ExpiringInDays 0 # already expired, every store
certutil -store My # the same Personal store, through certutil
certutil -q -v -store My # verbose: every extension, the template and the key provider
certutil -store My <thumbprint> # one certificate
PS> Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 30 | Format-List Subject, NotAfter, Thumbprint, HasPrivateKey, DnsNameList
Subject : CN=app01.corp.example.com
NotAfter : 11/17/2026 9:00:00 AM
Thumbprint : <thumbprint>
HasPrivateKey : True
DnsNameList : {app01.corp.example.com, app.corp.example.com}
Look for: the NotAfter date, HasPrivateKey : True (the certificate has its private key on this computer), and every name staff use in DnsNameList. DnsNameList comes from the SAN's DNS names, or from the subject if there's no SAN.
Make the change#
certreq -new creates a new private key on this computer as well as the request file. certreq -accept installs the issued certificate.
app01.corp.example.com is an internal name, so the certificate comes from the company's enterprise CA, Example Issuing CA, not a public one. This request file asks for a server certificate with a SAN and the Server Authentication EKU (1.3.6.1.5.5.7.3.1), and, in [RequestAttributes], names the WebServer template, as the example on Microsoft's certreq page does. An enterprise CA issues certificates from templates, so name one it publishes. Save it as app01.inf. The [Extensions] section carries both the SAN (2.5.29.17) and the EKU (2.5.29.37), using the {text} form that the certreq page's [Extensions] table gives for each; Microsoft's LDAPS page uses a separate [EnhancedKeyUsageExtension] section for the EKU instead. Both forms are documented. Keep Exportable = FALSE unless you have to move the key to another machine; Microsoft's certreq page says that for "a high level of security, private keys shouldn't be exportable".
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject = "CN=app01.corp.example.com"
KeyLength = 2048
KeySpec = 1
KeyUsage = 0xa0 ; digital signature + key encipherment
Exportable = FALSE
MachineKeySet = TRUE ; key belongs to the computer, not to you
RequestType = PKCS10
[RequestAttributes]
CertificateTemplate = WebServer ; the template the enterprise CA issues from
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "DNS=app01.corp.example.com&"
_continue_ = "DNS=app.corp.example.com"
2.5.29.37 = "{text}1.3.6.1.5.5.7.3.1"
certreq -new .\app01.inf .\app01.req # creates the key and the request (CSR)
certutil -dump .\app01.req # read-only: check names, EKU and template before you send it
Send the request to the CA. -config names the CA as CAHostName\CAName; replace <CAHost> with the CA server's name. If the CA issues it straight away, certreq saves it as app01.cer.
certreq -submit -config "<CAHost>\Example Issuing CA" .\app01.req .\app01.cer
certreq -accept .\app01.cer # installs the issued certificate and links it to the key
certreq -accept needs no -machine here: the certreq page says the -user and -machine options aren't needed when there's an outstanding request that matches the certificate, and certreq -new left one on this computer.
If the CA is an enterprise CA in your forest, you can enroll from a template instead of writing an INF:
certreq -enroll -machine -policyserver * WebServer # enroll from an enterprise CA template
certreq -autoenroll -q # trigger autoenrollment now
gpupdate /force # autoenrollment also runs when Group Policy refreshes
Confirm it worked#
Get-ChildItem Cert:\LocalMachine\My -DnsName "app.corp.example.com" |
Format-List Subject, NotAfter, Thumbprint, HasPrivateKey, DnsNameList
certutil -verifystore My <thumbprint> # check the new certificate's chain
Look for: a new certificate with a later NotAfter, HasPrivateKey : True, and both names in DnsNameList. Then point the site's HTTPS binding at the new thumbprint (in IIS Manager, or whatever runs the site) and browse to both names.
If it didn't work#
HasPrivateKeyis False aftercertreq -accept. The certificate didn't link to the key thatcertreq -newcreated, often because the request was made on another computer or as another user. On the computer that made the request,certutil -repairstore My <thumbprint>re-links an installed certificate to its private key (this changes the store).- One name works and the other gives a name error. That name isn't in the SAN. Modern clients match the SAN and ignore the subject, so add it to the INF and request again.
- The CA rejects the request or leaves it pending. Check the template. Microsoft's checks for a template a requester can't use (in Manage certificate templates in Windows Server) are that the CA is an enterprise CA, the template is on that CA's issuance list (
Get-CATemplateon the CA lists it), AD DS replication is complete, and you have Read and Enroll permissions on the template. A pending request waits for the CA administrator; once it's issued,certreq -retrieve -config "<CAHost>\Example Issuing CA" <requestid> .\app01.cerfetches it.
Quick reference: renew a server certificate#
| Command | What it does | Read-only or changes something |
|---|---|---|
Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 30 | Lists Personal certificates that expire within 30 days | Read-only |
Get-ChildItem Cert:\LocalMachine -Recurse -ExpiringInDays 0 | Lists already-expired certificates in every store | Read-only |
Get-ChildItem Cert:\LocalMachine\My -SSLServerAuthentication | Lists certificates with the Server Authentication EKU (or no EKU) | Read-only |
Get-ChildItem Cert:\LocalMachine\My -DnsName "*.corp.example.com" | Finds certificates by DNS name | Read-only |
Get-ChildItem Cert:\LocalMachine\My -EKU "*Client Authentication*" | Finds certificates by EKU (or no EKU) | Read-only |
certutil -store My | Lists the local computer Personal store (-user for yours) | Read-only |
certutil -q -v -store My | Verbose: every extension, the template and the key provider | Read-only |
certreq -new app01.inf app01.req | Creates a private key and a request | Changes this computer |
certutil -dump app01.req | Decodes a certificate, request or CRL file | Read-only |
certreq -submit -config "<CAHost>\Example Issuing CA" app01.req app01.cer | Sends the request to the CA and saves the issued certificate | CA submission (the CA issues a certificate) |
certreq -retrieve -config "<CAHost>\Example Issuing CA" <requestid> app01.cer | Fetches a certificate after the CA has issued a pending request | Writes a file (certificate only) |
certreq -accept app01.cer | Installs the issued certificate and links it to the key | Changes this computer |
certreq -enroll -machine -policyserver * WebServer | Enrolls from an enterprise CA template | Changes this computer |
certreq -autoenroll -q | Triggers autoenrollment now | Changes this computer |
certutil -repairstore My <thumbprint> | Re-links an installed certificate to its private key | Changes this computer |
Fix a chain a client won't trust#
The situation: an untrusted root on a new laptop#
Ana Silva at corp.example.com rebuilt a laptop from a fresh Windows image. Now every internal site warns that its certificate isn't trusted, though the same sites work on everyone else's machine. The internal certificates come from Example Issuing CA, which chains to the company's own root.
Find out what's going on (read-only)#
Copy the site's certificate to the laptop as app01.cer (export it from the browser, or from certlm.msc on the server without the key), then:
certutil -verify .\app01.cer # build the chain and check it with the local stores
certutil -verify -urlfetch .\app01.cer # also fetch and check the AIA and CDP URLs
certutil -store Root # trusted roots (local computer)
certutil -store CA # intermediates; also what "certutil -store" shows with no store name
certutil -enumstore # list the store names on this computer
certutil -enterprise -store NTAuth # CAs in the forest's NTAuth store
certutil -dump .\example-root-ca.cer # decode the root you plan to trust
certutil -hashfile .\example-root-ca.cer SHA256 # file hash, to compare two copies
-urlfetch downloads the issuer certificates (AIA) and CRLs (CDP) named in the certificate, so it needs network access to those addresses.
PS> certutil -verify .\app01.cer
Issuer:
CN=Example Issuing CA
Subject:
CN=app01.corp.example.com
...
A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
Look for: whether the chain stops at the root (the root is missing from Root) or before it (an intermediate is missing from CA, and -urlfetch can't fetch it either). Compare the root's -hashfile output with a copy you got from the CA administrator another way.
Make the change#
Add the company root to the laptop's trusted roots. Before you add it by hand, ask the CA administrator how other machines get this root; if that process skipped the rebuilt laptop, fix it too.
certutil -addstore Root .\example-root-ca.cer # every user and service on this computer will trust this root
Confirm it worked#
certutil -verify .\app01.cer
certutil -verifystore My <thumbprint> # on the server: check a certificate that's already installed
The untrusted-root message should be gone. Then reopen the site in the browser.
If it didn't work#
- It still fails, but now at the intermediate. The laptop can't reach the AIA address, or the intermediate isn't published there. Run
certutil -verify -urlfetchfrom the laptop to see which address fails, and fix the network path or the CA's publication rather than piling certificates into stores. - Smart card or certificate sign-in to the domain still fails. That uses the forest's NTAuth store, not the laptop's Root store. Check that
certutil -enterprise -store NTAuthlists the issuing CA, and talk to whoever runs the CA.
Quick reference: chain and trust#
| Command | What it does | Read-only or changes something |
|---|---|---|
certutil -verify app01.cer | Builds the chain and checks it with the local stores | Read-only |
certutil -verify -urlfetch app01.cer | Also fetches and checks the AIA and CDP URLs | Read-only (connects over the network) |
certutil -verifystore My <thumbprint> | Checks a certificate that's already installed | Read-only |
certutil -store Root / certutil -store CA | Lists trusted roots / intermediates | Read-only |
certutil -enumstore | Lists the store names on this computer | Read-only |
certutil -enterprise -store NTAuth | Shows the CAs in the forest's NTAuth store | Read-only |
certutil -hashfile file.cer SHA256 | File hash, to compare two copies | Read-only |
certutil -addstore Root example-root-ca.cer | Trusts a root for every user and service on this computer | Changes this computer |
Move a certificate to a new server#
The situation: app01 moves to new hardware#
The intranet is moving from app01 to a new server, and Lee wants the new box to answer as app.corp.example.com with the same certificate until the next renewal. The old certificate has to go from app01 once the move is done.
Find out what's going on (read-only)#
Get-ChildItem Cert:\LocalMachine\My -DnsName "app.corp.example.com" |
Format-List Subject, NotAfter, Thumbprint, HasPrivateKey
certutil -store My <thumbprint>
Look for: HasPrivateKey : True. Without the key on this computer, there's nothing to move: request a new certificate on the new server instead (see the first job).
Make the change#
On the old server, export the certificate and key. Leave the password off the command line, so it doesn't end up in your shell history.
certutil -exportPFX My <thumbprint> .\app01.pfx # exports certificate AND private key
On the new server, import it. certutil's NoExport modifier "Makes the private key non-exportable", which matches the Exportable = FALSE advice in the first job.
certutil -importPFX My .\app01.pfx NoExport # imports certificate and key into the local computer Personal store; the key can't be exported again
Before you touch app01, bind the certificate to the site on the new server, test HTTPS against the new server, and move traffic to it. Only then remove the old copy from app01 and delete the PFX. Try -WhatIf on the PowerShell command first.
Remove-Item Cert:\LocalMachine\My\<thumbprint> -WhatIf # on app01: preview
Remove-Item Cert:\LocalMachine\My\<thumbprint> -DeleteKey # on app01: deletes the certificate and its private key
certutil -delstore My <thumbprint> # or: deletes the certificate from the store
Confirm it worked#
Get-ChildItem Cert:\LocalMachine\My -DnsName "app.corp.example.com" |
Format-List Subject, NotAfter, Thumbprint, HasPrivateKey # on the new server: HasPrivateKey True
certutil -verifystore My <thumbprint>
On app01, the same Get-ChildItem should return nothing. Then delete the working copy of app01.pfx.
If it didn't work#
- The export refuses. The key was created with
Exportable = FALSE, which is the safer default. Request a new certificate on the new server instead of trying to force the key out. - The import works but
HasPrivateKeyis False. Runcertutil -repairstore My <thumbprint>on the new server to re-link the certificate to its key, then check again.
Quick reference: move a certificate#
| Command | What it does | Read-only or changes something |
|---|---|---|
certutil -store My <thumbprint> | Shows one certificate | Read-only |
certutil -exportPFX My <thumbprint> app01.pfx | Exports the certificate and private key | Changes this computer (writes the key to a file) |
certutil -importPFX My app01.pfx NoExport | Imports certificate and key into the local computer Personal store, key not exportable | Changes this computer |
Remove-Item Cert:\LocalMachine\My\<thumbprint> -WhatIf | Previews the delete | Read-only (preview) |
Remove-Item Cert:\LocalMachine\My\<thumbprint> -DeleteKey | Deletes the certificate and its private key | Changes this computer |
certutil -delstore My <thumbprint> | Deletes the certificate from the store | Changes this computer |
certutil -repairstore My <thumbprint> | Re-links an installed certificate to its private key | Changes this computer |
Publish a template on the issuing CA (AD CS)#
The situation: a pilot web server template#
Morgan Diaz, who runs Example Issuing CA, has built a new template with the short name PilotWebServer in certtmpl.msc. Two web teams want to try it before it replaces the old one, so Morgan needs the CA to start issuing it without disturbing anything else.
Find out what's going on (read-only)#
Run these on an enterprise issuing CA with the ADCSAdministration module. Get-CATemplate lists what the CA issues; template names are short names without spaces, not display names.
Get-CATemplate
Add-CATemplate -Name "PilotWebServer" -WhatIf # preview only
Look for: PilotWebServer isn't in the list yet, and the -WhatIf preview names the template you expect.
Make the change#
Add-CATemplate -Name "PilotWebServer" # the CA starts issuing this template
Confirm it worked#
Get-CATemplate # PilotWebServer is now listed
Then ask one of the pilot teams to enroll a test server with certreq -enroll -machine -policyserver * PilotWebServer.
If it didn't work, or you need to roll back#
- You need to undo it. Microsoft says "the usual first rollback action is to remove the new template from the affected CA's issuance list, not delete its AD DS object". Preview, then remove it. Removing a template doesn't revoke certificates already issued from it.
- Don't use
Remove-CATemplate -AllTemplatesto undo one template: it removes every removable template from the CA.
Remove-CATemplate -Name "PilotWebServer" -WhatIf # preview only
Remove-CATemplate -Name "PilotWebServer" # the CA stops issuing it; issued certificates stay valid
Quick reference: AD CS templates#
| Command | What it does | Read-only or changes something |
|---|---|---|
Get-CATemplate | Lists the templates the CA issues | Read-only |
Add-CATemplate -Name "PilotWebServer" -WhatIf | Previews publishing a template | Read-only (preview) |
Add-CATemplate -Name "PilotWebServer" | The CA starts issuing the template | Changes the CA |
Remove-CATemplate -Name "PilotWebServer" -WhatIf | Previews removing a template | Read-only (preview) |
Remove-CATemplate -Name "PilotWebServer" | The CA stops issuing it; issued certificates stay valid | Changes the CA |
Related#
- OpenSSL certificate inspection: the same checks from Linux or macOS, including a live server with
s_client. - Certificates explained: what the subject, SAN, EKU, chain and CRL fields mean.
Sources and official documentation
- Microsoft Learn: certutil
- Microsoft Learn: certreq
- Microsoft Learn: How to view certificates with the MMC snap-in (certlm.msc and certmgr.msc)
- Microsoft Learn: about_Certificate_Provider (PowerShell 7.5)
- Microsoft Learn: about_Certificate_Provider (Windows PowerShell 5.1)
- Microsoft Learn: StoreName enum (what My, Root and CertificateAuthority hold)
- Microsoft Learn: X509Certificate2.HasPrivateKey
- Microsoft Learn: Configure certificates for LDAP over SSL in AD DS
- Microsoft Learn: Windows Hello for Business on-premises certificate trust deployment guide (certutil -q -v -store my, certreq -autoenroll -q, NTAuth)
- Microsoft Learn: Manage certificate templates in Windows Server
- Microsoft Learn: Get-CATemplate
- RFC 9525: Service Identity in TLS (the SAN, not the common name, identifies the server)
- Apple: Requirements for trusted certificates in iOS 13 and macOS 10.15 (SAN, not CommonName)
- Microsoft Learn: Add-CATemplate
- Microsoft Learn: Remove-CATemplate
Review history
- Technical review: Jeremiah Ellington,
- Editorial review: Jeremiah Ellington,
- Next scheduled review:
Spotted something out of date or wrong? Email a correction and I'll fix it. See how these guides are made.