Skip to content

Installer: transparent migration from legacy system install (PR-C)#2024

Draft
tyrielv wants to merge 7 commits into
microsoft:masterfrom
tyrielv:tyrielv/migration-cleanup
Draft

Installer: transparent migration from legacy system install (PR-C)#2024
tyrielv wants to merge 7 commits into
microsoft:masterfrom
tyrielv:tyrielv/migration-cleanup

Conversation

@tyrielv

@tyrielv tyrielv commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

PR-C: Install-time migration + SYSTEM cleanup task

Stacked on PR #2022 (PR-B: user-mode install via /CURRENTUSER).

When the user-mode installer detects a legacy system install, migration is transparent -- no CLI verbs, no user prompts.

Install-time (elevated /ADMINSTAGE)

  • Stop + sc delete GVFS.Service
  • Copy legacy repo-registry to user LocalRepoRegistry location (then delete source to prevent cleanup-task rollback false positive)
  • Remove legacy dir from system PATH
  • Delete legacy AutoLogger registry key
  • Register MigrationCleanup scheduled task
  • Trigger immediate cleanup

Passes /USERLOCALAPPDATA to the elevated process so repo-registry lands in the correct user dir even under Over-the-Shoulder UAC.

Cleanup task (SYSTEM context, self-unregistering)

Fires at boot, logon, and every 30 minutes. Four guards:

  1. GVFS.Service in SCM = rollback detected, skip
  2. Legacy repo-registry exists = rollback detected, skip
  3. Legacy GVFS.Mount processes running from Program Files = wait
  4. Legacy dir gone = already done, unregister self

When all guards pass: deletes legacy files + dirs, unregisters self.

Build changes

GVFS.Installers.csproj: BuildCleanupTaskXml target (reuses build-task-xml.ps1 from A5). Cleanup task XML embedded via [Files] dontcopy.

Review fixes incorporated

  • Delete source repo-registry after FileCopy (prevents cleanup task permanent block)
  • Pass USERLOCALAPPDATA from non-elevated caller (fixes OTS UAC wrong-user)

tyrielv added 5 commits June 15, 2026 11:45
Adds LocalRepoRegistration (POCO + source-gen JSON context) and
LocalRepoRegistry (instance class) to GVFS.Common. Wire-compatible
with the service's on-disk repo-registry format.

18 new unit tests. 836/836 pass (818 prior + 18 new).

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
…navailable

MountVerb.RegisterMount, UnmountVerb.UnregisterRepo, and
ServiceVerb.TryGetRepoList fall back to LocalRepoRegistry when the
service pipe fails to open. Behavior unchanged when service is running.

UnmountVerb distinguishes not-found (benign no-op) from I/O errors
(propagated to caller) in the fallback path.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
…navailable

Returns true when the service pipe fails to open. In user-level
install model the boot-time EnableProjFSOnAllDrives task handles
PrjFlt. Removes now-orphaned StartServiceInstructions constant.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Adds IScheduledTaskInvoker, SchTasksScheduledTaskInvoker, and
LogonTaskRegistration. Manages a per-user logon task that runs
gvfs.exe service --mount-all via conhost.exe --headless to prevent
console window flash. Drift detection via full SHA-256 hash marker.

21 new unit tests. 857/857 pass.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
… task

Three files under scripts/projfs-attach/: the PS1 script body,
the task XML template with placeholders, and build-task-xml.ps1
that base64-encodes the script into the template. None deployed
to disk; the installer embeds via -EncodedCommand.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/migration-cleanup branch from 926c95c to c49e541 Compare June 15, 2026 18:47
tyrielv added 2 commits June 15, 2026 11:54
Extends the existing Inno Setup installer with a /CURRENTUSER flag
that routes to a complete user-mode install path. Default behavior
(admin, system-mode) is unchanged.

User-mode (/CURRENTUSER) flow:
  1. Drift-detect: checks ProjFS enabled + EnableProjFSOnAllDrives
     task registered with current hash marker
  2. If drift detected: self-elevates via /ADMINSTAGE=true to enable
     ProjFS and register the task from pre-built embedded XML
  3. Deploys payload to %LocalAppData%\GVFS\Versions\<version>\
  4. Creates/swaps Current junction with verification + rollback
  5. Updates user PATH (HKCU) and GVFS env vars
  6. Registers per-user \GVFS\AutoMount logon task (conhost --headless)
  7. GCs old versions (keeps most recent 2)

Build changes:
  - GVFS.Installers.csproj: BuildProjFSTaskXml target runs
    build-task-xml.ps1 and passes output to ISCC
  - Setup.iss: PrivilegesRequiredOverridesAllowed=commandline

Review fixes incorporated:
  - /ADMINSTAGE=true (not bare /ADMINSTAGE) for Inno Setup param parsing
  - Junction rollback reads old target via fsutil reparsepoint query
    and actually restores it via mklink /J
  - Logon task XML declares UTF-8 encoding (matches SaveStringToFile)

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Transparent migration from legacy system install to user-mode:
- Detect legacy install via SCM query + directory probe in /ADMINSTAGE
- Force-unmount all repos via legacy gvfs.exe, wait for processes
- Stop and delete GVFS.Service
- Copy repo-registry to user LocalAppData (preserve source for rollback)
- Remove legacy PATH entry and AutoLogger registry key
- Synchronous DelTree of legacy install dir (no deferred cleanup task)
- Structured [GVFS-INSTALL] log entries at key decision points

Functional test --no-service mode for user-mode installs:
- --no-service flag skips service install/uninstall in test harness
- Categories.RequiresService auto-excluded when --no-service
- Settings.cs auto-detects user-mode gvfs at %LocalAppData%\GVFS\Current
- ServiceVerbTests, ServiceTests, UpgradeReminderTests tagged RequiresService

CI test matrix changes:
- functional-tests.yaml: install_mode input (system/user), conditional
  install steps, GITHUB_PATH for user-mode, --no-service in test runner
- build.yaml: functional_tests_usermode job for full user-mode coverage
- upgrade-tests.yaml: user-mode-cold-install scenario

README: document /CURRENTUSER opt-in and migration behavior

Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
@tyrielv tyrielv force-pushed the tyrielv/migration-cleanup branch from c49e541 to c85c34c Compare June 15, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant