Repository navigation
Conversation
…s look much more bloated
Adds DotnetAccessMode.Admin, the DotnetupPolicy registry store for the AdminMode and BlockUnsignedDownloads policy values, the access mode resolver, the install mechanism request option, admin mode error codes, and the AdminModeSupport command contract. No behavior is wired yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds dotnetup.access_mode and dotnetup.access_mode_source to the common telemetry attributes and excludes admin mode from the ADX dashboard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds AdminModeGate, which rejects commands and explicitly supplied options or arguments that are not allowed in admin mode. Commands are blocked by default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds init --mode and admin mode switching through a single elevated operation that sets or clears the AdminMode policy value. Enabling admin mode also sets BlockUnsignedDownloads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In admin mode, sdk and runtime installs download the official .exe bundle, verify its hash and Authenticode signature, and run it into Program Files. Admin installs require --untracked and never touch the dotnetup manifest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The admin install check loaded the system hostfxr into dotnetup, locking a file the Windows installer may need to replace. Query the install root's dotnet executable in a child process instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verify the locked installer against the downloader's expected hash, decide the unsigned allowance from the actual download source, and stop launching further installers after Ctrl+C. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed dotnetup installs verify the replacement's Authenticode signature, so BlockUnsignedDownloads no longer blocks their self update. init and env set now leave admin mode only right before applying the new mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Corrects the admin mode design to the implemented policy layout (AdminMode and BlockUnsignedDownloads 0/1 values under the Policies key), init --mode semantics, unsigned daily installer handling, installer verification and exit codes, and documents init --mode and env set admin. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 3 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
dotnetup <> install under admin mode MVP
There was a problem hiding this comment.
🟡 Changes recommended
Organizational policy handling conflicts with the specification, and long-running installers can cause batch preparation to time out.
6 open findings
Separate machine preference and organizational policy registry values · New Hide migration options in Admin mode · New Require explicit mode when interactive mode is disabled · New Ignore download-cache overrides for admin installer caching · New Prevent preparation timeouts while commits hold the install mutex · New Ignore redirected temp directories for admin installer staging · New
What changed in this PR
Adds Windows-only dotnetup admin-mode installation through official installers, alongside the existing archive-based installation workflow.
Changes:
- Adds machine-wide mode switching and command restrictions.
- Adds installer selection, verification, execution, and cancellation handling.
- Extends tests, telemetry, and user documentation.
| File | Description |
|---|---|
| test/dotnetup.Tests/WindowsBundleArtifactTests.cs | Tests bundle verification and execution. |
| test/dotnetup.Tests/TelemetryTests.cs | Tests access-mode telemetry. |
| test/dotnetup.Tests/TelemetryDrainE2ETests.cs | Checks persisted mode tags. |
| test/dotnetup.Tests/SelfUpdateSignatureTests.cs | Tests signed-update policy exemptions. |
| test/dotnetup.Tests/ReleaseManifestFilterTests.cs | Tests installer selection. |
| test/dotnetup.Tests/Mocks/MockArchiveDownloader.cs | Supplies verification metadata. |
| test/dotnetup.Tests/InstallWorkflowTests.cs | Tests admin install routing. |
| test/dotnetup.Tests/InstallerOrchestratorTests.cs | Tests mechanisms and cancellation. |
| test/dotnetup.Tests/InitFormRendererTests.cs | Adjusts form-height expectations. |
| test/dotnetup.Tests/InitFormModelTests.cs | Tests Admin selection. |
| test/dotnetup.Tests/EnvCommandTests.cs | Isolates machine policy. |
| test/dotnetup.Tests/DotnetupPolicyTests.cs | Tests policy storage. |
| test/dotnetup.Tests/DotnetupConfigTests.cs | Rejects per-user Admin configuration. |
| test/dotnetup.Tests/DotnetDownloaderTests.cs | Tests accepted hashes. |
| test/dotnetup.Tests/DotnetDownloaderBlobFeedTests.cs | Tests bundle downloads and policy. |
| test/dotnetup.Tests/AdminModeSwitcherTests.cs | Tests elevated mode switching. |
| test/dotnetup.Tests/AdminModeSupportTests.cs | Tests command allowlists. |
| test/dotnetup.Tests/AdminModeGateTests.cs | Tests argument restrictions. |
| test/dotnetup.Tests/AdminModeGateExecutionTests.cs | Tests execution gating. |
| test/dotnetup.Tests/AdminModeCommandTests.cs | Tests mode-switch command flows. |
| test/dotnetup.Tests/AdminInstallTests.cs | Tests roots and installation discovery. |
| test/dotnetup.Tests/AdminAccessModeTests.cs | Tests mode constraints and errors. |
| test/dotnetup.Tests/AccessModeResolverTests.cs | Tests effective-mode resolution. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/UnsignedSourcePolicy.cs | Delegates registry policy reads. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/ReleaseManifest.cs | Selects Windows bundles. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/InstallBatchContext.cs | Tracks batch cancellation. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/IInstallArtifact.cs | Abstracts installation artifacts. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/IArchiveDownloader.cs | Returns verification metadata. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetupPolicy.cs | Implements machine policy storage. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetInstall.cs | Adds installation mechanism selection. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetDownloader.cs | Supports verified bundle downloads. |
| src/Installer/Microsoft.Dotnet.Installation/Internal/DotnetArchiveExtractor.cs | Implements the artifact interface. |
| src/Installer/Microsoft.Dotnet.Installation/DotnetInstallException.cs | Adds admin installation errors. |
| src/Installer/dotnetup.Library/WindowsPathHelper.cs | Supports directory-free elevated operations. |
| src/Installer/dotnetup.Library/WindowsInstaller/WindowsBundleArtifact.cs | Verifies and installs bundles. |
| src/Installer/dotnetup.Library/WindowsInstaller/MuxerInstallQuery.cs | Queries installations through child processes. |
| src/Installer/dotnetup.Library/WindowsInstaller/InstallerSignatureVerifier.cs | Checks installer signatures. |
| src/Installer/dotnetup.Library/WindowsInstaller/BundleProcessRunner.cs | Runs bundles and handles cancellation. |
| src/Installer/dotnetup.Library/WindowsInstaller/BundleExitCodes.cs | Classifies installer results. |
| src/Installer/dotnetup.Library/Telemetry/TelemetryTagNames.cs | Defines mode and mechanism tags. |
| src/Installer/dotnetup.Library/Telemetry/TelemetryCommonProperties.cs | Emits access-mode attributes. |
| src/Installer/dotnetup.Library/Telemetry/ErrorCategoryClassifier.cs | Categorizes new errors. |
| src/Installer/dotnetup.Library/Telemetry/dotnetup-adx-dashboard.json | Excludes admin-mode events. |
| src/Installer/dotnetup.Library/SelfUpdate/SelfUpdateSignature.cs | Exposes signed-replacement requirements. |
| src/Installer/dotnetup.Library/SelfUpdate/SelfUpdateNotifier.cs | Applies signed-update policy exemptions. |
| src/Installer/dotnetup.Library/InstallerOrchestratorSingleton.cs | Coordinates bundle installation and validation. |
| src/Installer/dotnetup.Library/IInstallationValidator.cs | Adds validation failure details. |
| src/Installer/dotnetup.Library/HostFxrInstallationValidator.cs | Validates installer-managed installations. |
| src/Installer/dotnetup.Library/EnvSettingsApplier.cs | Rejects direct Admin application. |
| src/Installer/dotnetup.Library/DotnetupConfig.cs | Keeps Admin outside user configuration. |
| src/Installer/dotnetup.Library/DotnetAccessModePolicy.cs | Restricts Admin to Windows. |
| src/Installer/dotnetup.Library/docs/dotnetup-telemetry.md | Documents access-mode telemetry. |
| src/Installer/dotnetup.Library/Commands/Shared/InstallWorkflow.cs | Routes admin requests to system roots. |
| src/Installer/dotnetup.Library/Commands/Shared/InstallCommand.cs | Declares supported install arguments. |
| src/Installer/dotnetup.Library/Commands/Self/SelfUpdateCommand.cs | Enables policy-aware admin self-update. |
| src/Installer/dotnetup.Library/Commands/Init/InitWorkflows.cs | Coordinates initialization and mode switching. |
| src/Installer/dotnetup.Library/Commands/Init/InitDefaultsResolver.cs | Prevents default Admin selection. |
| src/Installer/dotnetup.Library/Commands/Init/InitCommandParser.cs | Adds --mode. |
| src/Installer/dotnetup.Library/Commands/Init/InitCommand.cs | Routes explicit mode requests. |
| src/Installer/dotnetup.Library/Commands/Init/Form/InitFormModel.cs | Adds Admin choice and explanations. |
| src/Installer/dotnetup.Library/Commands/Env/EnvSetCommandParser.cs | Reuses shared mode parsing. |
| src/Installer/dotnetup.Library/Commands/Env/EnvSetCommand.cs | Handles machine-mode transitions. |
| src/Installer/dotnetup.Library/Commands/ElevatedSystemPath/ElevatedSystemPathCommandParser.cs | Parses elevated policy operations. |
| src/Installer/dotnetup.Library/Commands/ElevatedSystemPath/ElevatedSystemPathCommand.cs | Executes elevated policy changes. |
| src/Installer/dotnetup.Library/CommandBase.cs | Enforces admin restrictions. |
| src/Installer/dotnetup.Library/AdminModeSwitcher.cs | Coordinates elevated mode changes. |
| src/Installer/dotnetup.Library/AdminModeSupport.cs | Defines command support contracts. |
| src/Installer/dotnetup.Library/AdminModeGate.cs | Rejects unsupported commands and arguments. |
| src/Installer/dotnetup.Library/AdminInstallRootResolver.cs | Resolves architecture-specific system roots. |
| src/Installer/dotnetup.Library/AccessModeResolver.cs | Resolves policy and user preferences. |
| src/Installer/dotnetup.Library/AccessModeCliParsing.cs | Centralizes mode parsing. |
| documentation/general/dotnetup/signature-verification.md | Documents installer trust and policy. |
| documentation/general/dotnetup/reference/dotnetup-init.md | Documents initialization mode selection. |
| documentation/general/dotnetup/reference/dotnetup-env-set.md | Documents mode transitions. |
| documentation/general/dotnetup/concepts/environment.md | Explains Admin environment behavior. |
| .github/memory/FILE_MAP.md | Maps admin-mode implementation. |
🧠 Review effort: Balanced
nagilson
left a comment
There was a problem hiding this comment.
env script gets written to profiles and fails under admin mode - it should also not resurface user level .net installs with dotnetup if the tags persist - they need to be removedbut dotnetup should remain on the path if switching to admin mode.
We are also missing a hostfxr probe instead of the manifest check for already installed scenarios but I'm ok to defer that to another issue.
I need to continue this later.
Address review feedback on localized messages, concise command names, and unsupported-symbol selection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve the prior migration selection when switching back to an archive mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the admin-mode requirement in validation instead of forcing the request contract from the current mode. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make DotnetupPolicy an instance service over an IDotnetupPolicyStore, with the machine store (WindowsRegistryPolicyStore on Windows, UnixPolicyStore for the sentinel file elsewhere) as the production default. AccessModeResolver, AdminModeSwitcher, CommandBase (and the commands that need it), DotnetDownloader, WindowsBundleArtifact, SelfUpdateNotifier and telemetry common properties take the policy through constructor or method parameters. Remove DotnetupPolicy.Store/ResetStoreForTesting, AccessModeResolver.OverrideForTesting and UnsignedSourcePolicy.OverrideForTesting. Tests now construct the real services over a FakeDotnetupPolicyStore, and the fake elevator applies changes with the same code as the elevated child. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep --untracked validation at the command workflow boundary that owns the option. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the stage-0-compatible baseline TFM for standalone fixtures and reuse the pipeline-built managed dotnetup assembly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move bundle download, verification, process, restart, and exit-code messages into resources and regenerate XLF files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…out holding onto the muxer doing it in process will cause us to block other dotnetup instances or from us replacing the hostfxr.dll ourselves - doing it out of proc will help with that problem.
There was a problem hiding this comment.
Note
Copilot was unable to run its full agentic suite in this review.
Copilot review overview
1 open issue
6 resolved since last review
Separate machine preference and organizational policy registry values Ignore redirected temp directories for admin installer staging Prevent preparation timeouts while commits hold the install mutex Ignore download-cache overrides for admin installer caching Require explicit mode when interactive mode is disabled Hide migration options in Admin mode
Review effort: Lite
Disable Spectre default profile enrichment for explicitly configured test consoles and cover local and Azure Pipelines environments at multiple terminal widths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| /// signature on the replacement for <paramref name="installedPath"/>. Such a download is not | ||
| /// trusted on its hash alone, so the unsigned-download policy does not apply to it. | ||
| /// </summary> | ||
| [SupportedOSPlatformGuard("windows5.1.2600")] |
There was a problem hiding this comment.
Why are you checking against XP? .NET has a list of compatible/supported OS versions for each .NET release.
| /// and every other user, including the same user running without elevation, can only read. | ||
| /// </summary> | ||
| [SupportedOSPlatform("windows")] | ||
| internal static class SecureScratchDirectory |
| } | ||
| } | ||
|
|
||
| private static string RequireFolder(string folder) |
There was a problem hiding this comment.
What's the purpose of this method?
| private const int LOAD_WITH_ALTERED_SEARCH_PATH = 0x8; | ||
|
|
||
| [LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16)] | ||
| [LibraryImport("kernel32.dll", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)] |
There was a problem hiding this comment.
Is this loaded from a safe location?
|
|
||
| `/uninstall` respects reference counts but only VS and a few others respect it - e.g. when tools like PowerToys give the user a link to download the Runtime, that is not reference counted, so garbage collection as it is for non-`admin` modes would remove what users had already requested if the installs are not respected from other sources. | ||
|
|
||
| We also know `/uninstall` on the `.exe` may return `0` even if the install was not uninstalled if other references remain so we must make our own hostfxr API check afterward to see if something was actually uninstalled or not. |
There was a problem hiding this comment.
hostfxr has no knowledge about actual installs. It can tell you what runtimes it thinks are on disk, but nothing about actual installs.
|
|
||
| `dotnetup uninstall` will not initially be supported in `admin` mode. | ||
|
|
||
| `/uninstall` respects reference counts but only VS and a few others respect it - e.g. when tools like PowerToys give the user a link to download the Runtime, that is not reference counted, so garbage collection as it is for non-`admin` modes would remove what users had already requested if the installs are not respected from other sources. |
There was a problem hiding this comment.
Does it? I installed PowerToys, they ship as a self-contained application, but yes, there are plenty of applications that either prompt or chain various .NET runtimes. I'm not sure what you mean by reference count in this context. The MSI are always ref counted against the parent bundle, but we never ref count the bundles
|
|
||
| ## Concurrency | ||
|
|
||
| Simultaneous commit operations - which in non-admin means 'extract', is not possible with MSI installs. `dotnetup` already defers the extract operation to one sequential step with concurrent downloads. The commit operation will happen sequentially in the same way. Concurrency will be deferred to avoid multi-UAC prompting. |
There was a problem hiding this comment.
The only reason to install sequentially is because per-machine MSIs are not permitted to run concurrently by the window installer service.
| | Result | Handling | | ||
| | --- | --- | | ||
| | `0` | Success. | | ||
| | `3010`, `1641` | Success. A restart is required; `dotnetup` reports this and does not restart. | |
There was a problem hiding this comment.
1641 is considered a success code, but if you ever receive it, it means that a restart is already underway whereas 3010 is to inform the user they may need to restart to complete the install, e.g. pending file renames.


Implements the MVP of
dotnetup <> install --untrackedunderadminmode, per the specification in #56603. Please read that specification for details / design components, such as howPATHhandling is owned by the admin installer(.exe MSI bundle)rather thandotnetup.In this PR:
adminmode is added as a configuration, only for Windowsinstallfunctionality is added at a relatively straightforward level.dailybuilds under admin mode are disabled by default but enable-able via policy settings in the registry, considering they are unsigned.dotnetupfails on all other commands or arguments underadminmode, to prevent buggy or unexpected behavior.dotnetupin other contexts.Timeout handling and process termination / cancellation of the admin installer is left for another PR to reduce scope: nagilson#211
Initial Switch
Examples of Unsupported Scenarios
It handles cancellation
It Installs non daily builds when online locally
If you ctrl + c (we can't stop the admin installer)
Going out of Admin mode (UAC again)