Skip to content

Practical technology help for homes and small businesses, from someone who knows how to make it work. Based in Martinez, serving Contra Costa County.

Practical IT guides, cheatsheets, and references from Jeremiah Ellington, drawn from more than 20 years of IT work in public sector and higher education.

Contact Info
Location Martinez, CA (Serving Contra Costa County)
Contact Info
Location Martinez, CA (Serving Contra Costa County)

Cheatsheet

Windows Certificate Commands Cheatsheet

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.

  • Applies to: Windows Server 2016 to 2025 and Windows 11: certutil, certreq, certlm.msc and certmgr.msc; the PowerShell Cert: drive in Windows PowerShell 5.1 and PowerShell 7.6 (the -DnsName, -EKU, -ExpiringInDays and -SSLServerAuthentication filters need 5.1 or 7.1 and later); the ADCSAdministration module on an enterprise issuing CA. Checked against Microsoft Learn on 2026-10-27, not lab-tested
  • Last reviewed

Free, no email required.

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#

ConsoleOpens
certlm.mscCertificates for the local computer (all users, and services that run as the computer)
certmgr.mscCertificates for the current user
certtmpl.mscCertificate 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 commandsName in the consoleHolds
MyPersonalThis computer's (or user's) own certificates, usually with private keys
RootTrusted Root Certification AuthoritiesTrust anchors
CAIntermediate Certification AuthoritiesIntermediate CA certificates
NTAuth (with -enterprise)n/aThe 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)#

PowerShellRead-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
Plain textSample output (illustrative)
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".

INIapp01.inf (example)
[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"
PowerShellChanges this computer: creates a key and the request
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.

PowerShellCA submission: the CA issues a certificate from this request
certreq -submit -config "<CAHost>\Example Issuing CA" .\app01.req .\app01.cer
PowerShellChanges this computer: installs the certificate
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:

PowerShellChanges this computer: enrolls from an enterprise CA
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#

PowerShellRead-only
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#

  • HasPrivateKey is False after certreq -accept. The certificate didn't link to the key that certreq -new created, 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-CATemplate on 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.cer fetches it.

Quick reference: renew a server certificate#

CommandWhat it doesRead-only or changes something
Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 30Lists Personal certificates that expire within 30 daysRead-only
Get-ChildItem Cert:\LocalMachine -Recurse -ExpiringInDays 0Lists already-expired certificates in every storeRead-only
Get-ChildItem Cert:\LocalMachine\My -SSLServerAuthenticationLists certificates with the Server Authentication EKU (or no EKU)Read-only
Get-ChildItem Cert:\LocalMachine\My -DnsName "*.corp.example.com"Finds certificates by DNS nameRead-only
Get-ChildItem Cert:\LocalMachine\My -EKU "*Client Authentication*"Finds certificates by EKU (or no EKU)Read-only
certutil -store MyLists the local computer Personal store (-user for yours)Read-only
certutil -q -v -store MyVerbose: every extension, the template and the key providerRead-only
certreq -new app01.inf app01.reqCreates a private key and a requestChanges this computer
certutil -dump app01.reqDecodes a certificate, request or CRL fileRead-only
certreq -submit -config "<CAHost>\Example Issuing CA" app01.req app01.cerSends the request to the CA and saves the issued certificateCA submission (the CA issues a certificate)
certreq -retrieve -config "<CAHost>\Example Issuing CA" <requestid> app01.cerFetches a certificate after the CA has issued a pending requestWrites a file (certificate only)
certreq -accept app01.cerInstalls the issued certificate and links it to the keyChanges this computer
certreq -enroll -machine -policyserver * WebServerEnrolls from an enterprise CA templateChanges this computer
certreq -autoenroll -qTriggers autoenrollment nowChanges this computer
certutil -repairstore My <thumbprint>Re-links an installed certificate to its private keyChanges 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:

PowerShellRead-only
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.

Plain textSample output (illustrative, trimmed)
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.

PowerShellChanges this computer: every user and service will trust this root
certutil -addstore Root .\example-root-ca.cer   # every user and service on this computer will trust this root

Confirm it worked#

PowerShellRead-only
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 -urlfetch from 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 NTAuth lists the issuing CA, and talk to whoever runs the CA.

Quick reference: chain and trust#

CommandWhat it doesRead-only or changes something
certutil -verify app01.cerBuilds the chain and checks it with the local storesRead-only
certutil -verify -urlfetch app01.cerAlso fetches and checks the AIA and CDP URLsRead-only (connects over the network)
certutil -verifystore My <thumbprint>Checks a certificate that's already installedRead-only
certutil -store Root / certutil -store CALists trusted roots / intermediatesRead-only
certutil -enumstoreLists the store names on this computerRead-only
certutil -enterprise -store NTAuthShows the CAs in the forest's NTAuth storeRead-only
certutil -hashfile file.cer SHA256File hash, to compare two copiesRead-only
certutil -addstore Root example-root-ca.cerTrusts a root for every user and service on this computerChanges 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)#

PowerShellRead-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.

PowerShellChanges this computer: writes the private key to a file
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.

PowerShellChanges this computer: imports the certificate and key
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.

PowerShellChanges app01: removes the old certificate and key
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#

PowerShellRead-only
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 HasPrivateKey is False. Run certutil -repairstore My <thumbprint> on the new server to re-link the certificate to its key, then check again.

Quick reference: move a certificate#

CommandWhat it doesRead-only or changes something
certutil -store My <thumbprint>Shows one certificateRead-only
certutil -exportPFX My <thumbprint> app01.pfxExports the certificate and private keyChanges this computer (writes the key to a file)
certutil -importPFX My app01.pfx NoExportImports certificate and key into the local computer Personal store, key not exportableChanges this computer
Remove-Item Cert:\LocalMachine\My\<thumbprint> -WhatIfPreviews the deleteRead-only (preview)
Remove-Item Cert:\LocalMachine\My\<thumbprint> -DeleteKeyDeletes the certificate and its private keyChanges this computer
certutil -delstore My <thumbprint>Deletes the certificate from the storeChanges this computer
certutil -repairstore My <thumbprint>Re-links an installed certificate to its private keyChanges 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.

PowerShellRead-only (-WhatIf previews; nothing runs)
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#

PowerShellChanges the CA
Add-CATemplate -Name "PilotWebServer"      # the CA starts issuing this template

Confirm it worked#

PowerShellRead-only
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 -AllTemplates to undo one template: it removes every removable template from the CA.
PowerShellChanges the CA: preview with -WhatIf first
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#

CommandWhat it doesRead-only or changes something
Get-CATemplateLists the templates the CA issuesRead-only
Add-CATemplate -Name "PilotWebServer" -WhatIfPreviews publishing a templateRead-only (preview)
Add-CATemplate -Name "PilotWebServer"The CA starts issuing the templateChanges the CA
Remove-CATemplate -Name "PilotWebServer" -WhatIfPreviews removing a templateRead-only (preview)
Remove-CATemplate -Name "PilotWebServer"The CA stops issuing it; issued certificates stay validChanges the CA

Sources and official documentation

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.