The "Same PC" Is Not the Same Execution Environment — The User Boundary That Separates AppData, HKCU, DPAPI, and Credentials
· Updated: · Go Komura · Windows, DPAPI, Registry, AppData, Credentials, Task Scheduler
Revision history (first version, published Aug 28, 2026)
- First published
Cite this article(DOI: 10.5281/zenodo.22640260)
This article is archived on Zenodo. Below are both the DOI that always resolves to the latest version and the DOI pinned to the version you are reading.
Go Komura (2026). The "Same PC" Is Not the Same Execution Environment — The User Boundary That Separates AppData, HKCU, DPAPI, and Credentials. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22640260 https://comcomponent.com/en/blog/windows-user-boundary-appdata-hkcu-dpapi/
- DOI (latest version)
- 10.5281/zenodo.22640260
- DOI (this version)
- 10.5281/zenodo.22640261
The app reads its configuration file when launched from File Explorer, but Task Scheduler reports it “not found.” Turn it into a service and it can no longer decrypt the saved password. The browser on your desk is signed in, but in CI it lands back on the login screen.
With this kind of problem, check who the program is running as, and how before you look at the code. Files and settings that exist on the same PC cannot necessarily be used in the same way from a different execution user.
The question this article answers is why an app breaks when nothing in the code changed and it was merely turned into a scheduled task, a service, or a CI job. If you want to start from the symptom, go to the section that matches in the following table.
| Symptom | What to compare first | Where to read |
|---|---|---|
| The configuration file or a command cannot be found | Execution user, the actual AppData path, user environment variables | AppData and environment variables |
| A registry value you are sure you wrote is missing | The user hive that HKCU points to | HKCU |
| The file can be read, but the secret cannot be decrypted | The DPAPI scope and the owner of the master key | DPAPI |
| The browser’s sign-in state does not carry over | Execution user, profile, the DPAPI-protected key | Browser profiles |
| Saved credentials or certificates cannot be used | The execution account’s vault and certificate store, the task’s logon type | Credentials and certificates |
| The Z: drive is gone when running as administrator | The token and logon session before and after elevation | UAC elevation |
| You want a full inspection before a migration | The dependencies and setup for each execution form | Checklist by execution form, Investigation procedure |
Assumptions of This Article
| Item | Content |
|---|---|
| Intended readers | Developers who turn business apps into services, scheduled tasks, or CI jobs, and operations staff who investigate “it works on my machine” problems |
| Prerequisite environment | Windows 10/11. The verification code runs on PowerShell 5.1 or later |
| Difficulty | Intermediate |
1. The Bottom Line First
The basic unit that partitions a Windows execution environment is not the PC but the access token and the SID, that is, “who the process is running as.” AppData, HKCU, DPAPI keys, browser profiles, and credentials belong to that user’s environment.
The settings and sign-in state you prepared under your own interactive logon are not carried over automatically to SYSTEM or to another service account. The areas for machine-wide data are ProgramData and HKLM, and sharing through them still requires you to design the access rights.
flowchart TB
accTitle: Two worlds inside the same PC
accDescr: The same PC shares only HKLM and ProgramData, while the world of your SID and the world of another SID each have their own AppData, registry hive, and DPAPI keys, invisible to each other across the user boundary
pc["Same PC"] --> shared["Shared: HKLM and ProgramData"]
pc --> wa["The world of your SID"]
pc --> wb["The world of another SID (SYSTEM etc.)"]
wa --> ra["AppData, HKCU, DPAPI keys"]
wb --> rb["Other AppData, other hive, other keys"]
ra -.-|"User boundary: invisible to each other"| rb
Figure 1: On the same PC, a different execution user means different AppData, a different registry, and different keys.
That said, the same SID does not guarantee the same environment either. Also check the task’s logon type, IIS profile loading, and the difference in logon session that UAC elevation creates. Elevating within the same account does not turn HKCU or the vault into another user’s; what matters is to think separately about which boundaries change.
The rest of the article proceeds in this order: the execution user as the premise (Chapter 2), the five boundaries (Chapters 3 to 7), the check per execution form (Chapter 8), and design and investigation (Chapter 9).
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (33 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
2. Premise: “Who It Runs As” Decides Everything
2.1 Check the SID and the Token, Not the User Name
The ID that Windows uses to identify a user is not the user name but the SID (security identifier). A process holds an access token, and the token contains the SID of the execution user. This execution principal is the starting point whenever you reason about file ACL checks, the physical registry behind an alias, or encryption keys.
Use whoami /user for the first check. Confirm the result in the execution environment where the problem occurs, not in your own terminal.
> whoami /user
USER INFORMATION
----------------
User Name SID
=============== =============================================
desktop\you S-1-5-21-3623811015-3361044348-30300820-1001
C:\Users\you is the on-disk form of the user profile tied to that SID. A profile consists of a set of folders such as AppData and the user registry hive NTUSER.DAT. Because it is copied from the default profile at first logon, another user’s profile starts from an initial state that is separate from the environment you configured.1
flowchart TB
accTitle: From launch path to profile
accDescr: Whether launched by double-click, Task Scheduler, or a service or IIS, the process holds the SID in its access token, and the set of user profile data tied to that SID becomes its execution environment
e1["Double-click"] --> tok["Process token (SID)"]
e2["Task Scheduler"] --> tok
e3["Service or IIS"] --> tok
tok --> prof["Profile set tied to the SID"]
prof -.-> note["A different SID means a different, initial-state profile"]
Figure 2: The path by which a process is launched decides which SID’s profile it carries while it runs.
2.2 Service Accounts Each Have an Environment of Their Own
Windows has built-in accounts that run without a human logging on. Each of them has an independent execution environment.2
| Account | SID | Where its profile and registry point |
|---|---|---|
| SYSTEM (LocalSystem) | S-1-5-18 |
Profile under C:\Windows\System32\config\systemprofile. HKCU is associated with the default user3 |
| LocalService | S-1-5-19 |
Under C:\Windows\ServiceProfiles\LocalService. Has its own subkey under HKEY_USERS4 |
| NetworkService | S-1-5-20 |
Under C:\Windows\ServiceProfiles\NetworkService. Like LocalService, has its own profile and hive4 |
IIS AppPool\<name> |
S-1-5-82-… |
A pool-specific identity. The profile is not loaded by default5 |
The difference between the launch paths of a double-click, Task Scheduler, a service, and IIS becomes a difference in whose environment is used. Do not assume that the settings, keys, and credentials you prepared under your interactive logon exist at that execution destination as well.
2.3 Three Conditions to Check After “the Same User”
| Condition to check | Example of where the difference shows |
|---|---|
| Logon type | With a task’s S4U logon, the password is not stored, and the network and EFS cannot be accessed6 |
| Profile loading | In IIS, loadUserProfile decides whether AppData and the user hive are available7 |
| Logon session and elevation | Even with the same SID, an elevated process may not see the mapped network drives89 |
Do not stop at checking the SID; use these three to sort out what differs even with the same account. Tasks are covered in detail in Chapter 8, IIS in Chapters 4 and 5, and elevation in Chapter 7.
3. Boundary 1: AppData — The Same Environment Variable Points to a Different Place
The typical symptom is that the configuration file stops being found the moment the app becomes a scheduled task. Path resolution has not failed; the path may have resolved correctly to another user’s location, where the file does not exist.
3.1 The Divisions of AppData and How the Execution User Changes Them
AppData is a folder under the user profile. Its purposes are divided as follows.10
| Area | Main purpose |
|---|---|
%APPDATA% (Roaming) |
User settings that should follow the profile when it roams |
%LOCALAPPDATA% (Local) |
Machine-local data and caches |
| AppData\LocalLow | Data for processes running at a low integrity level |
Even when the same code opens %APPDATA%, the location it refers to changes with the execution user.
| Execution user | Example of where the configuration file is looked for |
|---|---|
| User A | C:\Users\a\AppData\Roaming\MyApp |
| SYSTEM | AppData under systemprofile |
The file that user A saved does not exist on the SYSTEM side. An error that only says the configuration file is missing does not make this obvious, so during the investigation look at the actual path that was opened, not the name of the environment variable.
flowchart TB
accTitle: How %APPDATA% resolves depends on the user
accDescr: Even when the same code opens %APPDATA%, it resolves to a path under C:\Users if the execution user is you and under systemprofile if it is SYSTEM, and your configuration file does not exist in the latter
code["Same code: open %APPDATA%"] --> q{"Execution user?"}
q -->|"You"| a["C:\Users\you\AppData\Roaming"]
q -->|"SYSTEM"| b["AppData under systemprofile"]
b -.-> miss["The file you put there is missing"]
Figure 3: Environment variables do not lie, but where they resolve depends on the token.
3.2 PATH Also Differs per User
System environment variables are shared by the whole machine, but user environment variables are per user. When a command you added to your own PATH cannot be found from a service, check this difference too.
Decide the storage location by who reads the data. Settings for that user alone go under AppData; data shared by all users or by services goes under %ProgramData%, and for the latter you design the ACLs. For a detailed way to choose, see “How to Choose Where a Windows App Stores Local Data”.
flowchart TB
accTitle: Choose the storage location by its readers
accDescr: Data that only that user reads goes in AppData or HKCU, data shared with all users or services goes in ProgramData or HKLM, and the latter comes with ACL design
q{"Who reads this data?"} -->|"Only that user"| f1["AppData, HKCU"]
q -->|"All users, services"| f2["ProgramData, HKLM"]
f1 -.-> w1["Reconsider if it may become a service"]
f2 -.-> w2["Design write permissions and ACLs"]
Figure 4: “It cannot read it once it became a service” is the result of skipping this branch at design time.
4. Boundary 2: HKCU — “Current User” Changes with the Caller
The typical symptom is that a service cannot find the license information an installer wrote. Even when both the write and the read went to something named HKCU, they are not necessarily the same physical hive.
4.1 HKCU Is an Alias for the User’s Hive
HKEY_CURRENT_USER (HKCU) is not an independent hive; it is an alias that is redirected to a physical location according to the calling user. In an ordinary user process it points to that SID’s key under HKEY_USERS. Its contents are the NTUSER.DAT loaded at logon.1
The exception is HKCU\Software\Classes, whose physical location is a separate hive file, UsrClass.dat. That file lives under %LOCALAPPDATA%\Microsoft\Windows.11
The HKCU of LocalSystem is associated with the default user (HKEY_USERS\.DEFAULT). When an installer running under an administrator account writes to HKCU and a SYSTEM service reads from HKCU, the two refer to different places.3
flowchart TB
accTitle: What the HKCU alias really is
accDescr: When an app opens HKCU, it is redirected to your SID key under HKEY_USERS in your process and to the default user's key in a LocalSystem process, so the value the installer wrote is no longer visible
app["App code: open HKCU"] --> alias["HKCU is an alias for the real key"]
alias -->|"Your process"| ha["Your SID under HKEY_USERS"]
alias -->|"SYSTEM process"| hd["HKEY_USERS\.DEFAULT"]
hd -.-> gone["The value you wrote does not exist"]
Figure 5: Even under the same name HKCU, a different user means a different hive is read and written.
Put machine-wide settings in HKLM. Microsoft does not recommend accessing HKCU from a service. If you need to read a user’s settings, impersonate that user and then use RegOpenCurrentUser.12
4.2 Also Check Whether the Profile Is Loaded
Beyond the execution account, whether the profile is loaded can also be the problem.
IIS application pools run without loading a user profile by default. Enabling loadUserProfile makes AppData and the hive under the profile available.7 This setting also affects where the DPAPI and ASP.NET Core Data Protection keys of the next chapter are stored.
The task setting “Do not store password” is checked separately, as a logon-type constraint. Even with the same user specified, an S4U logon cannot use the network or EFS. The concrete differences between configurations are summarized in Chapter 8.6
5. Boundary 3: DPAPI — The Encryption Is Locked with “the User’s Key”
Whereas AppData and HKCU are problems of looking in a different place, DPAPI produces a problem where the file can be read but its contents cannot be decrypted. Turning an app that uses a saved password into a service and getting a CryptographicException is one example.
5.1 A Different Master Key Owner Means No Decryption
DPAPI (Data Protection API) is the encryption facility that Windows provides to applications. Calling CryptProtectData or .NET’s ProtectedData.Protect lets an app protect data without carrying an encryption key around in its own code.13
That does not make the key unnecessary, though. DPAPI uses a master key managed by the OS. In the CurrentUser scope, a randomly generated per-user master key is protected with a key derived from the logon credentials and stored under the profile.14
flowchart TB
accTitle: The DPAPI key chain
accDescr: The randomly generated user master key is protected by a key derived from the logon credentials, that master key encrypts the app's secrets, and another user's master key cannot decrypt the same ciphertext
pwd["Logon credentials"] -->|"Protects via derived key"| mk["Your master key"]
mk -->|"Encrypts"| sec["App secret (saved password etc.)"]
mk2["Another user's master key"] -.->|"Cannot decrypt"| sec
mk -.-> loc["Stored under the profile"]
Figure 6: Data is not encrypted directly from the credentials; a key derived from the credentials protects the master key.
Next is a minimal example in which user A encrypts data, places it in a shared location, and a different user tries to decrypt it. Sharing the storage location does not change who can decrypt under CurrentUser.
# In user A's session: encrypt in the CurrentUser scope and save to a shared location
Add-Type -AssemblyName System.Security
$bytes = [Text.Encoding]::UTF8.GetBytes("secret")
$enc = [Security.Cryptography.ProtectedData]::Protect($bytes, $null, "CurrentUser")
[Convert]::ToBase64String($enc) | Set-Content C:\ProgramData\demo.bin
# As a different user (for example, after becoming SYSTEM with PsExec), try to decrypt
$enc = [Convert]::FromBase64String((Get-Content C:\ProgramData\demo.bin))
[Security.Cryptography.ProtectedData]::Unprotect($enc, $null, "CurrentUser")
# → CryptographicException: Key not valid for use in specified state.
5.2 Choose the Scope from Who Should Be Able to Decrypt
| Scope | Unit of decryption | Design consideration |
|---|---|---|
CurrentUser |
The master key of the user who encrypted the data | Cannot be decrypted once moved to a different execution account |
LocalMachine |
A key shared by the same machine | Any process on the same machine can decrypt, so restrict who can read the ciphertext with a file ACL |
A secret that both a service and the interactive user read should be designed from the start as LocalMachine combined with a file ACL, or the process should run under the account of the person who encrypted it. Do not change the scope merely to make the decryption error go away; decide who is allowed to decrypt. On shared machines, also be aware of the risk that machine-level protection is too broad.15
flowchart TB
accTitle: How to choose the DPAPI scope
accDescr: Choose the CurrentUser scope if only that user should be able to decrypt and the LocalMachine scope if several principals on the same PC should, and restrict readers of the latter with a file ACL
q{"Who should be able to decrypt?"} -->|"Only that user"| cu["CurrentUser scope"]
q -->|"Several principals on the same PC"| lm["LocalMachine scope"]
cu -.-> r1["Decryption fails when run as another user"]
lm -.-> r2["Restrict readers with a file ACL"]
Figure 7: Choose the scope as a design decision about who decrypts, not as “whichever happened to work.”
5.3 A Password “Change” and a “Reset” Are Different
The key that guards the master key depends on the logon credentials. When users change their own password, the master key is re-protected with a key derived from the new password, and the ability to decrypt carries over.
By contrast, when an administrator resets the password of a local account, past ciphertext may no longer be decryptable. Even with the same account, you need to check how the credentials were changed.14
5.4 Check Where the Keys Are Stored in ASP.NET Core Too
Even code that never calls DPAPI directly can depend on this boundary. ASP.NET Core Data Protection stores the key ring used to protect cookie authentication and the like in a location that depends on the environment.16
| Environment | Where the keys go and the consequence |
|---|---|
| A user profile is available | %LOCALAPPDATA%\ASP.NET\DataProtection-Keys. On Windows the keys are encrypted with DPAPI |
| No profile is available, and the app is hosted in IIS | Falls back to the HKLM registry, ACLed to the worker process account |
| Neither applies | The keys become process-local, ephemeral keys. They are lost on restart, and protected data such as authentication cookies becomes invalid |
Check loadUserProfile, setProfileEnvironment, and the hosting model as a set, and understand which configuration decides where the keys are placed. What matters is not just that the app starts, but whether it can use the same keys after a restart.
Scope selection and when to use Credential Manager instead are covered in detail in “Storing Secrets in Windows Apps - Avoiding Plaintext Configuration with DPAPI”.
6. Boundary 4: Browser Profiles — “Signed In” Belongs to the User
Signed in on your desk, yet when CI launches the browser it is back at the login screen. This problem becomes tractable once you separate where the profile is stored from the encryption key.
6.1 There Are Two Boundaries: Storage Location and Key
The profile of a Chromium-based browser such as Chrome or Edge lives by default in the User Data folder under %LOCALAPPDATA%. History, cookies, extensions, saved passwords, and so on belong to that Windows user’s environment.17
Cookies and saved passwords are encrypted with an encryption key inside the profile, and that key itself is protected by DPAPI. Copying the folder to another user or another machine therefore fails to decrypt because the key does not match.
Recent Chrome layers App-Bound Encryption on top of this. Key decryption goes through a service running with SYSTEM privileges, which verifies not only the user but also the identity of the requesting app.18 This applies to Chromium-based browsers; the situation differs for browsers such as Firefox that have their own profile protection.
| Boundary | What happens at the automation target |
|---|---|
| The AppData boundary | The CI agent’s or service’s user does not have the profile you normally use |
| The DPAPI boundary | Even if the folder is copied, the protected key cannot be decrypted |
flowchart TB
accTitle: The two boundaries behind a browser's sign-in state
accDescr: The browser profile lives under LOCALAPPDATA and belongs to boundary 1, and the cookie encryption key is protected by DPAPI and belongs to boundary 3, so neither the profile nor the key carries over to another user
prof["Browser profile"] --> loc["Stored under LOCALAPPDATA"]
prof --> key["Cookie encryption key protected by DPAPI"]
loc -.-> ci["CI's execution user gets an empty, separate profile"]
key -.-> copy["Cannot be carried out by copying the folder"]
Figure 8: “Taking the signed-in state with you” is blocked by both boundary 1 and boundary 3.
6.2 In Automation, Make the Way Sign-In State Is Created Explicit
Selenium and Playwright launch with a throwaway temporary profile by default. So even under the same user, the sign-in state of your everyday browser is not used automatically.
Even if you specify a persistent profile directory, the storage-location and key problems of the previous section remain the moment you move to a CI job or a service under a different user. The remedy is not to copy a signed-in profile but one of the following.
- Code the sign-in steps for a test account.
- Use the automation tool’s storage-state mechanism to save and restore cookies and the like explicitly.
That another user cannot use the cookies with a mere copy is not an inconvenience; it is also a security boundary. Design the automation on the premise that this boundary exists.
7. Boundary 5: Credentials and Certificates — Each User Has a Separate Vault
Credentials saved with cmdkey are not used when the task runs, and authentication fails. Here too, check not “it was saved on the PC” but “which user it was saved as.”
7.1 Credential Manager Is a Vault per Execution User
Credential Manager, which you can inspect with cmdkey /list, is a per-user vault.19 Saved credentials are on disk, but they are protected by DPAPI and used by programs running as that user.20
The vault holds saved credentials for file servers and network drives, Git tokens saved by git-credential-manager, saved passwords for RDP connections, secrets of apps that use the Credential API, and so on.
Being in the vault of your interactive logon does not put them in the vault of the account that runs the service or task. Prepare a setup step that enters the required credentials in the context of the execution account itself. When only the git pull on your own desk succeeds, check the difference in vaults as well.
However, a task configured with S4U is not fixed by merely entering credentials. First check the logon type, and consider a configuration that stores the password or a switch to a service account. The order of steps is laid out in Chapter 8.
flowchart TB
accTitle: The credential vault is per user
accDescr: Your vault holds Git credentials, saved credentials for file servers, and RDP passwords, but the vault of the service execution user is empty unless credentials are entered, and that is what the authentication error really is
you["Your vault"] --> g["Git credentials"]
you --> n["Saved credentials for file servers"]
you --> r["Saved RDP passwords"]
svc["Service execution user's vault"] -.-> empty["Empty unless entered = the real authentication error"]
Figure 9: “Authentication works on my machine” is only shorthand for “my vault is available.”
7.2 For Certificates, Check the Store and the Private-Key Permissions Separately
| Store | Boundary and purpose |
|---|---|
Cert:\CurrentUser |
Per-user store. The private key of a client certificate placed here is protected per user |
Cert:\LocalMachine |
Machine-wide store. Place certificates for services here, and grant the service account read access through the private key’s ACL |
For a certificate used by a service, the basic design is the LocalMachine store together with the ACL on the private key.21 The user store physically lives under HKCU\Software\Microsoft\SystemCertificates, so it sits inside the HKCU boundary.22
For details, see “The Windows Certificate Store in Practice — User or Computer, Which Should You Use?”.
7.3 With UAC Elevation, Separate “the Same Account” from “a Different Account”
When an administrator user logs on with UAC enabled, two linked tokens are created: a standard token with restricted privileges and a full administrator token.8
Network drive mappings are per logon session. Z: may be visible in File Explorer yet invisible to a tool run as administrator.9
| How it runs | What changes and what does not |
|---|---|
| UAC elevation while staying on the same account | The SID is the same, and HKCU and the credential vault stay the same. Drive mappings, which are per logon session, may become invisible |
| Elevation or RunAs with the credentials of a different administrator account | The SID changes too. HKCU and the vault become that administrator’s. AppData, keys, and browser state are also subject to the other user’s boundary |
Do not assume that every “it stops working when elevated” is a change of user; first check whether it is the same account.
flowchart TB
accTitle: The split within one user created by UAC elevation
accDescr: A UAC-enabled administrator logon creates two tokens, a standard token and an elevated token, and a network drive mapped on the standard token side is not visible to a process running with the elevated token
logon["Administrator user logon"] --> t1["Standard token"]
logon --> t2["Elevated token"]
t1 --> d1["Z: drive mapped here"]
t2 -.->|"Separate logon session"| d2["Elevated tool cannot see Z:"]
Figure 10: Elevation creates “another world for the same user.” The boundary is not only about the SID.
8. Checklist by Execution Form
8.1 For Tasks, Look at the Logon Type After the Execution Account
In Task Scheduler, what is available changes with the logon type even when the same user is specified.6
| Logon type | What to check |
|---|---|
| Interactive token (InteractiveToken) | A configuration that runs in the session that is logged on |
| Stored password (Password) | A configuration that can use credentials even when non-interactive |
| S4U (password not stored) | The password is not stored, and network resources and encrypted files (EFS) cannot be accessed |
When a task cannot use saved credentials, first check the S4U constraint. Do not make adding credentials to the vault while staying on S4U your fix. Consider a configuration that stores the password or a switch to a service account, and only then, if still needed, enter credentials into the execution account’s vault.
The details of the settings are covered in “When Task Scheduler Tasks Don’t Run or Exit with 0x1”.
flowchart TB
accTitle: The task logon type as a second axis
accDescr: A Task Scheduler execution configuration has a logon type of interactive token, stored password, or S4U, and with S4U the password is not stored and the network and EFS cannot be accessed
task["Task execution configuration"] --> lt{"Logon type"}
lt -->|"Interactive token"| it["Runs in the logged-on session"]
lt -->|"Stored password"| pw["Credentials usable even non-interactively"]
lt -->|"S4U (password not stored)"| s4u["Cannot reach the network or EFS"]
Figure 11: Even with the same execution user, how it was logged on changes what is available.
8.2 The Inspection Table Before Changing the Execution Destination
| Execution form | Execution principal | Boundaries and symptoms to inspect in particular |
|---|---|---|
| Task Scheduler | The account specified at registration | Boundaries 1, 2, 3, and 5. Check where AppData and HKCU point, DPAPI decryption, and the vault. With S4U, the network and EFS cannot be used |
| Windows service | SYSTEM, LocalService, NetworkService, a service account | Boundaries 1 to 5. SYSTEM uses systemprofile and the default user’s HKCU; LocalService and NetworkService use their own environments under ServiceProfiles. The developer’s keys, vault, and browser state do not carry over |
| IIS application pool | A pool-specific identity such as IIS AppPool\<name> |
Boundaries 1, 2, 3, and 5. Check the profile not being loaded by default, where the Data Protection keys are placed, and access to the private keys of CurrentUser certificates |
| RunAs / UAC elevation | The specified user, or a different token of the same user | With the same account, the SID, HKCU, and vault are the same, and drive mappings are affected by the session difference. With a different account, inspect all of boundaries 1 to 5 |
| CI/CD agent | The agent’s service user. Often has never logged on interactively | Boundaries 1 to 5. Check for dependencies on the browser’s profile and sign-in state, Git credentials, the developer’s HKCU settings, and DPAPI-protected data |
| RDP / shared server | Multiple sessions of the same user, or multiple users | Multiple sessions of the same user share AppData and HKCU, so watch for write conflicts. Different users are separated by boundaries 1 to 5 |
The last row is a caution in the opposite direction. Multiple RDP sessions of the same user do not give each session its own independent AppData and HKCU. Here the problem is not that something is invisible, but that the same thing is shared and written to.
9. Guidelines for Design and Troubleshooting
9.1 Decide Storage Locations and Setup from the Principal That Uses Them
| Target | Design basics |
|---|---|
| User-specific settings | Put them in AppData or HKCU |
| Data and settings shared by all users or services | Put them in ProgramData or HKLM, and design write permissions and ACLs |
| Secrets | Choose the DPAPI scope from who should be able to decrypt. With LocalMachine, design the file ACL as well |
| Credentials and certificates for services | Include entering credentials into the execution account’s vault, placing the certificate in the LocalMachine certificate store, and setting the private key’s ACL in the setup procedure |
If you plan to turn the app into a service later, include that execution principal among the readers at the stage when you decide where to store things. The principle is not to carry a dependency on “whatever happened to exist in the developer’s environment” into operations.
9.2 Investigate from the Execution Principal to the Actual Referenced Location
flowchart TB
accTitle: Investigation procedure for user-boundary trouble
accDescr: Confirm the execution user with whoami, look at the token in Process Explorer, identify the paths and registry keys actually read with Process Monitor, and if needed reproduce from the other side's world with psexec
s1["Confirm the execution user with whoami /all"] --> s2["Check the token in Process Explorer"]
s2 --> s3["Identify the actual paths and keys with ProcMon"]
s3 --> s4["Reproduce from the other side's world with psexec"]
s3 -.-> hint["An unexpected profile path is the clue"]
Figure 12: Confirm the execution user, look at the actual paths and registry keys, then reproduce as the target execution principal.
| Step | How to check | What to look at |
|---|---|---|
| 1. Confirm the execution user | Write whoami /all to the log right after startup |
Whether the execution principal of the failing task or service is the same as on your desk |
| 2. Check the token | Process Explorer | The process’s user and session. Is it a different user, or a different execution context of the same user? |
| 3. Look at the actual referenced location | Process Monitor | The paths of the files opened and the registry keys. Does a profile other than the expected one show up in PATH NOT FOUND? |
| 4. Reproduce as the target execution principal | For SYSTEM, psexec -s -i cmd |
Try the same operation from a SYSTEM shell and confirm the differences from your own interactive environment |
When settings are missing, go back to AppData and HKCU; when the file can be read but not decrypted, to DPAPI; when only authentication fails, to the vault, certificates, and logon type. Do not judge from the error message alone; the shortcut is to line up “who used which location, with which key or credentials.”
10. Summary
“It works on my machine” means “it works as that user, with that profile, with those keys and that vault.” Even when the same .exe is launched on the same PC, turning it into a task, a service, or a CI job has to be treated as a migration of the execution environment.
AppData and user environment variables refer to the execution user’s profile, and HKCU likewise points to that user’s hive. The DPAPI CurrentUser scope depends on the user’s master key, and browser sign-in state and Credential Manager are also affected by that boundary.
Furthermore, even with the same SID, the differences in logon type, profile loading, and the session created by UAC elevation remain. Conversely, when multiple sessions of the same user share AppData and HKCU, think about write conflicts.
In design reviews, ask the following question.
Is this code correct no matter which user it runs as?
Provide the required storage locations, keys, and credentials explicitly for the actual execution principal. Confirm this principle before the migration, and you can reduce, at the design stage, the breakage where “the code did not change, yet it broke.”
Related Articles
- Storing Secrets in Windows Apps - Avoiding Plaintext Configuration with DPAPI
- How to Choose Where a Windows App Stores Local Data — A Decision Table for SQLite / JSON / Registry / Access
- When Task Scheduler Tasks Don’t Run or Exit with 0x1 — Isolating the Cause and Designing for Reliable Operation
- Choosing a Windows Service Account — LocalSystem, Virtual Accounts, and gMSA
- The Windows Certificate Store in Practice — User or Computer, Which Should You Use?
Related Consulting Areas
KomuraSoft LLC handles the design of execution environments when business apps are turned into services or scheduled tasks, the investigation of “it works on my machine” failures, and the design of secret management for Windows apps.
- Windows Application Development
- Bug Investigation & Root-Cause Analysis
- Legacy Asset Migration
- Contact Us
References
-
Microsoft Learn, About User Profiles. On the user profile being created at first logon, and on a profile consisting of the registry hive NTUSER.DAT (loaded at logon and mapped to HKEY_CURRENT_USER) and the set of profile folders on the file system. ↩ ↩2
-
Microsoft Learn, Local accounts. On SYSTEM (S-1-5-18), NETWORK SERVICE (S-1-5-20), and LOCAL SERVICE (S-1-5-19) being the default local system accounts used to run the OS and services. ↩
-
Microsoft Learn, LocalSystem Account. On the LocalSystem token including NT AUTHORITY\SYSTEM, on its not being associated with any logged-on user account, and consequently on HKEY_CURRENT_USER being associated with the default user and on the need to impersonate a user in order to access that user’s profile. ↩ ↩2
-
Microsoft Learn, LocalService Account. On the LocalService account having its own subkey under HKEY_USERS, and on HKEY_CURRENT_USER being associated with the LocalService account. The same applies to NetworkService (NetworkService Account). ↩ ↩2
-
Microsoft Learn, Application Pool Identities. On application pools running under a pool-specific identity, on IIS not loading the Windows user profile by default, and on setting the LoadUserProfile attribute to true to load the profile. ↩
-
Microsoft Learn, logonType Simple Type. On task logon types including S4U, Password, and InteractiveToken, and on an S4U logon not storing the password and having no access to the network or to encrypted files. ↩ ↩2 ↩3
-
Microsoft Learn, Process Model Settings for an Application Pool. On the loadUserProfile and setProfileEnvironment attributes of an application pool’s processModel, which control whether the worker process loads the user profile. ↩ ↩2
-
Microsoft Learn, How User Account Control works. On an administrator user’s logon creating two linked tokens, a standard user token and a full administrator access token, when UAC is enabled. ↩ ↩2
-
Microsoft Learn, Mapped drives are not available from an elevated prompt. On network drives mapped in a session logged on with the standard token being unavailable to elevated processes, and on the underlying reason that the two linked logon sessions hold their drive mappings separately. ↩ ↩2
-
Microsoft Learn, KNOWNFOLDERID. On FOLDERID_RoamingAppData (%APPDATA%), FOLDERID_LocalAppData (%LOCALAPPDATA%), and FOLDERID_LocalAppDataLow being defined as per-user known folders. ↩
-
Microsoft Learn, Error occurs during desktop setup and desktop location is unavailable. On a user profile having two hive files, NTUSER.DAT and UsrClass.dat, and on UsrClass.dat being placed under AppData\Local\Microsoft\Windows. ↩
-
Microsoft Learn, Services and the Registry. On services not accessing HKEY_CURRENT_USER or HKEY_CLASSES_ROOT, and on using the RegOpenCurrentUser function when impersonating a user. ↩
-
Microsoft Learn, CryptProtectData function. On CryptProtectData typically protecting data with a session key associated with the logged-on user and assuming decryption by the same user, and on the CRYPTPROTECT_LOCAL_MACHINE flag switching to machine-level protection. ↩
-
Microsoft Learn, Windows Data Protection. On DPAPI protecting a randomly generated master key by encrypting it with a key derived from the user’s password, on the master key being stored under the user profile, and on the master key being re-protected when the password changes. ↩ ↩2
-
Microsoft Learn, ProtectedData Class. On DataProtectionScope.CurrentUser allowing decryption only by the user who protected the data, and on LocalMachine allowing decryption by any process on the same machine. ↩
-
Microsoft Learn, Data Protection key management and lifetime in ASP.NET Core. On the keys being stored in %LOCALAPPDATA%\ASP.NET\DataProtection-Keys and encrypted with DPAPI on Windows when a user profile is available, on the fallback to the HKLM registry ACLed to the worker process account when hosted in IIS without a profile, on the keys being lost when the process exits and protected payloads becoming undecryptable when none of the conditions apply, and on the involvement of the setProfileEnvironment attribute. ↩
-
Chromium project, User Data Directory. On the default User Data directory of Chrome on Windows being %LOCALAPPDATA%\Google\Chrome\User Data, and on profiles (history, bookmarks, cookies, and so on) being placed under it. ↩
-
Google Security Blog, Improving the security of Chrome cookies on Windows. On Chrome having used DPAPI to encrypt cookies and the like on Windows, and on App-Bound Encryption protecting the key through a service running with SYSTEM privileges and verifying the identity of the app that requests decryption. ↩
-
Microsoft Learn, cmdkey. On the cmdkey command listing, creating, and deleting stored user names and passwords (credentials). ↩
-
Microsoft Learn, Cached and Stored Credentials Technical Overview. On credentials saved in Credential Manager being stored on disk and protected by DPAPI, and on programs running as that user being able to access the credentials in this store. ↩
-
Microsoft Learn, Local Machine and Current User Certificate Stores. On there being two kinds of certificate stores, the local machine store (machine-wide) and the current user store (per user). ↩
-
Microsoft Learn, System Store Locations. On the CERT_SYSTEM_STORE_CURRENT_USER system store being placed under HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates in the registry. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Handling Credentials Safely in PowerShell — Banishing Plaintext Passwords from Your Scripts
A practical walkthrough of moving plaintext passwords out of PowerShell scripts and into safe storage: what SecureString really is and wh...
Registry 32-bit/64-bit Redirection and Virtualization Pitfalls — Wow6432Node and the "The Value I Wrote Isn't There" Problem
How a 32-bit app's writes to HKLM\Software get redirected to Wow6432Node, the conditions under which UAC virtualization diverts them to t...
Choosing Between Power Automate and PowerShell + Task Scheduler — Putting Each Automation Tool Where It Fits Instead of Mixing Them
For IT staff at small and mid-sized companies where PowerShell + Task Scheduler nightly batches and Power Automate flows have started to ...
PowerShell Error Handling and Retry Design — From the try/catch Trap to Exit Codes and Retry Best Practices
A practical rundown of PowerShell error handling: the difference between terminating and non-terminating errors, the -ErrorAction Stop pa...
How to Choose Where a Windows App Stores Local Data — A Decision Table for SQLite / JSON / Registry / Access
Where — and in what format — should a Windows desktop app store its data? This article organizes the choice between AppData and ProgramDa...
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.
- An app that works when launched from File Explorer cannot find its configuration file when launched from Task Scheduler. Why?
- Because environment variables such as %APPDATA% resolve to the profile of the user who is running the program. When the task runs as SYSTEM or as another account, the environment variables point to a different profile (under systemprofile in the case of SYSTEM), and the configuration file you saved does not exist there. Check the account the task runs as, and put data that should be shared under ProgramData as the permanent fix.
- A password saved with ProtectedData.Protect can no longer be decrypted once the app became a service.
- DPAPI in the CurrentUser scope depends on the master key of the user who encrypted the data. If the service runs as a different account, the master key is a different one, so decryption fails with a CryptographicException. Redesign a secret that both the service and the interactive user read to use the LocalMachine scope plus a file ACL, or run the service under the account of the person who encrypted it.
- What happens when a process running as SYSTEM reads HKCU?
- In a LocalSystem process, HKEY_CURRENT_USER is associated with the default user (HKEY_USERS\.DEFAULT), so the values the interactive user wrote to HKCU are not visible. Put machine-wide settings in HKLM, and if you absolutely must read a user's settings, impersonate that user and then use RegOpenCurrentUser.
- Can I copy a signed-in Chrome/Edge profile to a CI machine and use it?
- Generally, no. The profile of a Chromium-based browser such as Chrome or Edge lives under the user's %LOCALAPPDATA%, and the encryption key for cookies and saved passwords is protected by that user's DPAPI. Copying the folder to another user or another machine fails to decrypt because the key does not match (browsers such as Firefox, which have their own profile protection, are a different story). For automation, code the sign-in steps for a test account, or use the storage-state mechanism of your automation tool.
- Credentials saved with cmdkey are not used when the task runs from Task Scheduler.
- Because the Credential Manager vault is separate for each user, and what you saved went into the vault of your own interactive logon. In addition, a task configured with "Do not store password" (S4U) runs without network credentials, so entering credentials into the vault does not help while it stays on S4U. First consider a configuration that stores the password or a switch to a service account, and only then, if still needed, enter the credentials into the vault of the execution account itself.