The Windows Certificate Store in Practice — User or Computer, Which Should You Use?
· Go Komura · Certificate, Windows, Security, PKI, TLS, PowerShell, Business Applications, Information Systems
“We reinstalled the client certificate for online eligibility verification onto the new terminal, and now it can’t connect.” “The dev machine can reach the bank API fine, but once it became a Windows service it says ‘certificate not found’.” “I can’t even tell which certificate is the real one — the one certmgr.msc shows, or the one certlm.msc shows.” — when you build Web API integrations that use client certificates as contract work, this kind of question comes up on a regular basis.
Online eligibility verification at healthcare institutions, electronic filing, banking APIs, EDI with business partners. Client certificates, once the exclusive territory of infrastructure staff at large enterprises, are now something IT staff and business-application developers at small and medium-sized companies handle themselves. And certificate-related incidents actually boil down to just a handful of patterns: putting the certificate in the wrong place, forgetting to grant private-key permissions, and forgetting about expiry — these three.
This article is aimed at developers of business applications that use client certificates and at IT staff who get assigned certificate-renewal work. Centred on the decision of whether to use the user store or the computer store, it works through everything in one pass — the structure of the Windows certificate store, granting private-key permissions, taking an expiry inventory with PowerShell, and the code for using a certificate from .NET. The content is based on primary Microsoft Learn sources as of August 2026.
1. The Bottom Line First
- The Windows certificate store comes in two systems: “User” (CurrentUser) and “Computer” (LocalMachine). The user store is separate per account (under the registry’s HKEY_CURRENT_USER), while the computer store is shared across the whole PC (under HKEY_LOCAL_MACHINE).12
- There are also two management tools. certmgr.msc opens the current user’s store, and certlm.msc opens the local computer’s store. From PowerShell these are
Cert:\CurrentUserandCert:\LocalMachine.34 - Which store to use is decided by “who the program that uses the certificate runs as”. As a rule, an interactive user’s app uses the user store, while unattended execution — a Windows service, IIS, or Task Scheduler — uses the computer store (the decision table in Section 3).
- “It worked while developing but can’t be found once it became a service” has almost one cause. A certificate a developer put in their own user store is invisible from the CurrentUser of a service running under a different account (Section 3).
- A certificate and its private key are different things. Merely placing a certificate in the computer store does not, by itself, let the service account read the private key — that is the normal situation. Grant read permission to the execution account through certlm.msc’s “Manage Private Keys”.5
- When importing a pfx, the private key is not exportable by default.
Import-PfxCertificateimports the private key in a form that cannot be re-exported unless you specify-Exportable. This is not a bug — it is the desirable default.6 - Expiry is prevented by automating the inventory.
Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60mechanically extracts certificates that will expire within the given number of days.4 - Hard-coding a thumbprint into code or configuration will kill you at every certificate renewal, because a new certificate’s thumbprint is always different. Externalising it into configuration, plus an old-and-new overlap period, is the basic design (Sections 5 and 7).
2. The Big Picture of Certificate Stores — Two Locations and the Logical Stores
2.1. Two Systems: User and Computer
The Windows certificate store is split, broadly, into two “locations”.1
- The computer (local computer, LocalMachine) certificate store: there is one per PC, and it is shared by all users and services on that PC. It physically lives under the registry key
HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates.2 - The user (current user, CurrentUser) certificate store: this is separate for each user account. It physically lives under
HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates, in other words, as part of the user profile.2
There is also a store per service account,3 which physically lives under a registry key per service name.2 For practical purposes, the two locations above are what you need to grasp first.
There is one important behaviour to note. Every logical store in the user store, except “Personal”, inherits and shows the contents of the same-named store in the computer store.1 For example, if you add a corporate CA’s certificate to “Trusted Root Certification Authorities” in the computer store, it also appears in “Trusted Root Certification Authorities” for every user. Conversely, only the “Personal” store is not inherited, so for a client certificate — something that goes into the personal store — you have to decide for yourself “who needs to be able to see this”. This asymmetry is the central character of this whole article.
flowchart TB
subgraph LM["Computer - LocalMachine<br/>One per PC, shared by all users and services"]
LMMY["Personal - My"]
LMROOT["Trusted Root Certification Authorities - Root"]
LMCA["Intermediate Certification Authorities - CA"]
LMTP["Trusted Publishers - TrustedPublisher"]
end
subgraph CU["User - CurrentUser<br/>Separate per account"]
CUMY["Personal - My<br/>Not inherited - you decide where to put it yourself"]
CUROOT["Trusted Root Certification Authorities - Root"]
CUCA["Intermediate Certification Authorities - CA"]
CUTP["Trusted Publishers - TrustedPublisher"]
end
LMROOT -.->|"content appears via inheritance"| CUROOT
LMCA -.->|"inherited"| CUCA
LMTP -.->|"inherited"| CUTP
2.2. The Main Logical Stores
Inside each location, contents are split into logical stores by role. These are the folders you see in certmgr.msc / certlm.msc; from PowerShell or the command line you use the English internal names.24
| Display name | Internal name | What goes here |
|---|---|---|
| Personal | My | Certificates used by yourself (this PC, this user). Client certificates and server certificates go here. This is also where a certificate is associated with its private key |
| Trusted Root Certification Authorities | Root | Root CA certificates that act as trust anchors. Anything issued under a CA placed here is “trusted” |
| Intermediate Certification Authorities | CA | Intermediate CA certificates that bridge the root and the leaf. Material for building the chain |
| Trusted Publishers | TrustedPublisher | Certificates trusted as the publisher of signed software (Section 8) |
2.3. Three Windows Onto the Same Data — certmgr.msc / certlm.msc / the Cert: Drive
There are three ways to look at the same stores.34
- certmgr.msc: a management console that opens the current user’s store.
- certlm.msc: a management console that opens the local computer’s store.
- PowerShell’s
Cert:drive: lets you treat theCert:\CurrentUser\...andCert:\LocalMachine\...hierarchies like a file system. Certificates are identified by thumbprint.
Note that when you add the certificates snap-in to mmc.exe manually, you choose the target from three kinds — “My user account”, “Computer account”, and “Service account”. A non-administrator user can only manage the store for their own user account.3
The first step in any troubleshooting is making sure “which store the app is looking at” and “which store you are looking at” line up. Staring at certmgr.msc while investigating a service failure never gets you an answer, because you are looking at the wrong place.
3. Which Store to Use — A Decision Table Based on How the Program Runs
There is a single criterion: which account does the program that uses the certificate run as?
| Execution form | Runs as | Store to use | Notes |
|---|---|---|---|
| A desktop app launched by an interactive user | The signed-in user themselves | User (Cert:\CurrentUser\My) | Must be installed separately for each user’s account. If several people share one PC, also consider the computer store |
| A Windows service | LocalSystem / NETWORK SERVICE / a dedicated service account | Computer (Cert:\LocalMachine\My) | Anything other than LocalSystem (NETWORK SERVICE, a dedicated account, etc.) must have private-key read permission granted explicitly (Section 4). LocalSystem can already read it under its default SYSTEM permissions |
| A web app running under IIS | The application pool identity | Computer | Same as above |
| Unattended execution via Task Scheduler (runs whether or not a user is logged on) | The account specified on the task | Computer, recommended | It can also be made to run from the execution account’s user store, but that only adds verification work around profiles and store visibility, with little benefit |
| Electronic filing / web authentication in a browser | The signed-in user themselves | User | Also the natural choice in the sense that only the person it was issued to should be able to use it |
If in doubt: unattended programs use the computer store, human-operated programs use the user store.
3.1. Anatomy of the Classic Failure — “It Worked While Developing, but Once It Became a Service It Couldn’t Find the Certificate”
This failure can be reproduced precisely by the following sequence of steps.
- A developer double-clicks a pfx on their own PC to import it. The wizard defaults to “Current User”, so the certificate goes into the developer account’s user store.
- During development the app runs from Visual Studio — that is, as the developer’s account — so opening
StoreLocation.CurrentUserfinds the certificate. It works. - It is registered as a Windows service on the production server. The service runs as NETWORK SERVICE or a dedicated account.
- The
CurrentUserthe service’s code opens is the user store of the service’s execution account, and that store is empty. “Certificate not found.”
flowchart TB
subgraph DEV["Development machine"]
D1["Double-click the pfx to import it<br/>The wizard defaults to 'Current User'"] --> D2["Goes into the developer's<br/>account user store"]
D2 --> D3["Run from Visual Studio<br/>= runs as the developer's account"]
D3 --> D4["Opening CurrentUser finds it<br/>-> it works"]
end
subgraph PROD["Production server"]
P1["Registered as a Windows service<br/>Runs as NETWORK SERVICE or similar"] --> P2["The CurrentUser the code opens is<br/>the service account's user store"]
P2 --> P3["It's empty<br/>-> 'Certificate not found'"]
end
D4 -.->|"deploy the same program"| P1
The key point is that the user store exists “once per account”. An administrator opening certmgr.msc and saying “it’s clearly right there, isn’t it?” is only looking at their own store, not the service account’s store. The fix is not an ad hoc copy — it is to re-import into the computer store and align the code with StoreLocation.LocalMachine. And that, together with the permission grant covered in the next section, is a single unit of work.
4. Private Keys and Access Rights — The Second Classic Failure
4.1. A Certificate and Its Private Key Are Different Things
What you see listed in the certificate store is the certificate (public information), not the private key itself. What client authentication actually needs is a signing operation that uses the private key, so “visible in the list” and “usable” are different problems. Confusing the two produces the kind of hard-to-diagnose failure where “the certificate is there, but the TLS handshake fails” or “you get some opaque Access Denied error”.
4.2. Importing a pfx in Practice — Exportability Is a Decision
A certificate and its private key are handed over as a pfx (PKCS #12) file and can be imported into the store with Import-PfxCertificate.6
$pwd = Get-Credential -UserName '(enter the password below)' -Message 'PFX password'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
-CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password
What matters here is the default behaviour: unless you specify -Exportable, the imported private key cannot be re-exported.6 Importing everything as exportable “just in case you need to migrate it later” adds one more route by which the private key could be exfiltrated. Keep the original pfx stored safely, and treat the private key in the store as non-exportable by default — that is what we recommend. Note that it is precisely the storage of the original pfx and its password that tends to get left lying around in plaintext. We cover the reasoning in “Storing Secrets in Windows Apps - Avoiding Plaintext Configuration with DPAPI” and “Handling Credentials Safely in PowerShell”.
4.3. Granting Private Key Permissions to a Service Account
The private key of a certificate placed in the computer store is normally readable, by default, by nobody but administrators and SYSTEM. Because of this, a service running as LocalSystem can read the private key without any extra work, but if it runs under any other account — NETWORK SERVICE, a dedicated service account, an IIS app pool identity, and so on — you must explicitly grant that execution account read permission. The steps are done through the certificates snap-in UI.5
- Open certlm.msc (or the certificates snap-in targeted at the computer account).
- Under “Personal” → “Certificates”, right-click the certificate in question, then from “All Tasks” open “Manage Private Keys”.
- On the “Security” tab, add the execution account (NETWORK SERVICE, a dedicated service account, an IIS app pool identity, and so on) and grant it “Read”.5
Full control is not required. Read is enough if the key is only being used for signing. Conversely, granting Everyone full control just because “it isn’t working” reduces the private key to the security level of a plaintext password, so avoid it absolutely. Placement in the computer store and granting private-key permissions are always a single unit of work — just writing that rule down in a runbook eliminates this whole class of incident.
5. Preventing Expiry Incidents — Inventory, Renewal, and a Ledger
5.1. Taking Inventory with PowerShell
A certificate’s expiry date is held in the NotAfter property. Get-ChildItem against the Cert: drive lets you take mechanical inventory.4
# List the "Personal" store of the computer store, sorted by expiry date
Get-ChildItem Cert:\LocalMachine\My |
Sort-Object NotAfter |
Format-Table Thumbprint, Subject, NotAfter
# Extract only certificates expiring within 60 days (0 returns already-expired certificates)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60
-ExpiringInDays is a parameter that returns “certificates that expire within the given number of days”; passing 0 returns certificates that have already expired.4 Turn this into a monthly scheduled task run against every server, and consolidate the results by email or into a ledger — do just that, and you can eliminate almost all incidents of the “eligibility verification can’t go through on Monday morning because a certificate expired” variety.
5.2. The Renewal Procedure — the Overlap Period and the Thumbprint Trap
Renewing a certificate is not “delete then add” — it is “add, then switch over, then verify, then delete”.
- Import the new certificate (pfx) into the same store. Because the thumbprint is different, old and new can coexist in the same store.
- Grant private-key permission on the new certificate (Section 4). This is the step people forget most easily at renewal time. Permission is per certificate private key, so when you swap the certificate, you also redo the permission grant.
- For any counterparty system that requires the certificate to be pre-registered, complete that registration first while continuing to operate on the old certificate, and secure an overlap period during which either certificate is accepted. Switching over first would let the other side reject the new certificate and halt production traffic.
- Switch the app’s configuration to the new certificate and verify it works.
- After a sufficient period, delete the old certificate.
flowchart LR
I["1. Import the new pfx into<br/>the same store - old and new coexist"] --> P["2. Grant private key<br/>permissions on the new certificate"]
P --> R["3. Pre-register with the counterparty<br/>- keep running on the old certificate"]
R --> SW["4. Rewrite the thumbprint in<br/>configuration, switch over, verify"]
SW --> DEL["5. After the overlap period,<br/>delete the old certificate"]
The biggest trap here is the thumbprint written into configuration files or code. A thumbprint is unique per certificate, so it necessarily changes on every renewal. If even a single place still references the old thumbprint, you get “the certificate was renewed, but it won’t connect”. The reliable approach is to keep a ledger of where the thumbprint is referenced — app configuration, IIS bindings, scripts, and registrations with counterparties.
5.3. Recommending a Certificate Ledger
A ledger does not have to be elaborate; a single spreadsheet is enough to start. At minimum, create columns for purpose / issuer / subject / thumbprint / location (server name plus store) / accounts with private-key permission / expiry date / link to the renewal procedure / owner, and cross-check it against the inventory results from 5.1. In practice, certificate incidents are not really a technical problem — they are a “nobody has a complete list” problem, which is exactly why a ledger is the most effective fix.
6. Verification and Reading Failures — Chains and Root Distribution
6.1. The Basics of Chain Verification, and certutil
Errors of the “this certificate is not trusted” variety mean the chain (the certification path) from the leaf certificate to the root CA is broken somewhere. certutil is a convenient tool for narrowing the problem down.7
flowchart TB
LEAF["Leaf certificate<br/>client certificate or server certificate"] --> INT["Intermediate CA certificate<br/>Location - Intermediate Certification Authorities CA store"]
INT --> ROOT["Root CA certificate<br/>Location - Trusted Root Certification Authorities Root store"]
INT -.->|"cannot be obtained<br/>not presented, not via AIA, not in the store"| E1["Chain cannot be built<br/>classic cause 1"]
ROOT -.->|"not distributed"| E2["'Not trusted' error<br/>classic cause 2"]
LEAF -.->|"expired"| E3["Validity period error<br/>classic cause 3"]
:: Build and verify the chain for a certificate file (fetching revocation-check URLs too)
certutil -urlfetch -verify client.cer
:: If the target app uses the user store, add -user to verify in the same context
certutil -user -urlfetch -verify client.cer
:: Dump the contents of a store (add -user for the user store)
certutil -store My
certutil -user -store My
certutil -verify validates a certificate, its CRL, and its chain, and builds and verifies a complete chain when no CA certificate file is specified.7 The output is long, but from it you can read at which level trust broke and whether revocation information was obtainable. There are three typical causes: (1) the intermediate CA certificate cannot be obtained — the TLS peer does not send it, it cannot be fetched from the certificate’s AIA information either, and it is not present in the “Intermediate Certification Authorities” store; (2) the internal CA’s root has not been distributed to “Trusted Root Certification Authorities”; and (3) the certificate itself has expired. Because an intermediate CA can also be resolved through presentation by the peer or automatic retrieval via AIA, treat placing it in the store as “one way to make it certain”, not the only way.
6.2. Distribute Internal CA and Self-Signed Roots via GPO / Intune
If you use an internal CA or a self-signed certificate for testing, you need to distribute its root certificate to every PC. Rather than installing it by hand on each machine, put it on a proper distribution mechanism.
- In an Active Directory environment (GPO): importing a certificate into “Trusted Root Certification Authorities” under Group Policy’s
Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policiesdistributes it to the target PCs.8 - In an Intune-managed environment: a “Trusted certificate” profile distributes the root or intermediate CA certificate. On Windows you can choose the destination store (computer root/intermediate, or user intermediate).9
As noted in 2.1, placing a certificate in the root of the computer store makes it trusted by every user.1 Which is exactly why you must look squarely at the reverse risk. Putting a self-signed certificate into “Trusted Root Certification Authorities” is the act of planting a new trust anchor on that PC. If that certificate’s private key leaks, it becomes a foothold for issuing certificates that impersonate any site or piece of software. If you want a permanent setup, either stand up an internal CA that properly protects its private key or lean toward a public CA certificate — a self-signed root should be limited to test environments, with an expiry date set on it, as a rule.
7. A Developer’s Perspective — Using the Store Correctly from .NET
7.1. Searching by Thumbprint with X509Store
From .NET, you open a store with X509Store and retrieve a certificate with Find.1011
using System.Security.Cryptography.X509Certificates;
static X509Certificate2 GetClientCertificate(string thumbprint)
{
using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var found = store.Certificates.Find(
X509FindType.FindByThumbprint, thumbprint, validOnly: true);
if (found.Count == 0)
throw new InvalidOperationException(
$"Certificate not found: thumbprint={thumbprint}, " +
$"location={store.Location}\\{store.Name}");
var cert = found[0];
if (!cert.HasPrivateKey)
throw new InvalidOperationException(
$"Certificate found but it has no associated private key " +
$"(e.g. imported from a .cer): thumbprint={thumbprint}, location={store.Location}\\{store.Name}");
return cert;
}
The decision from Section 3 maps directly onto this code. Code that runs in a service uses StoreLocation.LocalMachine; an interactive app uses StoreLocation.CurrentUser. There is one more thing to watch: the third argument to Find, validOnly. Passing true returns only certificates that pass validation.11 That is insurance against picking up an expired certificate, but it also means a test self-signed certificate whose chain is not trusted falls into the “not found” bucket, so if something “is there but can’t be found”, suspect this too. Also, as in the example above, whenever the error message reports “not found” it must always state which store it searched. That one detail changes the time spent investigating a Section 3 failure by an order of magnitude.
7.2. Attaching a Client Certificate to HttpClient
The certificate you retrieved is added to HttpClientHandler.ClientCertificates and presented to the server. That collection is the set of certificates presented to the server for certificate-based client authentication.12
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));
var client = new HttpClient(handler);
// From here on, use it as an ordinary HttpClient
On .NET Core, the documentation states explicitly that if a certificate carries a Key Usage attribute, it is not used to send the request unless that attribute includes “Digital Signature”.12 If you are ever in the position of requesting a client certificate be issued, make sure the intended use (client authentication) is communicated correctly. Also note that HttpClient, if constructed the wrong way, can cause socket exhaustion or fail to pick up DNS changes; the design of keeping the handler long-lived is covered in “Don’t Wrap HttpClient in a using Block”.
7.3. The Problem of a Hard-Coded Thumbprint Breaking on Renewal
Searching by thumbprint is reliable, but embedding a thumbprint in code means every certificate renewal forces a build and a release. There are three stages of design response.
- At minimum: externalise the thumbprint into a configuration file (appsettings and so on), so it can be swapped without a release. Record where it is configured in the ledger from 5.3.
- A step further: search by subject name or issuer, combined with
validOnly: true, to select “whichever currently-valid certificate under that name has the furthest-outNotAfter”. That lets the app automatically move onto the new certificate during the old-and-new overlap period. There is a risk of accidentally picking up an unrelated certificate with the same name, so pair this with checking the issuer and logging the choice. Also note this automatic switch-over only works when the counterparty does not require pre-registration of the certificate. For an API that requires pre-registration (Section 5.2), an automatic switch to a merely-imported, unregistered certificate can silently halt communication, so stick to the externalised-configuration approach and switch over only after confirming registration is complete. - Tighten it operationally: whichever method you use, log which certificate (thumbprint and expiry) was chosen at startup. That single line of logging pays off both in incident investigation and when cross-checking against the ledger.
8. Relationship to Code-Signing Certificates — the “Trusted Publisher” Store
Everything covered so far has been about certificates for communication (TLS), but the certificate store also hosts another world — code signing. The “Trusted Publishers” (TrustedPublisher) store that appeared in the table in 2.2 is where the two meet: it is where you register the publisher certificate of signed software as trusted. It exists in both the user and computer locations,10 and is used in setups such as distributing the publisher of an internally distributed app to each PC’s TrustedPublisher store via GPO.
If you are on the “distributing” side of an app and need to deal with code signing or the SmartScreen warning (“Windows protected your PC”), we have covered that in a separate article, “Why Windows Shows "Windows protected your PC"”. The knowledge in this article (the two store systems, root distribution) carries straight over as a prerequisite there.
9. Summary
- The certificate store comes in two systems: user (CurrentUser) and computer (LocalMachine). certmgr.msc, certlm.msc, and the
Cert:drive are three windows onto the same thing. The first step of any investigation is agreeing which store you are talking about. - Where you put a certificate is decided by “who the program runs as”. As a rule, unattended execution (services, IIS, tasks) uses the computer store, and interactive apps use the user store.
- “It worked while developing but can’t be found in production” happens because the developer’s user store and the service account’s user store are different things. Fix it by aligning on the computer store plus
StoreLocation.LocalMachine. - Placement in the computer store and granting read permission through “Manage Private Keys” are a single unit of work. Don’t forget to redo the grant on renewal.
- pfx import is non-exportable by default. Use
-Exportableonly when you genuinely need it. Include storage of the original pfx and its password in your design too. - Prevent expiry with periodic inventory via
Get-ChildItem Cert: ... -ExpiringInDaysand a certificate ledger. Renew in the order “add → switch over → verify → delete”, and watch for missed thumbprint updates in configuration. - Narrow down chain problems with
certutil -urlfetch -verify. Distribute an internal CA’s root via GPO or Intune, and limit putting a self-signed certificate in the root store to test environments, with an expiry date. - In code, externalise the thumbprint into configuration and log the certificate you chose. That alone makes a visible difference to how certificate-related incidents get handled.
Related Articles
- Why Windows Shows “Windows protected your PC”
- Storing Secrets in Windows Apps - Avoiding Plaintext Configuration with DPAPI
- Handling Credentials Safely in PowerShell — Banishing Plaintext Passwords from Your Scripts
- Don’t Wrap HttpClient in a using Block — Practical HTTP Communication in C# Business Apps (Creation Patterns, Timeouts, Retries)
- What Happens When You Tap a My Number Health Insurance Card — Reading Online Eligibility Verification and Its Integration with the Medical Billing System from ORCA’s Source Code
Related Consulting Areas
KomuraSoft LLC handles the development of business applications that incorporate Web API integrations using client certificates (banking APIs, online eligibility verification, and the like), investigating failures of the “certificate not found” or “can’t connect after renewal” kind, and putting a certificate-renewal procedure in place. It is fine to reach out to us even at the stage of not knowing which part of the store to look at.
- Windows App Development
- Bug Investigation & Root Cause Analysis
- Technical Consulting & Design Review
- Contact Us
References
-
Microsoft Learn, Local Machine and Current User Certificate Stores. On how the computer’s certificate store is local to the PC and shared by all users, sitting under HKEY_LOCAL_MACHINE; how the user’s certificate store is separate per user account, sitting under HKEY_CURRENT_USER; and how the user store inherits the contents of the computer store for every logical store except “Personal” (so a certificate added to the computer’s “Trusted Root Certification Authorities” also appears in each user’s copy of the same store). ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, System Store Locations. On the registry locations of CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE (Software\Microsoft\SystemCertificates under HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE respectively), the predefined logical stores MY, Root, Trust, and CA, service-specific stores living under a per-service-name registry key (Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates), and the separate existence of stores used for Group Policy distribution. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, How to: View certificates with the MMC snap-in. On certlm.msc being the tool that manages certificates for the local device (local computer) and certmgr.msc the tool that manages certificates for the current user; the three kinds of target for the certificates snap-in — “Computer account”, “My user account”, and “Service account”; and a non-administrator user only being able to manage certificates for their own user account. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_Certificate_Provider. On the PowerShell Cert: drive being a hierarchical namespace with two store locations, CurrentUser and LocalMachine; enumerating stores and certificates with Get-ChildItem; the -ExpiringInDays parameter returning certificates that expire within the given number of days (0 returns already-expired certificates); dynamic parameters such as -CodeSigningCert; the expiry date being held in the NotAfter property; and certificates being identified by thumbprint. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. On the procedure for opening “Manage Private Keys” from a certificates snap-in targeting the local computer’s certificate store, and adding “Read” access permission for the service’s execution account (for example, Network Service) on the “Security” tab. ↩ ↩2 ↩3
-
Microsoft Learn, Import-PfxCertificate. On Import-PfxCertificate importing a certificate and its private key from a PFX file into a specified store; the imported private key not being exportable unless the -Exportable switch is given; and the syntax and usage examples for the -CertStoreLocation, -Password, and -FilePath parameters. ↩ ↩2 ↩3
-
Microsoft Learn, certutil. On certutil -verify validating a certificate, its CRL, and its certificate chain, building and verifying a complete chain when no CA certificate file is specified; the availability of the -urlfetch option; and certutil -store dumping a certificate store, with the -user option accessing the user store instead of the computer store. ↩ ↩2
-
Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. On the procedure for importing a certificate into “Trusted Root Certification Authorities” under Group Policy’s Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies to distribute it to client computers in the domain, and the permissions required (equivalent to Domain Admins / Enterprise Admins). ↩
-
Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. On Intune’s “Trusted certificate” profile being the mechanism for distributing a root or intermediate CA certificate to managed devices, its use in establishing trust in a root CA as a prerequisite for SCEP/PKCS certificate profiles, and the fact that on Windows you can select the destination store from “Computer certificate store - Root”, “Computer certificate store - Intermediate”, and “User certificate store - Intermediate”. ↩
-
Microsoft Learn, X509Store Class. On X509Store being constructible with a StoreName and a StoreLocation (CurrentUser / LocalMachine), opening the store via the Open method and OpenFlags (ReadOnly, OpenExistingOnly, and so on), obtaining the certificate collection via the Certificates property, the standard store names including My, Root, CA, and TrustedPublisher, and the TrustedPublisher store existing in both CurrentUser and LocalMachine. ↩ ↩2
-
Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. On the Find method searching for certificates by an X509FindType (such as FindByThumbprint) and a search value, and on passing true for the third argument, validOnly, causing only certificates that passed validation to be returned. ↩ ↩2
-
Microsoft Learn, HttpClientHandler.ClientCertificates Property. On the ClientCertificates property being the X509CertificateCollection presented to the server for certificate-based client authentication, and on .NET Core requiring that, where a certificate has a Key Usage attribute, it include “Digital Signature”. ↩ ↩2
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
The Windows Firewall and Business Applications — Register Inbound Rules From the Installer
"It works on the dev machine but the client can't connect" almost always traces back to the Windows Firewall. This article covers the def...
Windows Security Audit Policy and Event Log Investigation in Practice — Becoming an IT Team That Can Read Event 4625
A practical guide for answering "please look into the failed sign-in logs." It covers the relationship between basic and advanced audit p...
A Practical Guide to Windows LAPS — Retiring the Shared Local Administrator Password Across All PCs
A shared local administrator password across every PC is fertile ground for Pass-the-Hash attacks, where the compromise of one machine sp...
SMB Signing and LDAP Channel Binding — Closing the "Other Half" of Your NTLM Defences in Practice
SMB signing and LDAP signing/channel binding are the defences that limit the damage from relay attacks while you work towards retiring NT...
Will NTLM Deprecation Stop Your Business Apps? — How to Collect Audit Logs, and the Order in Which to Kill Dependencies
A practical procedure for finding out where your Windows environment and business applications depend on NTLM ahead of its retirement: au...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Frequently Asked Questions
Common questions about the topic of this article.
- What is the difference between certmgr.msc and certlm.msc?
- They target different stores. certmgr.msc opens the certificate store of the currently signed-in user (the current user, CurrentUser); certlm.msc opens the certificate store of the computer (the local computer, LocalMachine). The computer store is shared by every user and service on the PC, and managing it requires administrator rights. A non-administrator user can only manage their own user store. Inside both, the contents are split into logical stores such as "Personal" and "Trusted Root Certification Authorities", and from PowerShell you see the same structure as Cert:\CurrentUser and Cert:\LocalMachine.
- Should a client certificate go in the user store or the computer store?
- It depends on who the program that uses the certificate runs as. For a desktop app launched by an interactive user, the user store of the person who uses it (Cert:\CurrentUser\My) is the default choice. For a program that runs unattended — a Windows service, an IIS application pool, or Task Scheduler — put it in the computer store (Cert:\LocalMachine\My) and grant the execution account permission to read the private key. Because the user store is separate for each account, a certificate a developer put in their own user store is invisible to a service running under a different account. That is the classic cause of "it worked while developing but can't be found in production".
- What should I check when a Windows service can't find or use a certificate?
- Check two things, in order. First, which store is it looking at. If the code opens StoreLocation.CurrentUser, that is the user store of the service's execution account, not the store an administrator sees when they open certmgr.msc for themselves. Move the certificate to the computer store and align the code with StoreLocation.LocalMachine. Second, can the private key actually be read. Being visible in the certificate list and being usable are two different things — by default, only administrators and SYSTEM can normally access the private key in the computer store. Open "Manage Private Keys" for the certificate in certlm.msc and grant "Read" to the service's execution account (NETWORK SERVICE or similar).
- How can I catch certificate expiry ahead of time with PowerShell?
- You can take inventory with Get-ChildItem against the Cert: drive. For example, Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter lists the personal store of the computer store in order of expiry date. The -ExpiringInDays parameter lets you extract only "certificates that expire within the given number of days"; passing 0 returns certificates that have already expired. Run this monthly against every server and cross-check the results against a certificate ledger, and you can eliminate almost all incidents of the "can't authenticate from Monday morning because a certificate expired" variety.