更新履歴(1件・最終更新 2026年09月05日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- ユーザー境界の技術的主張と条件を維持し、症状別の案内、境界ごとの説明、実行形態別の確認表と調査手順で記事構成を整理した。 更新前のバージョンを見る (DOI: 10.5281/zenodo.22170939)
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.22170938)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「「同じPC」は同じ実行環境ではない ── AppData・HKCU・DPAPI・資格情報を隔てるユーザー境界」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22170938 https://comcomponent.com/blog/windows-user-boundary-appdata-hkcu-dpapi/
- DOI(最新版)
- 10.5281/zenodo.22170938
- DOI(この版)
- 10.5281/zenodo.22345339
エクスプローラーから起動すると設定ファイルを読めるのに、タスクスケジューラでは「見つからない」。サービス化すると、保存したパスワードを復号できない。手元のブラウザではログイン済みなのに、CIではログイン画面に戻る。
この種の問題では、コードより先に「誰として、どのように実行しているか」を確認します。同じPCにあるファイルや設定でも、別の実行ユーザーから同じように使えるとは限らないためです。
本記事の問いは、コードを変えていないのに、タスク化・サービス化・CI化しただけでアプリが壊れるのはなぜかです。症状から調べたい場合は、次の表から該当箇所へ進んでください。
| 症状 | 最初に比べるもの | 読む箇所 |
|---|---|---|
| 設定ファイルやコマンドが見つからない | 実行ユーザー、AppDataの実際のパス、ユーザー環境変数 | AppDataと環境変数 |
| 書いたはずのレジストリ値が無い | HKCUが指すユーザーのハイブ | HKCU |
| ファイルは読めるが、秘密情報を復号できない | DPAPIのスコープとマスターキーの持ち主 | DPAPI |
| ブラウザのログイン状態を引き継げない | 実行ユーザー、プロファイル、DPAPIで保護された鍵 | ブラウザプロファイル |
| 保存済みの資格情報や証明書を使えない | 実行アカウントの金庫・証明書ストア、タスクのログオン種別 | 資格情報と証明書 |
| 管理者として実行するとZ:ドライブが無い | 昇格前後のトークンとログオンセッション | UAC昇格 |
| 移行前に一通り点検したい | 実行形態ごとの依存先とセットアップ | 実行形態別チェックリスト、調査手順 |
この記事の前提
| 項目 | 内容 |
|---|---|
| 対象読者 | 業務アプリをサービス化・タスク化・CI化する開発者と、「手元では動くのに」を調査する運用担当者 |
| 前提環境 | Windows 10/11。検証コードはPowerShell 5.1以降で実行する |
| 難易度 | 中級 |
1. まず結論
Windowsの実行環境を区切る基本単位は、PCではなくアクセストークンとSID、つまり「誰として動いているか」です。AppData・HKCU・DPAPIの鍵・ブラウザプロファイル・資格情報は、そのユーザーの環境に属します。
対話ログオンした自分が用意した設定やログイン状態は、SYSTEMや別のサービスアカウントへ自動では引き継がれません。マシン全体のデータを置く領域はProgramDataやHKLMで、共有する場合もアクセス権の設計が必要です。
flowchart TB
accTitle: 同じPCの中の2つの世界
accDescr: 同じPCはHKLMとProgramDataだけを共有し、あなたのSIDの世界と別SIDの世界がそれぞれ独自のAppData・レジストリハイブ・DPAPI鍵を持ち、ユーザー境界で互いに見えない
pc["同じPC"] --> shared["共有:HKLM・ProgramData"]
pc --> wa["あなたのSIDの世界"]
pc --> wb["別SIDの世界(SYSTEMなど)"]
wa --> ra["AppData・HKCU・DPAPI鍵"]
wb --> rb["別のAppData・別ハイブ・別の鍵"]
ra -.-|"ユーザー境界:互いに見えない"| rb
図1: 同じPCでも、実行ユーザーが違えばAppData・レジストリ・鍵は別のものになる。
ただし、SIDが同じなら必ず同じ環境になるわけでもありません。タスクのログオン種別、IISのプロファイル読み込み、UAC昇格によるログオンセッションの違いも確認します。同一アカウントの昇格でHKCUや金庫まで別ユーザーのものになるわけではなく、変わる境界を分けて考えることが大切です。
以下は、前提となる実行ユーザー(2章)、5つの境界(3〜7章)、実行形態別の点検(8章)、設計と調査(9章)の順です。
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全33件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. 前提: 「誰として動くか」がすべてを決める
2.1 ユーザー名ではなく、SIDとトークンを確認する
Windowsがユーザーを識別するIDは、ユーザー名ではなくSID(セキュリティ識別子)です。プロセスはアクセストークンを持ち、その中に実行ユーザーのSIDが含まれます。ファイルのACL判定、レジストリの実体、暗号鍵を考えるときも、この実行主体が出発点になります。
最初の確認にはwhoami /userを使います。自分のターミナルの結果ではなく、問題が起きる実行環境での結果を確かめます。
> whoami /user
ユーザー情報
----------------
ユーザー名 SID
=============== =============================================
desktop\you S-1-5-21-3623811015-3361044348-30300820-1001
C:\Users\youは、そのSIDに紐づくユーザープロファイルの実体です。プロファイルにはAppDataなどのフォルダー群と、ユーザーレジストリハイブNTUSER.DATがあります。初回ログオン時に既定プロファイルから複製されるため、別ユーザーのプロファイルは、自分が設定を整えた環境とは別の初期状態から始まります。1
flowchart TB
accTitle: 起動経路からプロファイルまでの流れ
accDescr: ダブルクリック・タスクスケジューラ・サービスやIISのどの経路で起動しても、プロセスはアクセストークンのSIDを持ち、そのSIDに紐づくユーザープロファイル一式が実行環境になる
e1["ダブルクリック"] --> tok["プロセスのトークン(SID)"]
e2["タスクスケジューラ"] --> tok
e3["サービス・IIS"] --> tok
tok --> prof["SIDに紐づくプロファイル一式"]
prof -.-> note["別SIDなら初期状態の別プロファイル"]
図2: どの経路で起動されるかは、どのSIDのプロファイルを背負って動くかを決める。
2.2 サービス用のアカウントにも、それぞれの環境がある
Windowsには、人間がログオンしなくても動く組み込みアカウントがあります。それぞれが独立した実行環境を持ちます。2
| アカウント | SID | プロファイル・レジストリの参照先 |
|---|---|---|
| SYSTEM(LocalSystem) | S-1-5-18 |
プロファイルはC:\Windows\System32\config\systemprofile配下。HKCUは既定ユーザーに関連付く3 |
| LocalService | S-1-5-19 |
C:\Windows\ServiceProfiles\LocalService配下。HKEY_USERSに自分のサブキーを持つ4 |
| NetworkService | S-1-5-20 |
C:\Windows\ServiceProfiles\NetworkService配下。LocalServiceと同様に、自分のプロファイルとハイブを持つ4 |
IIS AppPool\<名前> |
S-1-5-82-… |
プール専用のID。プロファイルは既定では読み込まれない5 |
ダブルクリック、タスクスケジューラ、サービス、IISという起動経路の違いは、どの実行主体の環境を使うかの違いにつながります。自分の対話ログオンで用意した設定・鍵・資格情報が、その実行先にもあるとは考えないでください。
2.3 「同じユーザー」の次に確認する三つの条件
| 確認する条件 | 違いが表れる例 |
|---|---|
| ログオン種別 | タスクのS4Uログオンでは、パスワードを保存せず、ネットワークやEFSにアクセスできない6 |
| プロファイルの読み込み | IISではloadUserProfileによりAppDataやユーザーハイブを使えるかが変わる7 |
| ログオンセッションと昇格 | 同じSIDでも、昇格したプロセスからネットワークドライブが見えない場合がある89 |
SIDの確認で終わらず、「同じアカウントでも何が違うのか」をこの三つで整理します。タスクは8章、IISは4〜5章、昇格は7章で詳しく見ます。
3. 境界1: AppData ── 同じ環境変数が別の場所を指す
典型的な症状は、タスク化した途端に設定ファイルが見つからなくなることです。パスの解決に失敗しているのではなく、別ユーザーの正しいパスへ解決され、そこにファイルが無い場合があります。
3.1 AppDataの区分と、実行ユーザーによる違い
AppDataはユーザープロファイル配下のフォルダーです。用途は次のように分かれます。10
| 領域 | 主な用途 |
|---|---|
%APPDATA%(Roaming) |
プロファイルの移動に追従させたいユーザー設定 |
%LOCALAPPDATA%(Local) |
マシンローカルなデータやキャッシュ |
| AppData\LocalLow | 低い完全性レベルのプロセス用のデータ |
同じコードで%APPDATA%を開いても、実行ユーザーによって参照先は変わります。
| 実行ユーザー | 設定ファイルを探す場所の例 |
|---|---|
| ユーザーA | C:\Users\a\AppData\Roaming\MyApp |
| SYSTEM | systemprofile配下のAppData |
ユーザーAが保存したファイルは、SYSTEM側には存在しません。「設定ファイルが無い」というエラーだけでは分かりにくいため、調査では環境変数名ではなく、実際に開いたパスを見ます。
flowchart TB
accTitle: %APPDATA%の解決はユーザーで変わる
accDescr: 同じコードが%APPDATA%を開いても、実行ユーザーがあなたならC:\Users配下、SYSTEMならsystemprofile配下に解決され、後者にはあなたの設定ファイルが存在しない
code["同じコード:%APPDATA%を開く"] --> q{"実行ユーザーは?"}
q -->|"あなた"| a["C:\Users\you\AppData\Roaming"]
q -->|"SYSTEM"| b["systemprofile配下のAppData"]
b -.-> miss["置いたはずのファイルが無い"]
図3: 環境変数は嘘をつかないが、解決先はトークンで変わる。
3.2 PATHにも、ユーザーごとの違いがある
システム環境変数はマシン共有ですが、ユーザー環境変数はユーザーごとです。自分のPATHへ追加したコマンドがサービスから見つからない場合も、この違いを確認します。
保存先は「誰が読むデータか」で決めます。そのユーザーだけの設定はAppDataへ、全ユーザーやサービスで共有するデータは%ProgramData%配下へ置き、後者はACLを設計します。詳しい選び方は「Windowsアプリのローカルデータはどこに置くべきか」を参照してください。
flowchart TB
accTitle: 保存先は読者で決める
accDescr: そのユーザーだけが読むデータはAppDataやHKCUに、全ユーザーやサービスと共有するデータはProgramDataやHKLMに置き、後者はACL設計を伴う
q{"そのデータを読むのは誰か"} -->|"そのユーザーだけ"| f1["AppData・HKCU"]
q -->|"全ユーザー・サービス"| f2["ProgramData・HKLM"]
f1 -.-> w1["将来サービス化するなら再考"]
f2 -.-> w2["書き込み権限とACLを設計する"]
図4: 「サービス化したら読めない」は、設計時にこの分岐を飛ばした結果である。
4. 境界2: HKCU ── 「現在のユーザー」は呼び出し元で変わる
典型的な症状は、インストーラーが書いたライセンス情報をサービスから見つけられないことです。書いた先と読んだ先が、どちらもHKCUという名前でも同じ実体とは限りません。
4.1 HKCUは、ユーザーのハイブへの別名
HKEY_CURRENT_USER(HKCU)は独立したハイブではなく、呼び出し元のユーザーに応じて実体へ振り替えられる別名です。通常のユーザープロセスでは、HKEY_USERS配下のそのSIDのキーを指します。その中身は、ログオン時にロードされたNTUSER.DATです。1
例外はHKCU\Software\Classesで、実体は別のハイブファイルUsrClass.datです。このファイルは%LOCALAPPDATA%\Microsoft\Windows配下に置かれます。11
LocalSystemのHKCUは、既定ユーザー(HKEY_USERS\.DEFAULT)に関連付けられます。管理者アカウントで実行したインストーラーがHKCUへ書き、SYSTEMのサービスがHKCUから読むと、参照先が食い違います。3
flowchart TB
accTitle: HKCUという別名の実体
accDescr: アプリがHKCUを開くと、あなたのプロセスではHKEY_USERS配下のあなたのSIDキーに、LocalSystemのプロセスでは既定ユーザーのキーに振り替えられ、インストーラーが書いた値が見えなくなる
app["アプリのコード:HKCUを開く"] --> alias["HKCUは実体への別名"]
alias -->|"あなたのプロセス"| ha["HKEY_USERS配下のあなたのSID"]
alias -->|"SYSTEMのプロセス"| hd["HKEY_USERS\.DEFAULT"]
hd -.-> gone["書いたはずの値が存在しない"]
図5: HKCUという同じ名前を使っても、ユーザーが変われば読み書きする実体が変わる。
マシン全体の設定はHKLMへ置きます。MicrosoftはサービスからHKCUへアクセスすることを推奨していません。ユーザーの設定を読む必要がある場合は、そのユーザーを偽装(impersonation)したうえでRegOpenCurrentUserを使います。12
4.2 プロファイルが読み込まれているかも確認する
実行アカウントに加えて、プロファイルがロードされているかが問題になる場合もあります。
IISのアプリケーションプールは、既定ではユーザープロファイルを読み込まずに動きます。loadUserProfileを有効にすることで、プロファイル配下のAppDataやハイブを使えるようになります。7 この設定は、次章のDPAPIやASP.NET Core Data Protectionの鍵の保存先にも関わります。
タスクの「パスワードを保存しない」設定は、これとは別にログオン種別の制約として確認します。同じユーザーを指定していても、S4UログオンではネットワークやEFSを使えません。具体的な構成の違いは8章にまとめます。6
5. 境界3: DPAPI ── 暗号は「ユーザーの鍵」で掛かっている
AppDataとHKCUが「探す場所が違う」問題なのに対し、DPAPIではファイルが読めても、中身を復号できないという問題が起きます。保存済みパスワードを使うアプリのサービス化で、CryptographicExceptionになる例がこれです。
5.1 マスターキーの持ち主が違えば復号できない
DPAPI(Data Protection API)は、Windowsがアプリへ提供する暗号化機能です。CryptProtectDataや.NETのProtectedData.Protectを呼べば、アプリ自身が暗号鍵をコードで持ち回らずにデータを保護できます。13
ただし、鍵が不要になるわけではありません。OSが管理するマスターキーを使います。CurrentUserスコープでは、ランダムに生成したユーザーごとのマスターキーを、ログオン資格情報から派生した鍵で保護し、プロファイル配下に保存します。14
flowchart TB
accTitle: DPAPIの鍵の連鎖
accDescr: ランダム生成されたユーザーのマスターキーはログオン資格情報から派生した鍵で保護され、そのマスターキーがアプリの秘密を暗号化しており、別ユーザーのマスターキーでは同じ暗号文を復号できない
pwd["ログオン資格情報"] -->|"派生鍵で保護"| mk["あなたのマスターキー"]
mk -->|"暗号化"| sec["アプリの秘密(保存パスワード等)"]
mk2["別ユーザーのマスターキー"] -.->|"復号できない"| sec
mk -.-> loc["保存先はプロファイル配下"]
図6: 資格情報から直接データを暗号化するのではなく、資格情報由来の鍵でマスターキーを保護する。
次は、ユーザーAが暗号化したデータを共有場所へ置き、別ユーザーで復号を試す最小例です。保存場所を共有しても、CurrentUserの復号者は変わりません。
# ユーザーAのセッションで: CurrentUserスコープで暗号化して共有場所に保存
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
# 別ユーザー(たとえばPsExecでSYSTEMになって)復号を試みる
$enc = [Convert]::FromBase64String((Get-Content C:\ProgramData\demo.bin))
[Security.Cryptography.ProtectedData]::Unprotect($enc, $null, "CurrentUser")
# → CryptographicException: 現在の状態では無効なデータです
5.2 スコープは、復号できるべき相手から選ぶ
| スコープ | 復号の単位 | 設計上の注意 |
|---|---|---|
CurrentUser |
暗号化したユーザーのマスターキー | 別の実行アカウントへ移すと復号できない |
LocalMachine |
同じマシンの共通の鍵 | 同じマシン上の任意のプロセスから復号できるため、暗号文を読める相手をファイルACLで絞る |
サービスと対話ユーザーの両方が読む秘密は、最初からLocalMachineとファイルACLを組み合わせて設計するか、暗号化した本人のアカウントで実行します。単に復号エラーを消すためにスコープを変えるのではなく、誰に復号を許すかを決めます。共用端末では、マシン単位の保護が広すぎるリスクにも注意してください。15
flowchart TB
accTitle: DPAPIスコープの選び方
accDescr: 復号できるべき主体がそのユーザーだけならCurrentUserスコープ、同じPCの複数の実行主体ならLocalMachineスコープを選び、後者はファイルACLで読者を絞る
q{"誰が復号できるべきか"} -->|"そのユーザーだけ"| cu["CurrentUserスコープ"]
q -->|"同じPCの複数の実行主体"| lm["LocalMachineスコープ"]
cu -.-> r1["別ユーザー実行で復号失敗"]
lm -.-> r2["読者はファイルACLで絞る"]
図7: スコープは「たまたま動いた方」ではなく、復号者の設計として選ぶ。
5.3 パスワードの「変更」と「リセット」は違う
マスターキーを守る鍵はログオン資格情報に依存します。ユーザー自身がパスワードを変更すると、マスターキーが新しいパスワード由来の鍵で保護し直され、復号能力を引き継ぎます。
一方、管理者がローカルアカウントのパスワードをリセットすると、過去の暗号文を復号できなくなる場合があります。アカウントが同じでも、資格情報の変更方法まで確認する必要があります。14
5.4 ASP.NET Coreでも、鍵の保存先を確認する
DPAPIを直接呼んでいなくても、この境界に依存する場合があります。ASP.NET Core Data Protectionは、Cookie認証などの保護に使う鍵リングを、環境に応じた場所へ保存します。16
| 環境 | 鍵の置き場所と影響 |
|---|---|
| ユーザープロファイルが使える | %LOCALAPPDATA%\ASP.NET\DataProtection-Keys。WindowsではDPAPIで暗号化する |
| プロファイルが使えず、IISでホストされている | ワーカープロセスアカウントにACLを設定したHKLMレジストリ配下へフォールバックする |
| どちらにも当てはまらない | プロセス内限りの一時キーになる。再起動で鍵を失い、認証Cookieなどの保護済みデータが無効になる |
loadUserProfile、setProfileEnvironment、ホスト形態をセットで確認し、鍵がどこに置かれる構成かを把握します。「起動できる」だけでなく、再起動後も同じ鍵を使えるかが重要です。
スコープ選択とCredential Managerとの使い分けは「Windowsアプリの機密情報保存 - DPAPIで平文設定を避ける」で詳しく扱っています。
6. 境界4: ブラウザプロファイル ── 「ログイン済み」はユーザーの持ち物
手元ではログイン済みなのに、CIでブラウザを起動するとログイン画面に戻る。この問題は、プロファイルの保存場所と暗号鍵を分けると整理できます。
6.1 保存場所と鍵の、二つの境界がある
ChromeやEdgeなどChromium系ブラウザのプロファイルは、既定で%LOCALAPPDATA%配下のUser Dataフォルダーにあります。履歴・Cookie・拡張機能・保存パスワードなどは、そのWindowsユーザーの環境に属します。17
Cookieや保存パスワードは、プロファイル内の暗号鍵で暗号化され、その鍵自体がDPAPIで保護されています。したがって別ユーザーや別マシンへフォルダーをコピーしても、鍵が合わずに復号できません。
近年のChromeはApp-Bound Encryption(アプリ束縛暗号化)も重ねています。鍵の復号をSYSTEM権限のサービス経由にし、ユーザーだけでなく、要求したアプリのIDも検証します。18 これはChromium系の話であり、独自のプロファイル保護を持つFirefoxなどでは事情が異なります。
| 境界 | 自動化先で起きること |
|---|---|
| AppDataの境界 | CIエージェントやサービスのユーザーには、普段使うプロファイルが無い |
| DPAPIの境界 | フォルダーをコピーしても、保護された鍵を復号できない |
flowchart TB
accTitle: ブラウザのログイン状態を支える2つの境界
accDescr: ブラウザプロファイルはLOCALAPPDATA配下にあり境界1に属し、Cookieの暗号鍵はDPAPIで保護され境界3に属するため、別ユーザーにはプロファイルも鍵も引き継がれない
prof["ブラウザプロファイル"] --> loc["置き場所はLOCALAPPDATA配下"]
prof --> key["Cookie暗号鍵はDPAPIで保護"]
loc -.-> ci["CIの実行ユーザーには空の別プロファイル"]
key -.-> copy["フォルダーコピーでは持ち出せない"]
図8: 「ログイン済みを持っていく」は境界1と境界3の両方に阻まれる。
6.2 自動化では、ログイン状態の作り方を明示する
SeleniumやPlaywrightは、既定で使い捨ての一時プロファイルを作って起動します。そのため、同じユーザーでも、普段のブラウザのログイン状態が自動で使われるわけではありません。
永続プロファイルのディレクトリを指定しても、別ユーザーのCIやサービスへ移す段階では、前節の保存場所と鍵の問題が残ります。対策は、ログイン済みプロファイルをコピーすることではなく、次のどちらかです。
- テスト用アカウントのログイン手順をコード化する。
- 自動化ツールのストレージステート機構で、Cookieなどの保存・復元を明示する。
別ユーザーがコピーだけでCookieを使えないことは、不便さではなくセキュリティ上の境界でもあります。自動化の設計は、その境界があることを前提にします。
7. 境界5: 資格情報と証明書 ── 金庫はユーザーごとに別
cmdkeyで保存した資格情報が、タスク実行時には使われず認証エラーになる。ここでも「PCに保存した」ではなく、「どのユーザーとして保存したか」を確認します。
7.1 資格情報マネージャーは、実行ユーザーごとの金庫
cmdkey /listで確認できる資格情報マネージャーは、ユーザーごとの金庫です。19 保存した資格情報はディスク上にありますが、DPAPIで保護され、そのユーザーとして動くプログラムが使います。20
金庫には、ファイルサーバーやネットワークドライブの保存資格情報、git-credential-managerが保存したGitのトークン、RDP接続の保存パスワード、Credential APIを使うアプリのシークレットなどが入ります。
対話ログオンした自分の金庫にあっても、サービスやタスクの実行アカウントの金庫にはありません。必要な資格情報は、実行アカウント自身の文脈で投入するセットアップを用意します。手元のgit pullだけが成功する場合も、使っている金庫の違いを確認します。
ただし、S4U構成のタスクは資格情報を投入するだけでは解決しません。まずログオン種別を確認し、パスワードを保存する構成やサービスアカウントへの切り替えを検討します。手順の順番は8章で整理します。
flowchart TB
accTitle: 資格情報の金庫はユーザーごと
accDescr: あなたの金庫にはgitの資格情報やファイルサーバーの保存資格情報やRDPのパスワードが入っているが、サービス実行ユーザーの金庫は資格情報を投入しない限り空であり、それが認証エラーの正体になる
you["あなたの金庫"] --> g["gitの資格情報"]
you --> n["ファイルサーバーの保存資格情報"]
you --> r["RDPの保存パスワード"]
svc["サービス実行ユーザーの金庫"] -.-> empty["未投入なら空=認証エラーの正体"]
図9: 「手元では認証が通る」は「あなたの金庫が使える」の略でしかない。
7.2 証明書は、ストアと秘密鍵の権限を分けて確認する
| ストア | 境界と用途 |
|---|---|
Cert:\CurrentUser |
ユーザーごとのストア。ここへ入れたクライアント証明書の秘密鍵はユーザー単位で保護される |
Cert:\LocalMachine |
マシン全体のストア。サービス用の証明書を入れ、秘密鍵のACLでサービスアカウントに読み取りを許可する |
サービスで使う証明書は、LocalMachineストアと秘密鍵のACLをセットで設計するのが基本です。21 ユーザーストアの実体はHKCU\Software\Microsoft\SystemCertificates配下なので、HKCUの境界の内側にあります。22
詳しくは「Windows証明書ストア実務ガイド ── ユーザーとコンピューター、どちらに入れるか」を参照してください。
7.3 UAC昇格では、「同じアカウント」と「別アカウント」を分ける
UACが有効な管理者ユーザーのログオンでは、権限を制限した標準トークンと、完全な管理者トークンという、リンクされた二つのトークンが作られます。8
ネットワークドライブの割り当てはログオンセッション単位です。エクスプローラーではZ:が見えても、管理者として実行したツールからは見えないことがあります。9
| 実行方法 | 変わるもの・変わらないもの |
|---|---|
| 同一アカウントのままUAC昇格する | SIDは同じで、HKCUや資格情報の金庫もそのまま。ログオンセッション単位のドライブ割り当てが見えなくなる場合がある |
| 別の管理者アカウントの資格情報で昇格する/RunAsする | SIDも変わる。HKCUや金庫は、その管理者のものになる。AppData・鍵・ブラウザ状態も別ユーザーの境界を受ける |
「昇格したら動かない」を、すべてユーザーの変更と決めつけず、まず同一アカウントかどうかを確認します。
flowchart TB
accTitle: UAC昇格が生む同一ユーザー内の分裂
accDescr: UAC有効な管理者のログオンは標準トークンと昇格トークンの2つを作り、標準トークン側で割り当てたネットワークドライブが昇格トークンのプロセスからは見えない
logon["管理者ユーザーのログオン"] --> t1["標準トークン"]
logon --> t2["昇格トークン"]
t1 --> d1["ここで割り当てたZ:ドライブ"]
t2 -.->|"別のログオンセッション"| d2["昇格したツールからZ:が見えない"]
図10: 昇格は「同じユーザーの別世界」を作る。境界はSIDだけの話ではない。
8. 実行形態別チェックリスト
8.1 タスクでは、実行アカウントの次にログオン種別を見る
タスクスケジューラは、同じユーザーを指定してもログオン種別で利用できるものが変わります。6
| ログオン種別 | 確認すること |
|---|---|
| 対話トークン(InteractiveToken) | ログオン中のセッションで実行する構成 |
| パスワード保存(Password) | 非対話でも資格情報を使える構成 |
| S4U(パスワード非保存) | パスワードを保存せず、ネットワークリソースと暗号化ファイル(EFS)にアクセスできない |
保存資格情報が使えないタスクは、まずS4Uの制約を確認します。S4Uのまま金庫へ資格情報を足すことを対策にしないでください。パスワードを保存する構成やサービスアカウントへの切り替えを検討し、そのうえで必要なら実行アカウントの金庫へ投入します。
設定の詳細は「タスクスケジューラで業務バッチを安定運用する」で扱っています。
flowchart TB
accTitle: タスクのログオン種別という第2の軸
accDescr: タスクスケジューラの実行構成は対話トークン・パスワード保存・S4Uのログオン種別を持ち、S4Uではパスワードが保存されずネットワークとEFSにアクセスできない
task["タスクの実行構成"] --> lt{"ログオン種別"}
lt -->|"対話トークン"| it["ログオン中のセッションで実行"]
lt -->|"パスワード保存"| pw["非対話でも資格情報を使える"]
lt -->|"S4U(パスワード非保存)"| s4u["ネットワークとEFSに届かない"]
図11: 同じ実行ユーザーでも、ログオンのされ方で使えるものが変わる。
8.2 実行先を変える前の点検表
| 実行形態 | 実行主体 | 特に点検する境界と症状 |
|---|---|---|
| タスクスケジューラ | 登録時に指定したアカウント | 境界1・2・3・5。AppDataやHKCUの参照先、DPAPIの復号、金庫を確認する。S4Uではネットワーク・EFSを使えない |
| Windowsサービス | SYSTEM、LocalService、NetworkService、サービスアカウント | 境界1〜5。SYSTEMはsystemprofileと既定ユーザーのHKCU、LocalService/NetworkServiceはServiceProfiles配下の各環境を使う。開発者の鍵・金庫・ブラウザ状態は引き継がれない |
| IISアプリプール | IIS AppPool\<名前>などのプール固有ID |
境界1・2・3・5。既定のプロファイル未ロード、Data Protectionの鍵置き場、CurrentUser証明書の秘密鍵へのアクセスを確認する |
| RunAs/UAC昇格 | 指定ユーザー、または同一ユーザーの別トークン | 同一アカウントならSID・HKCU・金庫は同じで、ドライブ割り当てはセッションの違いを受ける。別アカウントなら境界1〜5すべてを点検する |
| CI/CDエージェント | エージェントのサービスユーザー。対話ログオン歴が無い場合も多い | 境界1〜5。ブラウザのプロファイル・ログイン状態、Gitの資格情報、開発者のHKCU設定やDPAPI保護データに依存していないかを確認する |
| RDP/共用サーバー | 同じユーザーの多重セッション、または複数ユーザー | 同一ユーザーの多重セッションはAppData・HKCUを共有するため、書き込み競合に注意する。別ユーザーなら境界1〜5で分かれる |
最後の行は逆向きの注意です。同じユーザーのRDPセッションが複数あっても、AppDataやHKCUがセッションごとに独立するわけではありません。ここでは「見えない」ことではなく、「同じものを共有して書き込む」ことが問題になります。
9. 設計とトラブルシュートの指針
9.1 保存先とセットアップを、利用する主体から決める
| 対象 | 設計の基本 |
|---|---|
| ユーザー固有の設定 | AppData・HKCUへ置く |
| 全ユーザーやサービスで共有するデータ・設定 | ProgramData・HKLMへ置き、書き込み権限とACLを設計する |
| 秘密情報 | DPAPIのスコープを、復号できるべき相手から選ぶ。LocalMachineではファイルACLも設計する |
| サービス用の資格情報・証明書 | 実行アカウントの金庫への投入、LocalMachine証明書ストアへの配置と秘密鍵のACL設定を、セットアップ手順に含める |
将来サービス化する予定があるなら、保存先を決める段階で、その実行主体も読者に含めます。「たまたま開発者の環境にあったものを使う」という依存を、運用へ持ち込まないことが原則です。
9.2 調査は、実行主体から実際の参照先へ進む
flowchart TB
accTitle: ユーザー境界トラブルの調査手順
accDescr: whoamiで実行ユーザーを確認し、Process Explorerでトークンを見て、Process Monitorで実際に読んだパスとレジストリキーを特定し、必要ならpsexecで相手の世界から再現する
s1["whoami /allで実行ユーザーを確認"] --> s2["Process Explorerでトークンを確認"]
s2 --> s3["ProcMonで実際のパス・キーを特定"]
s3 --> s4["psexecで相手の世界から再現"]
s3 -.-> hint["期待と違うプロファイルパスが手がかり"]
図12: 実行ユーザーを確認し、実際のパスとレジストリキーを見てから、対象の実行主体で再現する。
| 手順 | 確認方法 | 見るポイント |
|---|---|---|
| 1. 実行ユーザーを確認する | 起動直後にwhoami /allをログへ出す |
問題が起きるタスクやサービスの実行主体が、手元と同じか |
| 2. トークンを確認する | Process Explorer | プロセスのユーザーとセッション。別ユーザーなのか、同一ユーザーの別の実行文脈なのか |
| 3. 実際の参照先を見る | Process Monitor | 開いたファイルのパスとレジストリキー。PATH NOT FOUNDに想定と違うプロファイルが現れていないか |
| 4. 対象の実行主体で再現する | SYSTEMならpsexec -s -i cmd |
SYSTEMのシェルから同じ操作を試し、自分の対話環境との差を確認する |
設定が無いときはAppDataとHKCU、ファイルが読めるのに復号できないときはDPAPI、認証だけ失敗するときは金庫・証明書・ログオン種別へ戻ります。エラーメッセージだけで判断せず、「誰が、どこを、どの鍵や資格情報で使ったか」を揃えるのが近道です。
10. まとめ
「手元で動く」は、「そのユーザー、そのプロファイル、その鍵と金庫で動く」という意味です。同じPCで同じ.exeを起動しても、タスク化・サービス化・CI化は実行環境の移行として扱う必要があります。
AppDataとユーザー環境変数は実行ユーザーのプロファイルを参照し、HKCUもそのユーザーのハイブへ向きます。DPAPIのCurrentUserスコープはユーザーのマスターキーに依存し、ブラウザのログイン状態と資格情報マネージャーも、その境界の影響を受けます。
さらに、同じSIDでもログオン種別、プロファイル読み込み、UAC昇格によるセッションの違いが残ります。逆に、同一ユーザーの複数セッションがAppDataやHKCUを共有する場合は、書き込み競合を考えます。
設計レビューでは、次の問いを確認してください。
これは、どのユーザーとして動いても正しいコードか?
必要な保存先・鍵・資格情報を、実際の実行主体へ明示的に用意する。この原則を移行前に確認すれば、「コードは変えていないのに壊れた」という事故を設計段階で減らせます。
関連記事
- Windowsアプリの機密情報保存 - DPAPIで平文設定を避ける
- Windowsアプリのデータ保存先の選び方 ── SQLite / JSON / レジストリ / Access 判断表
- タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計
- Windowsサービスのアカウント選定 ── LocalSystem・仮想アカウント・gMSAの使い分け
- Windows証明書ストア実務ガイド ── ユーザーとコンピューター、どちらに入れるか
関連する相談領域
合同会社小村ソフトでは、業務アプリのサービス化・タスク化に伴う実行環境の設計、「手元では動くのに」型の不具合調査、Windowsアプリの秘密情報管理の設計を扱っています。
参考リンク
-
Microsoft Learn, About User Profiles. ユーザープロファイルが初回ログオン時に作られること、プロファイルがレジストリハイブNTUSER.DAT(ログオン時にロードされHKEY_CURRENT_USERにマップされる)とファイルシステム上のプロファイルフォルダー群から成ることについて。 ↩ ↩2
-
Microsoft Learn, Local accounts. SYSTEM(S-1-5-18)・NETWORK SERVICE(S-1-5-20)・LOCAL SERVICE(S-1-5-19)がOSとサービスの実行に使われる既定のローカルシステムアカウントであることについて。 ↩
-
Microsoft Learn, LocalSystem Account. LocalSystemのトークンがNT AUTHORITY\SYSTEMを含むこと、どのログオンユーザーアカウントとも関連付かないこと、そのためHKEY_CURRENT_USERが既定ユーザーに関連付けられ、他ユーザーのプロファイルへアクセスするにはそのユーザーを偽装する必要があることについて。 ↩ ↩2
-
Microsoft Learn, LocalService Account. LocalServiceアカウントがHKEY_USERSの下に自分のサブキーを持ち、HKEY_CURRENT_USERがLocalServiceアカウントに関連付けられることについて。NetworkServiceも同様(NetworkService Account)。 ↩ ↩2
-
Microsoft Learn, Application Pool Identities. アプリケーションプールがプール固有のIDで動くこと、IISが既定ではWindowsユーザープロファイルを読み込まないこと、LoadUserProfile属性をtrueにするとプロファイルを読み込めることについて。 ↩
-
Microsoft Learn, logonType Simple Type. タスクのログオン種別にS4U・Password・InteractiveTokenがあること、S4Uログオンではパスワードが保存されず、ネットワークにも暗号化ファイルにもアクセスできないことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Process Model Settings for an Application Pool. アプリケーションプールのprocessModelにloadUserProfile属性とsetProfileEnvironment属性があり、ワーカープロセスがユーザープロファイルを読み込むかどうかを制御することについて。 ↩ ↩2
-
Microsoft Learn, How User Account Control works. UAC有効時、管理者ユーザーのログオンで標準ユーザートークンと完全な管理者アクセストークンという2つのリンクされたトークンが作られることについて。 ↩ ↩2
-
Microsoft Learn, Mapped drives are not available from an elevated prompt. 標準トークンでログオンしたセッションで割り当てたネットワークドライブが、昇格したプロセスから利用できないこと、およびその背景としてリンクされた2つのログオンセッションが別々にドライブ割り当てを持つことについて。 ↩ ↩2
-
Microsoft Learn, KNOWNFOLDERID. FOLDERID_RoamingAppData(%APPDATA%)・FOLDERID_LocalAppData(%LOCALAPPDATA%)・FOLDERID_LocalAppDataLowがユーザーごとの既知フォルダーとして定義されていることについて。 ↩
-
Microsoft Learn, Error occurs during desktop setup and desktop location is unavailable. ユーザープロファイルがNTUSER.DATとUsrClass.datという2つのハイブファイルを持ち、UsrClass.datがAppData\Local\Microsoft\Windows配下に置かれることについて。 ↩
-
Microsoft Learn, Services and the Registry. サービスがHKEY_CURRENT_USERやHKEY_CLASSES_ROOTへアクセスすべきでないこと、ユーザーを偽装する場合はRegOpenCurrentUser関数を使うべきことについて。 ↩
-
Microsoft Learn, CryptProtectData function. CryptProtectDataが通常はログオンしているユーザーに関連付けられたセッションキーでデータを保護し、同じユーザーでの復号を前提とすること、CRYPTPROTECT_LOCAL_MACHINEフラグでマシン単位の保護に切り替えられることについて。 ↩
-
Microsoft Learn, Windows Data Protection. DPAPIがランダムに生成したマスターキーを、ユーザーのパスワードから派生した鍵で暗号化して保護すること、マスターキーがユーザープロファイル配下に保存されること、パスワード変更時にマスターキーが保護し直されることについて。 ↩ ↩2
-
Microsoft Learn, ProtectedData Class. DataProtectionScope.CurrentUserが保護したユーザーのみに復号を許し、LocalMachineが同じマシン上の任意のプロセスからの復号を許すことについて。 ↩
-
Microsoft Learn, Data Protection key management and lifetime in ASP.NET Core. ユーザープロファイルが利用可能な場合、鍵が%LOCALAPPDATA%\ASP.NET\DataProtection-Keysに保存されWindowsではDPAPIで暗号化されること、IISホストでプロファイルが使えない場合はワーカープロセスアカウントにACLされたHKLMレジストリへフォールバックすること、どの条件にも当てはまらない場合は鍵がプロセス終了とともに失われ保護済みペイロードが復号できなくなること、setProfileEnvironment属性が関わることについて。 ↩
-
Chromium project, User Data Directory. WindowsにおけるChromeのUser Dataディレクトリの既定が%LOCALAPPDATA%\Google\Chrome\User Dataであり、プロファイル(履歴・ブックマーク・Cookie等)がその配下に置かれることについて。 ↩
-
Google Security Blog, Improving the security of Chrome cookies on Windows. ChromeがWindowsでCookie等の暗号化にDPAPIを使ってきたこと、App-Bound Encryptionにより鍵をSYSTEM権限のサービス経由で保護し、復号を要求したアプリのIDまで検証するようになったことについて。 ↩
-
Microsoft Learn, cmdkey. cmdkeyコマンドで保存済みのユーザー名とパスワード(資格情報)の一覧表示・作成・削除ができることについて。 ↩
-
Microsoft Learn, Cached and Stored Credentials Technical Overview. 資格情報マネージャーに保存された資格情報がディスク上に置かれDPAPIで保護されること、そのユーザーとして動くプログラムがこのストアの資格情報にアクセスできることについて。 ↩
-
Microsoft Learn, Local Machine and Current User Certificate Stores. 証明書ストアにローカルマシンストア(マシン全体)とカレントユーザーストア(ユーザーごと)の2種類があることについて。 ↩
-
Microsoft Learn, System Store Locations. CERT_SYSTEM_STORE_CURRENT_USERのシステムストアがレジストリのHKEY_CURRENT_USER\Software\Microsoft\SystemCertificates配下に置かれることについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
PowerShellでの資格情報の安全な扱い ── 平文パスワードをスクリプトから追放する
PowerShellスクリプトの平文パスワードを安全な保管へ移行する手順を整理します。SecureStringの実像と限界、Export-ClixmlによるDPAPI保存の仕組み、SecretManagement/SecretStoreの使いどころまで解説します。
レジストリの32bit/64bitリダイレクトと仮想化の落とし穴 ── Wow6432Nodeと「書いたはずの値がない」問題
32bitアプリのHKLM\Software書き込みがWow6432Nodeへリダイレクトされる仕組み、UAC仮想化でVirtualStoreに転送される条件、COM登録がbitnessで分かれる実害、RegistryViewやreg.exe /reg:64での正しい読み書...
Power AutomateとPowerShell+タスクスケジューラの使い分け ── 自動化の道具を混ぜずに適材適所でつなぐ
PowerShell+タスクスケジューラの夜間バッチとPower Automateフローが社内に混在し始めた中小企業の情シス向けに、両者の得意分野の違い、どちらで作るかの判断表、SharePoint経由で疎結合につなぐ連携パターン、ライセンスと保守の注意点まで整理します。
PowerShellのエラー処理と再実行設計 ── try/catchが効かない罠からexit code・リトライの定石まで
PowerShellの終了エラーと非終了エラーの違い、try/catchが効かない罠と-ErrorAction Stopの定石、$LASTEXITCODEによる成否判定、exit code設計、指数バックオフのリトライまでを実務目線で整理します。
Windowsアプリのデータ保存先の選び方 ── SQLite / JSON / レジストリ / Access 判断表
Windowsデスクトップアプリのデータをどこに・何で保存するか。AppData/ProgramDataの使い分け、SQLite・JSONファイル・レジストリ・Access(.accdb)それぞれの得意分野と落とし穴を判断表つきで整理し、破損対策やビット数問題まで実務目線で...
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- エクスプローラーから起動すると動くアプリが、タスクスケジューラからだと設定ファイルを見つけられません。なぜですか?
- %APPDATA%などの環境変数が「実行しているユーザー」のプロファイルに解決されるためです。タスクをSYSTEMや別アカウントで実行すると、環境変数は別のプロファイル(SYSTEMならsystemprofile配下)を指し、あなたが保存した設定ファイルはそこに存在しません。タスクの実行アカウントを確認し、共有すべきデータはProgramData配下に置くのが恒久対策です。
- ProtectedData.Protectで保存したパスワードが、サービス化したら復号できなくなりました。
- CurrentUserスコープのDPAPIは、暗号化したユーザーのマスターキーに依存します。サービスの実行アカウントが違えばマスターキーも別物なので、復号はCryptographicExceptionで失敗します。サービスと対話ユーザーの両方から読む秘密はLocalMachineスコープ+ファイルACLで設計し直すか、暗号化した本人のアカウントでサービスを実行してください。
- SYSTEMで動くプロセスからHKCUを読むとどうなりますか?
- LocalSystemのプロセスではHKEY_CURRENT_USERが既定ユーザー(HKEY_USERS\.DEFAULT)に関連付けられるため、対話ユーザーがHKCUに書いた値は見えません。マシン全体で共有する設定はHKLMに置き、どうしてもユーザーの設定を読む必要がある場合は、そのユーザーを偽装したうえでRegOpenCurrentUserを使います。
- ログイン済みのChrome/Edgeのプロファイルを、CIマシンにコピーして使えますか?
- 基本的に使えません。ChromeやEdgeなどChromium系ブラウザーのプロファイルはユーザーの%LOCALAPPDATA%配下にあり、Cookieや保存パスワードの暗号鍵はそのユーザーのDPAPIで保護されています。別ユーザー・別マシンにフォルダーをコピーしても鍵が合わず復号できません(Firefoxなど独自のプロファイル保護を持つブラウザーは事情が異なります)。自動化ではテスト用アカウントのログイン手順をコード化するか、自動化ツールのストレージステート機構を使ってください。
- cmdkeyで保存した資格情報が、タスクスケジューラ実行時に使われません。
- 資格情報マネージャーの金庫はユーザーごとに別で、保存したのは対話ログオンしたあなたの金庫だからです。加えて「パスワードを保存しない」(S4U)構成のタスクはネットワーク資格情報を持たずに動くため、S4Uのままでは金庫に資格情報を投入しても使えません。まず「パスワードを保存する」構成やサービスアカウントへの切り替えを検討し、そのうえで必要なら実行アカウント自身の金庫に資格情報を投入してください。