From 48792874db6a32d2664c7bad2a1e284acab95f28 Mon Sep 17 00:00:00 2001
From: MengAiDev Meng <3463526515@qq.com>
Date: Fri, 29 Aug 2025 10:12:06 +0000
Subject: [PATCH 1/2] Fix line endings and add IncludePrerelease parameter
support
- Convert CRLF to LF line endings across PowerShell cmdlets
- Add IncludePrerelease parameter to Assert-WinGetPackageManager and Repair-WinGetPackageManager
- Make IncludePrerelease parameter available across all parameter sets
- Update WinGetPackageManagerCommand to handle prerelease versions in repair operations
---
.../AssertWinGetPackageManagerCmdlet.cs | 82 +--
.../Common/WinGetPackageManagerCmdlet.cs | 81 ++-
.../RepairWinGetPackageManagerCmdlet.cs | 134 ++---
.../Commands/WinGetPackageManagerCommand.cs | 484 +++++++++---------
4 files changed, 396 insertions(+), 385 deletions(-)
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
index b33bdbd502..712c464d26 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
@@ -1,41 +1,41 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Commands.Common;
- using Microsoft.WinGet.Client.Common;
- using Microsoft.WinGet.Client.Engine.Commands;
-
- ///
- /// Assert-WinGetPackageManager. Verifies winget is installed properly.
- ///
- [Cmdlet(
- VerbsLifecycle.Assert,
- Constants.WinGetNouns.WinGetPackageManager,
- DefaultParameterSetName = Constants.IntegrityVersionSet)]
- [Alias("awgpm")]
- public class AssertWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
- {
- ///
- /// Validates winget is installed correctly. If not, throws an exception
- /// with the reason why, if any.
- ///
- protected override void ProcessRecord()
- {
- var command = new WinGetPackageManagerCommand(this);
- if (this.ParameterSetName == Constants.IntegrityLatestSet)
- {
- command.AssertUsingLatest(this.IncludePrerelease.ToBool());
- }
- else
- {
- command.Assert(this.Version);
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Commands.Common;
+ using Microsoft.WinGet.Client.Common;
+ using Microsoft.WinGet.Client.Engine.Commands;
+
+ ///
+ /// Assert-WinGetPackageManager. Verifies winget is installed properly.
+ ///
+ [Cmdlet(
+ VerbsLifecycle.Assert,
+ Constants.WinGetNouns.WinGetPackageManager,
+ DefaultParameterSetName = Constants.IntegrityVersionSet)]
+ [Alias("awgpm")]
+ public class AssertWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
+ {
+ ///
+ /// Validates winget is installed correctly. If not, throws an exception
+ /// with the reason why, if any.
+ ///
+ protected override void ProcessRecord()
+ {
+ var command = new WinGetPackageManagerCommand(this);
+ if (this.ParameterSetName == Constants.IntegrityLatestSet)
+ {
+ command.AssertUsingLatest(this.IncludePrerelease.ToBool());
+ }
+ else
+ {
+ command.Assert(this.Version, this.IncludePrerelease.ToBool());
+ }
+ }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
index 3d2f4d16d7..2977559cc2 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
@@ -1,41 +1,40 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands.Common
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Common;
-
- ///
- /// Common parameters for Assert-WinGetPackageManager and Repair-WinGetPackageManager.
- ///
- public abstract class WinGetPackageManagerCmdlet : PSCmdlet
- {
- ///
- /// Gets or sets the optional version.
- ///
- [Parameter(
- ParameterSetName = Constants.IntegrityVersionSet,
- ValueFromPipelineByPropertyName = true)]
- public string Version { get; set; } = string.Empty;
-
- ///
- /// Gets or sets a value indicating whether to use latest.
- ///
- [Parameter(
- ParameterSetName = Constants.IntegrityLatestSet,
- ValueFromPipelineByPropertyName = true)]
- public SwitchParameter Latest { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to include prerelease winget versions.
- ///
- [Parameter(
- ParameterSetName = Constants.IntegrityLatestSet,
- ValueFromPipelineByPropertyName = true)]
- public SwitchParameter IncludePrerelease { get; set; }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands.Common
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Common;
+
+ ///
+ /// Common parameters for Assert-WinGetPackageManager and Repair-WinGetPackageManager.
+ ///
+ public abstract class WinGetPackageManagerCmdlet : PSCmdlet
+ {
+ ///
+ /// Gets or sets the optional version.
+ ///
+ [Parameter(
+ ParameterSetName = Constants.IntegrityVersionSet,
+ ValueFromPipelineByPropertyName = true)]
+ public string Version { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating whether to use latest.
+ ///
+ [Parameter(
+ ParameterSetName = Constants.IntegrityLatestSet,
+ ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Latest { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to include prerelease winget versions.
+ ///
+ [Parameter(
+ ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter IncludePrerelease { get; set; }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
index b3e6ae4df2..c53bac23e0 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
@@ -1,67 +1,67 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Commands.Common;
- using Microsoft.WinGet.Client.Common;
- using Microsoft.WinGet.Client.Engine.Commands;
-
- ///
- /// Repair-WinGetPackageManager. Repairs winget if needed.
- ///
- [Cmdlet(
- VerbsDiagnostic.Repair,
- Constants.WinGetNouns.WinGetPackageManager,
- DefaultParameterSetName = Constants.IntegrityVersionSet)]
- [Alias("rpwgpm")]
- [OutputType(typeof(int))]
- public class RepairWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
- {
- private WinGetPackageManagerCommand command = null;
-
- ///
- /// Gets or sets a value indicating whether to repair for all users. Requires admin.
- ///
- [Parameter(ValueFromPipelineByPropertyName = true)]
- public SwitchParameter AllUsers { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to force application shutdown.
- ///
- [Parameter(ValueFromPipelineByPropertyName = true)]
- public SwitchParameter Force { get; set; }
-
- ///
- /// Attempts to repair winget.
- /// TODO: consider WhatIf and Confirm options.
- ///
- protected override void ProcessRecord()
- {
- this.command = new WinGetPackageManagerCommand(this);
- if (this.ParameterSetName == Constants.IntegrityLatestSet)
- {
- this.command.RepairUsingLatest(this.IncludePrerelease.ToBool(), this.AllUsers.ToBool(), this.Force.ToBool());
- }
- else
- {
- this.command.Repair(this.Version, this.AllUsers.ToBool(), this.Force.ToBool());
- }
- }
-
- ///
- /// Interrupts currently running code within the command.
- ///
- protected override void StopProcessing()
- {
- if (this.command != null)
- {
- this.command.Cancel();
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Commands.Common;
+ using Microsoft.WinGet.Client.Common;
+ using Microsoft.WinGet.Client.Engine.Commands;
+
+ ///
+ /// Repair-WinGetPackageManager. Repairs winget if needed.
+ ///
+ [Cmdlet(
+ VerbsDiagnostic.Repair,
+ Constants.WinGetNouns.WinGetPackageManager,
+ DefaultParameterSetName = Constants.IntegrityVersionSet)]
+ [Alias("rpwgpm")]
+ [OutputType(typeof(int))]
+ public class RepairWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
+ {
+ private WinGetPackageManagerCommand command = null;
+
+ ///
+ /// Gets or sets a value indicating whether to repair for all users. Requires admin.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter AllUsers { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to force application shutdown.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Force { get; set; }
+
+ ///
+ /// Attempts to repair winget.
+ /// TODO: consider WhatIf and Confirm options.
+ ///
+ protected override void ProcessRecord()
+ {
+ this.command = new WinGetPackageManagerCommand(this);
+ if (this.ParameterSetName == Constants.IntegrityLatestSet)
+ {
+ this.command.RepairUsingLatest(this.IncludePrerelease.ToBool(), this.AllUsers.ToBool(), this.Force.ToBool());
+ }
+ else
+ {
+ this.command.Repair(this.Version, this.AllUsers.ToBool(), this.Force.ToBool(), this.IncludePrerelease.ToBool());
+ }
+ }
+
+ ///
+ /// Interrupts currently running code within the command.
+ ///
+ protected override void StopProcessing()
+ {
+ if (this.command != null)
+ {
+ this.command.Cancel();
+ }
+ }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs b/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
index cdf5f16d51..ab62170916 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
@@ -1,236 +1,248 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Engine.Commands
-{
- using System;
- using System.Collections.Generic;
- using System.Management.Automation;
- using System.Threading.Tasks;
- using Microsoft.WinGet.Client.Engine.Commands.Common;
- using Microsoft.WinGet.Client.Engine.Common;
- using Microsoft.WinGet.Client.Engine.Exceptions;
- using Microsoft.WinGet.Client.Engine.Helpers;
- using Microsoft.WinGet.Common.Command;
- using Microsoft.WinGet.Resources;
- using static Microsoft.WinGet.Client.Engine.Common.Constants;
-
- ///
- /// Used by Repair-WinGetPackageManager and Assert-WinGetPackageManager.
- ///
- public sealed class WinGetPackageManagerCommand : BaseCommand
- {
- private const string EnvPath = "env:PATH";
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Cmdlet being executed.
- public WinGetPackageManagerCommand(PSCmdlet psCmdlet)
- : base(psCmdlet)
- {
- }
-
- ///
- /// Asserts winget version is the latest version on winget-cli.
- ///
- /// Use prerelease version on GitHub.
- public void AssertUsingLatest(bool preRelease)
- {
- var runningTask = this.RunOnMTA(
- async () =>
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
- this.Assert(expectedVersion);
- return true;
- });
-
- this.Wait(runningTask);
- }
-
- ///
- /// Asserts the version installed is the specified.
- ///
- /// The expected version.
- public void Assert(string expectedVersion)
- {
- WinGetIntegrity.AssertWinGet(this, expectedVersion);
- }
-
- ///
- /// Repairs winget using the latest version on winget-cli.
- ///
- /// Use prerelease version on GitHub.
- /// Install for all users. Requires admin.
- /// Force application shutdown.
- public void RepairUsingLatest(bool preRelease, bool allUsers, bool force)
- {
- this.ValidateWhenAllUsers(allUsers);
- var runningTask = this.RunOnMTA(
- async () =>
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
- await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
- return true;
- });
-
- this.Wait(runningTask);
- }
-
- ///
- /// Repairs winget if needed.
- ///
- /// The expected version, if any.
- /// Install for all users. Requires admin.
- /// Force application shutdown.
- public void Repair(string expectedVersion, bool allUsers, bool force)
- {
- this.ValidateWhenAllUsers(allUsers);
- var runningTask = this.RunOnMTA(
- async () =>
- {
- await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
- return true;
- });
- this.Wait(runningTask);
- }
-
- private async Task RepairStateMachineAsync(string expectedVersion, bool allUsers, bool force)
- {
- var seenCategories = new HashSet();
- var cancellationToken = this.GetCancellationToken();
-
- var currentCategory = IntegrityCategory.Unknown;
- while (currentCategory != IntegrityCategory.Installed)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- WinGetIntegrity.AssertWinGet(this, expectedVersion);
- this.Write(StreamType.Verbose, $"WinGet is in a good state.");
- currentCategory = IntegrityCategory.Installed;
- }
- catch (WinGetIntegrityException e)
- {
- currentCategory = e.Category;
-
- if (seenCategories.Contains(currentCategory))
- {
- this.Write(StreamType.Verbose, $"{currentCategory} encountered previously");
- throw;
- }
-
- this.Write(StreamType.Verbose, $"Integrity category type: {currentCategory}");
- seenCategories.Add(currentCategory);
-
- switch (currentCategory)
- {
- case IntegrityCategory.UnexpectedVersion:
- await this.InstallDifferentVersionAsync(new WinGetVersion(expectedVersion), allUsers, force);
- break;
- case IntegrityCategory.NotInPath:
- this.RepairEnvPath();
- break;
- case IntegrityCategory.AppInstallerNotRegistered:
- this.Register(expectedVersion);
- break;
- case IntegrityCategory.AppInstallerNotInstalled:
- case IntegrityCategory.AppInstallerNotSupported:
- case IntegrityCategory.Failure:
- await this.InstallAsync(expectedVersion, allUsers, force);
- break;
- case IntegrityCategory.AppInstallerNoLicense:
- // This requires -AllUsers in admin mode.
- if (allUsers && Utilities.ExecutingAsAdministrator)
- {
- await this.InstallAsync(expectedVersion, allUsers, force);
- }
- else
- {
- throw new WinGetRepairException(e);
- }
-
- break;
- case IntegrityCategory.AppExecutionAliasDisabled:
- case IntegrityCategory.Unknown:
- throw new WinGetRepairException(e);
- default:
- throw new NotSupportedException();
- }
- }
- }
- }
-
- private async Task InstallDifferentVersionAsync(WinGetVersion toInstallVersion, bool allUsers, bool force)
- {
- var installedVersion = WinGetVersion.InstalledWinGetVersion(this);
- bool isDowngrade = installedVersion.CompareAsDeployment(toInstallVersion) > 0;
-
- string message = $"Installed WinGet version '{installedVersion.TagVersion}' " +
- $"Installing WinGet version '{toInstallVersion.TagVersion}' " +
- $"Is downgrade {isDowngrade}";
- this.Write(
- StreamType.Verbose,
- message);
- var appxModule = new AppxModuleHelper(this);
- await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion.TagVersion, allUsers, isDowngrade, force);
- }
-
- private async Task InstallAsync(string toInstallVersion, bool allUsers, bool force)
- {
- // If we are here and toInstallVersion is empty, it means that they just ran Repair-WinGetPackageManager.
- // When there is not version specified, we don't want to assume an empty version means latest, but in
- // this particular case we need to.
- if (string.IsNullOrEmpty(toInstallVersion))
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- toInstallVersion = await gitHubClient.GetLatestReleaseTagNameAsync(false);
- }
-
- var appxModule = new AppxModuleHelper(this);
- await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion, allUsers, false, force);
- }
-
- private void Register(string toRegisterVersion)
- {
- var appxModule = new AppxModuleHelper(this);
- appxModule.RegisterAppInstaller(toRegisterVersion);
- }
-
- private void RepairEnvPath()
- {
- // Add windows app path to user PATH environment variable
- Utilities.AddWindowsAppToPath();
-
- // Update this sessions PowerShell environment so the user doesn't have to restart the terminal.
- string? envPathUser = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.User);
- string? envPathMachine = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.Machine);
- string newPwshPathEnv = $"{envPathMachine};{envPathUser}";
- this.SetVariable(EnvPath, newPwshPathEnv);
-
- this.Write(StreamType.Verbose, $"PATH environment variable updated");
- }
-
- private void ValidateWhenAllUsers(bool allUsers)
- {
- if (allUsers)
- {
- if (Utilities.ExecutingAsSystem)
- {
- throw new NotSupportedException();
- }
-
- if (!Utilities.ExecutingAsAdministrator)
- {
- throw new WinGetRepairException(Resources.RepairAllUsersMessage);
- }
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Engine.Commands
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Management.Automation;
+ using System.Threading.Tasks;
+ using Microsoft.WinGet.Client.Engine.Commands.Common;
+ using Microsoft.WinGet.Client.Engine.Common;
+ using Microsoft.WinGet.Client.Engine.Exceptions;
+ using Microsoft.WinGet.Client.Engine.Helpers;
+ using Microsoft.WinGet.Common.Command;
+ using Microsoft.WinGet.Resources;
+ using static Microsoft.WinGet.Client.Engine.Common.Constants;
+
+ ///
+ /// Used by Repair-WinGetPackageManager and Assert-WinGetPackageManager.
+ ///
+ public sealed class WinGetPackageManagerCommand : BaseCommand
+ {
+ private const string EnvPath = "env:PATH";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Cmdlet being executed.
+ public WinGetPackageManagerCommand(PSCmdlet psCmdlet)
+ : base(psCmdlet)
+ {
+ }
+
+ ///
+ /// Asserts winget version is the latest version on winget-cli.
+ ///
+ /// Use prerelease version on GitHub.
+ public void AssertUsingLatest(bool preRelease)
+ {
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
+ this.Assert(expectedVersion);
+ return true;
+ });
+
+ this.Wait(runningTask);
+ }
+
+ ///
+ /// Asserts the version installed is the specified.
+ ///
+ /// The expected version.
+ /// Include prerelease versions when validating the specified version.
+ public void Assert(string expectedVersion, bool preRelease = false)
+ {
+ // The preRelease parameter is for consistency but not used in this method
+ // since we're checking for an exact version match
+ WinGetIntegrity.AssertWinGet(this, expectedVersion);
+ }
+
+ ///
+ /// Repairs winget using the latest version on winget-cli.
+ ///
+ /// Use prerelease version on GitHub.
+ /// Install for all users. Requires admin.
+ /// Force application shutdown.
+ public void RepairUsingLatest(bool preRelease, bool allUsers, bool force)
+ {
+ this.ValidateWhenAllUsers(allUsers);
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
+ await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
+ return true;
+ });
+
+ this.Wait(runningTask);
+ }
+
+ ///
+ /// Repairs winget if needed.
+ ///
+ /// The expected version, if any.
+ /// Install for all users. Requires admin.
+ /// Force application shutdown.
+ /// Include prerelease versions when searching for the specified version.
+ public void Repair(string expectedVersion, bool allUsers, bool force, bool preRelease = false)
+ {
+ this.ValidateWhenAllUsers(allUsers);
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ // If no specific version is provided and IncludePrerelease is specified,
+ // we need to get the latest prerelease version
+ if (string.IsNullOrEmpty(expectedVersion) && preRelease)
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(true);
+ }
+
+ await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
+ return true;
+ });
+ this.Wait(runningTask);
+ }
+
+ private async Task RepairStateMachineAsync(string expectedVersion, bool allUsers, bool force)
+ {
+ var seenCategories = new HashSet();
+ var cancellationToken = this.GetCancellationToken();
+
+ var currentCategory = IntegrityCategory.Unknown;
+ while (currentCategory != IntegrityCategory.Installed)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ WinGetIntegrity.AssertWinGet(this, expectedVersion);
+ this.Write(StreamType.Verbose, $"WinGet is in a good state.");
+ currentCategory = IntegrityCategory.Installed;
+ }
+ catch (WinGetIntegrityException e)
+ {
+ currentCategory = e.Category;
+
+ if (seenCategories.Contains(currentCategory))
+ {
+ this.Write(StreamType.Verbose, $"{currentCategory} encountered previously");
+ throw;
+ }
+
+ this.Write(StreamType.Verbose, $"Integrity category type: {currentCategory}");
+ seenCategories.Add(currentCategory);
+
+ switch (currentCategory)
+ {
+ case IntegrityCategory.UnexpectedVersion:
+ await this.InstallDifferentVersionAsync(new WinGetVersion(expectedVersion), allUsers, force);
+ break;
+ case IntegrityCategory.NotInPath:
+ this.RepairEnvPath();
+ break;
+ case IntegrityCategory.AppInstallerNotRegistered:
+ this.Register(expectedVersion);
+ break;
+ case IntegrityCategory.AppInstallerNotInstalled:
+ case IntegrityCategory.AppInstallerNotSupported:
+ case IntegrityCategory.Failure:
+ await this.InstallAsync(expectedVersion, allUsers, force);
+ break;
+ case IntegrityCategory.AppInstallerNoLicense:
+ // This requires -AllUsers in admin mode.
+ if (allUsers && Utilities.ExecutingAsAdministrator)
+ {
+ await this.InstallAsync(expectedVersion, allUsers, force);
+ }
+ else
+ {
+ throw new WinGetRepairException(e);
+ }
+
+ break;
+ case IntegrityCategory.AppExecutionAliasDisabled:
+ case IntegrityCategory.Unknown:
+ throw new WinGetRepairException(e);
+ default:
+ throw new NotSupportedException();
+ }
+ }
+ }
+ }
+
+ private async Task InstallDifferentVersionAsync(WinGetVersion toInstallVersion, bool allUsers, bool force)
+ {
+ var installedVersion = WinGetVersion.InstalledWinGetVersion(this);
+ bool isDowngrade = installedVersion.CompareAsDeployment(toInstallVersion) > 0;
+
+ string message = $"Installed WinGet version '{installedVersion.TagVersion}' " +
+ $"Installing WinGet version '{toInstallVersion.TagVersion}' " +
+ $"Is downgrade {isDowngrade}";
+ this.Write(
+ StreamType.Verbose,
+ message);
+ var appxModule = new AppxModuleHelper(this);
+ await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion.TagVersion, allUsers, isDowngrade, force);
+ }
+
+ private async Task InstallAsync(string toInstallVersion, bool allUsers, bool force)
+ {
+ // If we are here and toInstallVersion is empty, it means that they just ran Repair-WinGetPackageManager.
+ // When there is not version specified, we don't want to assume an empty version means latest, but in
+ // this particular case we need to.
+ if (string.IsNullOrEmpty(toInstallVersion))
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ toInstallVersion = await gitHubClient.GetLatestReleaseTagNameAsync(false);
+ }
+
+ var appxModule = new AppxModuleHelper(this);
+ await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion, allUsers, false, force);
+ }
+
+ private void Register(string toRegisterVersion)
+ {
+ var appxModule = new AppxModuleHelper(this);
+ appxModule.RegisterAppInstaller(toRegisterVersion);
+ }
+
+ private void RepairEnvPath()
+ {
+ // Add windows app path to user PATH environment variable
+ Utilities.AddWindowsAppToPath();
+
+ // Update this sessions PowerShell environment so the user doesn't have to restart the terminal.
+ string? envPathUser = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.User);
+ string? envPathMachine = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.Machine);
+ string newPwshPathEnv = $"{envPathMachine};{envPathUser}";
+ this.SetVariable(EnvPath, newPwshPathEnv);
+
+ this.Write(StreamType.Verbose, $"PATH environment variable updated");
+ }
+
+ private void ValidateWhenAllUsers(bool allUsers)
+ {
+ if (allUsers)
+ {
+ if (Utilities.ExecutingAsSystem)
+ {
+ throw new NotSupportedException();
+ }
+
+ if (!Utilities.ExecutingAsAdministrator)
+ {
+ throw new WinGetRepairException(Resources.RepairAllUsersMessage);
+ }
+ }
+ }
+ }
+}
From e40bcebd23d501655d977a05fc0948dec59c863b Mon Sep 17 00:00:00 2001
From: MengAiDev Meng <3463526515@qq.com>
Date: Fri, 29 Aug 2025 10:25:53 +0000
Subject: [PATCH 2/2] crlf
---
.../AssertWinGetPackageManagerCmdlet.cs | 82 +--
.../Common/WinGetPackageManagerCmdlet.cs | 80 +--
.../RepairWinGetPackageManagerCmdlet.cs | 134 ++---
.../Commands/WinGetPackageManagerCommand.cs | 496 +++++++++---------
4 files changed, 396 insertions(+), 396 deletions(-)
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
index 712c464d26..4c68f32288 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/AssertWinGetPackageManagerCmdlet.cs
@@ -1,41 +1,41 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Commands.Common;
- using Microsoft.WinGet.Client.Common;
- using Microsoft.WinGet.Client.Engine.Commands;
-
- ///
- /// Assert-WinGetPackageManager. Verifies winget is installed properly.
- ///
- [Cmdlet(
- VerbsLifecycle.Assert,
- Constants.WinGetNouns.WinGetPackageManager,
- DefaultParameterSetName = Constants.IntegrityVersionSet)]
- [Alias("awgpm")]
- public class AssertWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
- {
- ///
- /// Validates winget is installed correctly. If not, throws an exception
- /// with the reason why, if any.
- ///
- protected override void ProcessRecord()
- {
- var command = new WinGetPackageManagerCommand(this);
- if (this.ParameterSetName == Constants.IntegrityLatestSet)
- {
- command.AssertUsingLatest(this.IncludePrerelease.ToBool());
- }
- else
- {
- command.Assert(this.Version, this.IncludePrerelease.ToBool());
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Commands.Common;
+ using Microsoft.WinGet.Client.Common;
+ using Microsoft.WinGet.Client.Engine.Commands;
+
+ ///
+ /// Assert-WinGetPackageManager. Verifies winget is installed properly.
+ ///
+ [Cmdlet(
+ VerbsLifecycle.Assert,
+ Constants.WinGetNouns.WinGetPackageManager,
+ DefaultParameterSetName = Constants.IntegrityVersionSet)]
+ [Alias("awgpm")]
+ public class AssertWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
+ {
+ ///
+ /// Validates winget is installed correctly. If not, throws an exception
+ /// with the reason why, if any.
+ ///
+ protected override void ProcessRecord()
+ {
+ var command = new WinGetPackageManagerCommand(this);
+ if (this.ParameterSetName == Constants.IntegrityLatestSet)
+ {
+ command.AssertUsingLatest(this.IncludePrerelease.ToBool());
+ }
+ else
+ {
+ command.Assert(this.Version, this.IncludePrerelease.ToBool());
+ }
+ }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
index 2977559cc2..7d2bd9121e 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/Common/WinGetPackageManagerCmdlet.cs
@@ -1,40 +1,40 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands.Common
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Common;
-
- ///
- /// Common parameters for Assert-WinGetPackageManager and Repair-WinGetPackageManager.
- ///
- public abstract class WinGetPackageManagerCmdlet : PSCmdlet
- {
- ///
- /// Gets or sets the optional version.
- ///
- [Parameter(
- ParameterSetName = Constants.IntegrityVersionSet,
- ValueFromPipelineByPropertyName = true)]
- public string Version { get; set; } = string.Empty;
-
- ///
- /// Gets or sets a value indicating whether to use latest.
- ///
- [Parameter(
- ParameterSetName = Constants.IntegrityLatestSet,
- ValueFromPipelineByPropertyName = true)]
- public SwitchParameter Latest { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to include prerelease winget versions.
- ///
- [Parameter(
- ValueFromPipelineByPropertyName = true)]
- public SwitchParameter IncludePrerelease { get; set; }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands.Common
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Common;
+
+ ///
+ /// Common parameters for Assert-WinGetPackageManager and Repair-WinGetPackageManager.
+ ///
+ public abstract class WinGetPackageManagerCmdlet : PSCmdlet
+ {
+ ///
+ /// Gets or sets the optional version.
+ ///
+ [Parameter(
+ ParameterSetName = Constants.IntegrityVersionSet,
+ ValueFromPipelineByPropertyName = true)]
+ public string Version { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating whether to use latest.
+ ///
+ [Parameter(
+ ParameterSetName = Constants.IntegrityLatestSet,
+ ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Latest { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to include prerelease winget versions.
+ ///
+ [Parameter(
+ ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter IncludePrerelease { get; set; }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
index c53bac23e0..4939355878 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Cmdlets/Cmdlets/RepairWinGetPackageManagerCmdlet.cs
@@ -1,67 +1,67 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Commands
-{
- using System.Management.Automation;
- using Microsoft.WinGet.Client.Commands.Common;
- using Microsoft.WinGet.Client.Common;
- using Microsoft.WinGet.Client.Engine.Commands;
-
- ///
- /// Repair-WinGetPackageManager. Repairs winget if needed.
- ///
- [Cmdlet(
- VerbsDiagnostic.Repair,
- Constants.WinGetNouns.WinGetPackageManager,
- DefaultParameterSetName = Constants.IntegrityVersionSet)]
- [Alias("rpwgpm")]
- [OutputType(typeof(int))]
- public class RepairWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
- {
- private WinGetPackageManagerCommand command = null;
-
- ///
- /// Gets or sets a value indicating whether to repair for all users. Requires admin.
- ///
- [Parameter(ValueFromPipelineByPropertyName = true)]
- public SwitchParameter AllUsers { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to force application shutdown.
- ///
- [Parameter(ValueFromPipelineByPropertyName = true)]
- public SwitchParameter Force { get; set; }
-
- ///
- /// Attempts to repair winget.
- /// TODO: consider WhatIf and Confirm options.
- ///
- protected override void ProcessRecord()
- {
- this.command = new WinGetPackageManagerCommand(this);
- if (this.ParameterSetName == Constants.IntegrityLatestSet)
- {
- this.command.RepairUsingLatest(this.IncludePrerelease.ToBool(), this.AllUsers.ToBool(), this.Force.ToBool());
- }
- else
- {
- this.command.Repair(this.Version, this.AllUsers.ToBool(), this.Force.ToBool(), this.IncludePrerelease.ToBool());
- }
- }
-
- ///
- /// Interrupts currently running code within the command.
- ///
- protected override void StopProcessing()
- {
- if (this.command != null)
- {
- this.command.Cancel();
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Commands
+{
+ using System.Management.Automation;
+ using Microsoft.WinGet.Client.Commands.Common;
+ using Microsoft.WinGet.Client.Common;
+ using Microsoft.WinGet.Client.Engine.Commands;
+
+ ///
+ /// Repair-WinGetPackageManager. Repairs winget if needed.
+ ///
+ [Cmdlet(
+ VerbsDiagnostic.Repair,
+ Constants.WinGetNouns.WinGetPackageManager,
+ DefaultParameterSetName = Constants.IntegrityVersionSet)]
+ [Alias("rpwgpm")]
+ [OutputType(typeof(int))]
+ public class RepairWinGetPackageManagerCmdlet : WinGetPackageManagerCmdlet
+ {
+ private WinGetPackageManagerCommand command = null;
+
+ ///
+ /// Gets or sets a value indicating whether to repair for all users. Requires admin.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter AllUsers { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to force application shutdown.
+ ///
+ [Parameter(ValueFromPipelineByPropertyName = true)]
+ public SwitchParameter Force { get; set; }
+
+ ///
+ /// Attempts to repair winget.
+ /// TODO: consider WhatIf and Confirm options.
+ ///
+ protected override void ProcessRecord()
+ {
+ this.command = new WinGetPackageManagerCommand(this);
+ if (this.ParameterSetName == Constants.IntegrityLatestSet)
+ {
+ this.command.RepairUsingLatest(this.IncludePrerelease.ToBool(), this.AllUsers.ToBool(), this.Force.ToBool());
+ }
+ else
+ {
+ this.command.Repair(this.Version, this.AllUsers.ToBool(), this.Force.ToBool(), this.IncludePrerelease.ToBool());
+ }
+ }
+
+ ///
+ /// Interrupts currently running code within the command.
+ ///
+ protected override void StopProcessing()
+ {
+ if (this.command != null)
+ {
+ this.command.Cancel();
+ }
+ }
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs b/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
index ab62170916..aa529cab98 100644
--- a/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
@@ -1,248 +1,248 @@
-// -----------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
-//
-// -----------------------------------------------------------------------------
-
-namespace Microsoft.WinGet.Client.Engine.Commands
-{
- using System;
- using System.Collections.Generic;
- using System.Management.Automation;
- using System.Threading.Tasks;
- using Microsoft.WinGet.Client.Engine.Commands.Common;
- using Microsoft.WinGet.Client.Engine.Common;
- using Microsoft.WinGet.Client.Engine.Exceptions;
- using Microsoft.WinGet.Client.Engine.Helpers;
- using Microsoft.WinGet.Common.Command;
- using Microsoft.WinGet.Resources;
- using static Microsoft.WinGet.Client.Engine.Common.Constants;
-
- ///
- /// Used by Repair-WinGetPackageManager and Assert-WinGetPackageManager.
- ///
- public sealed class WinGetPackageManagerCommand : BaseCommand
- {
- private const string EnvPath = "env:PATH";
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Cmdlet being executed.
- public WinGetPackageManagerCommand(PSCmdlet psCmdlet)
- : base(psCmdlet)
- {
- }
-
- ///
- /// Asserts winget version is the latest version on winget-cli.
- ///
- /// Use prerelease version on GitHub.
- public void AssertUsingLatest(bool preRelease)
- {
- var runningTask = this.RunOnMTA(
- async () =>
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
- this.Assert(expectedVersion);
- return true;
- });
-
- this.Wait(runningTask);
- }
-
- ///
- /// Asserts the version installed is the specified.
- ///
- /// The expected version.
- /// Include prerelease versions when validating the specified version.
- public void Assert(string expectedVersion, bool preRelease = false)
- {
- // The preRelease parameter is for consistency but not used in this method
- // since we're checking for an exact version match
- WinGetIntegrity.AssertWinGet(this, expectedVersion);
- }
-
- ///
- /// Repairs winget using the latest version on winget-cli.
- ///
- /// Use prerelease version on GitHub.
- /// Install for all users. Requires admin.
- /// Force application shutdown.
- public void RepairUsingLatest(bool preRelease, bool allUsers, bool force)
- {
- this.ValidateWhenAllUsers(allUsers);
- var runningTask = this.RunOnMTA(
- async () =>
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
- await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
- return true;
- });
-
- this.Wait(runningTask);
- }
-
- ///
- /// Repairs winget if needed.
- ///
- /// The expected version, if any.
- /// Install for all users. Requires admin.
- /// Force application shutdown.
- /// Include prerelease versions when searching for the specified version.
- public void Repair(string expectedVersion, bool allUsers, bool force, bool preRelease = false)
- {
- this.ValidateWhenAllUsers(allUsers);
- var runningTask = this.RunOnMTA(
- async () =>
- {
- // If no specific version is provided and IncludePrerelease is specified,
- // we need to get the latest prerelease version
- if (string.IsNullOrEmpty(expectedVersion) && preRelease)
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(true);
- }
-
- await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
- return true;
- });
- this.Wait(runningTask);
- }
-
- private async Task RepairStateMachineAsync(string expectedVersion, bool allUsers, bool force)
- {
- var seenCategories = new HashSet();
- var cancellationToken = this.GetCancellationToken();
-
- var currentCategory = IntegrityCategory.Unknown;
- while (currentCategory != IntegrityCategory.Installed)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- try
- {
- WinGetIntegrity.AssertWinGet(this, expectedVersion);
- this.Write(StreamType.Verbose, $"WinGet is in a good state.");
- currentCategory = IntegrityCategory.Installed;
- }
- catch (WinGetIntegrityException e)
- {
- currentCategory = e.Category;
-
- if (seenCategories.Contains(currentCategory))
- {
- this.Write(StreamType.Verbose, $"{currentCategory} encountered previously");
- throw;
- }
-
- this.Write(StreamType.Verbose, $"Integrity category type: {currentCategory}");
- seenCategories.Add(currentCategory);
-
- switch (currentCategory)
- {
- case IntegrityCategory.UnexpectedVersion:
- await this.InstallDifferentVersionAsync(new WinGetVersion(expectedVersion), allUsers, force);
- break;
- case IntegrityCategory.NotInPath:
- this.RepairEnvPath();
- break;
- case IntegrityCategory.AppInstallerNotRegistered:
- this.Register(expectedVersion);
- break;
- case IntegrityCategory.AppInstallerNotInstalled:
- case IntegrityCategory.AppInstallerNotSupported:
- case IntegrityCategory.Failure:
- await this.InstallAsync(expectedVersion, allUsers, force);
- break;
- case IntegrityCategory.AppInstallerNoLicense:
- // This requires -AllUsers in admin mode.
- if (allUsers && Utilities.ExecutingAsAdministrator)
- {
- await this.InstallAsync(expectedVersion, allUsers, force);
- }
- else
- {
- throw new WinGetRepairException(e);
- }
-
- break;
- case IntegrityCategory.AppExecutionAliasDisabled:
- case IntegrityCategory.Unknown:
- throw new WinGetRepairException(e);
- default:
- throw new NotSupportedException();
- }
- }
- }
- }
-
- private async Task InstallDifferentVersionAsync(WinGetVersion toInstallVersion, bool allUsers, bool force)
- {
- var installedVersion = WinGetVersion.InstalledWinGetVersion(this);
- bool isDowngrade = installedVersion.CompareAsDeployment(toInstallVersion) > 0;
-
- string message = $"Installed WinGet version '{installedVersion.TagVersion}' " +
- $"Installing WinGet version '{toInstallVersion.TagVersion}' " +
- $"Is downgrade {isDowngrade}";
- this.Write(
- StreamType.Verbose,
- message);
- var appxModule = new AppxModuleHelper(this);
- await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion.TagVersion, allUsers, isDowngrade, force);
- }
-
- private async Task InstallAsync(string toInstallVersion, bool allUsers, bool force)
- {
- // If we are here and toInstallVersion is empty, it means that they just ran Repair-WinGetPackageManager.
- // When there is not version specified, we don't want to assume an empty version means latest, but in
- // this particular case we need to.
- if (string.IsNullOrEmpty(toInstallVersion))
- {
- var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
- toInstallVersion = await gitHubClient.GetLatestReleaseTagNameAsync(false);
- }
-
- var appxModule = new AppxModuleHelper(this);
- await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion, allUsers, false, force);
- }
-
- private void Register(string toRegisterVersion)
- {
- var appxModule = new AppxModuleHelper(this);
- appxModule.RegisterAppInstaller(toRegisterVersion);
- }
-
- private void RepairEnvPath()
- {
- // Add windows app path to user PATH environment variable
- Utilities.AddWindowsAppToPath();
-
- // Update this sessions PowerShell environment so the user doesn't have to restart the terminal.
- string? envPathUser = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.User);
- string? envPathMachine = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.Machine);
- string newPwshPathEnv = $"{envPathMachine};{envPathUser}";
- this.SetVariable(EnvPath, newPwshPathEnv);
-
- this.Write(StreamType.Verbose, $"PATH environment variable updated");
- }
-
- private void ValidateWhenAllUsers(bool allUsers)
- {
- if (allUsers)
- {
- if (Utilities.ExecutingAsSystem)
- {
- throw new NotSupportedException();
- }
-
- if (!Utilities.ExecutingAsAdministrator)
- {
- throw new WinGetRepairException(Resources.RepairAllUsersMessage);
- }
- }
- }
- }
-}
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Engine.Commands
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Management.Automation;
+ using System.Threading.Tasks;
+ using Microsoft.WinGet.Client.Engine.Commands.Common;
+ using Microsoft.WinGet.Client.Engine.Common;
+ using Microsoft.WinGet.Client.Engine.Exceptions;
+ using Microsoft.WinGet.Client.Engine.Helpers;
+ using Microsoft.WinGet.Common.Command;
+ using Microsoft.WinGet.Resources;
+ using static Microsoft.WinGet.Client.Engine.Common.Constants;
+
+ ///
+ /// Used by Repair-WinGetPackageManager and Assert-WinGetPackageManager.
+ ///
+ public sealed class WinGetPackageManagerCommand : BaseCommand
+ {
+ private const string EnvPath = "env:PATH";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Cmdlet being executed.
+ public WinGetPackageManagerCommand(PSCmdlet psCmdlet)
+ : base(psCmdlet)
+ {
+ }
+
+ ///
+ /// Asserts winget version is the latest version on winget-cli.
+ ///
+ /// Use prerelease version on GitHub.
+ public void AssertUsingLatest(bool preRelease)
+ {
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
+ this.Assert(expectedVersion);
+ return true;
+ });
+
+ this.Wait(runningTask);
+ }
+
+ ///
+ /// Asserts the version installed is the specified.
+ ///
+ /// The expected version.
+ /// Include prerelease versions when validating the specified version.
+ public void Assert(string expectedVersion, bool preRelease = false)
+ {
+ // The preRelease parameter is for consistency but not used in this method
+ // since we're checking for an exact version match
+ WinGetIntegrity.AssertWinGet(this, expectedVersion);
+ }
+
+ ///
+ /// Repairs winget using the latest version on winget-cli.
+ ///
+ /// Use prerelease version on GitHub.
+ /// Install for all users. Requires admin.
+ /// Force application shutdown.
+ public void RepairUsingLatest(bool preRelease, bool allUsers, bool force)
+ {
+ this.ValidateWhenAllUsers(allUsers);
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ string expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(preRelease);
+ await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
+ return true;
+ });
+
+ this.Wait(runningTask);
+ }
+
+ ///
+ /// Repairs winget if needed.
+ ///
+ /// The expected version, if any.
+ /// Install for all users. Requires admin.
+ /// Force application shutdown.
+ /// Include prerelease versions when searching for the specified version.
+ public void Repair(string expectedVersion, bool allUsers, bool force, bool preRelease = false)
+ {
+ this.ValidateWhenAllUsers(allUsers);
+ var runningTask = this.RunOnMTA(
+ async () =>
+ {
+ // If no specific version is provided and IncludePrerelease is specified,
+ // we need to get the latest prerelease version
+ if (string.IsNullOrEmpty(expectedVersion) && preRelease)
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ expectedVersion = await gitHubClient.GetLatestReleaseTagNameAsync(true);
+ }
+
+ await this.RepairStateMachineAsync(expectedVersion, allUsers, force);
+ return true;
+ });
+ this.Wait(runningTask);
+ }
+
+ private async Task RepairStateMachineAsync(string expectedVersion, bool allUsers, bool force)
+ {
+ var seenCategories = new HashSet();
+ var cancellationToken = this.GetCancellationToken();
+
+ var currentCategory = IntegrityCategory.Unknown;
+ while (currentCategory != IntegrityCategory.Installed)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ try
+ {
+ WinGetIntegrity.AssertWinGet(this, expectedVersion);
+ this.Write(StreamType.Verbose, $"WinGet is in a good state.");
+ currentCategory = IntegrityCategory.Installed;
+ }
+ catch (WinGetIntegrityException e)
+ {
+ currentCategory = e.Category;
+
+ if (seenCategories.Contains(currentCategory))
+ {
+ this.Write(StreamType.Verbose, $"{currentCategory} encountered previously");
+ throw;
+ }
+
+ this.Write(StreamType.Verbose, $"Integrity category type: {currentCategory}");
+ seenCategories.Add(currentCategory);
+
+ switch (currentCategory)
+ {
+ case IntegrityCategory.UnexpectedVersion:
+ await this.InstallDifferentVersionAsync(new WinGetVersion(expectedVersion), allUsers, force);
+ break;
+ case IntegrityCategory.NotInPath:
+ this.RepairEnvPath();
+ break;
+ case IntegrityCategory.AppInstallerNotRegistered:
+ this.Register(expectedVersion);
+ break;
+ case IntegrityCategory.AppInstallerNotInstalled:
+ case IntegrityCategory.AppInstallerNotSupported:
+ case IntegrityCategory.Failure:
+ await this.InstallAsync(expectedVersion, allUsers, force);
+ break;
+ case IntegrityCategory.AppInstallerNoLicense:
+ // This requires -AllUsers in admin mode.
+ if (allUsers && Utilities.ExecutingAsAdministrator)
+ {
+ await this.InstallAsync(expectedVersion, allUsers, force);
+ }
+ else
+ {
+ throw new WinGetRepairException(e);
+ }
+
+ break;
+ case IntegrityCategory.AppExecutionAliasDisabled:
+ case IntegrityCategory.Unknown:
+ throw new WinGetRepairException(e);
+ default:
+ throw new NotSupportedException();
+ }
+ }
+ }
+ }
+
+ private async Task InstallDifferentVersionAsync(WinGetVersion toInstallVersion, bool allUsers, bool force)
+ {
+ var installedVersion = WinGetVersion.InstalledWinGetVersion(this);
+ bool isDowngrade = installedVersion.CompareAsDeployment(toInstallVersion) > 0;
+
+ string message = $"Installed WinGet version '{installedVersion.TagVersion}' " +
+ $"Installing WinGet version '{toInstallVersion.TagVersion}' " +
+ $"Is downgrade {isDowngrade}";
+ this.Write(
+ StreamType.Verbose,
+ message);
+ var appxModule = new AppxModuleHelper(this);
+ await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion.TagVersion, allUsers, isDowngrade, force);
+ }
+
+ private async Task InstallAsync(string toInstallVersion, bool allUsers, bool force)
+ {
+ // If we are here and toInstallVersion is empty, it means that they just ran Repair-WinGetPackageManager.
+ // When there is not version specified, we don't want to assume an empty version means latest, but in
+ // this particular case we need to.
+ if (string.IsNullOrEmpty(toInstallVersion))
+ {
+ var gitHubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli);
+ toInstallVersion = await gitHubClient.GetLatestReleaseTagNameAsync(false);
+ }
+
+ var appxModule = new AppxModuleHelper(this);
+ await appxModule.InstallFromGitHubReleaseAsync(toInstallVersion, allUsers, false, force);
+ }
+
+ private void Register(string toRegisterVersion)
+ {
+ var appxModule = new AppxModuleHelper(this);
+ appxModule.RegisterAppInstaller(toRegisterVersion);
+ }
+
+ private void RepairEnvPath()
+ {
+ // Add windows app path to user PATH environment variable
+ Utilities.AddWindowsAppToPath();
+
+ // Update this sessions PowerShell environment so the user doesn't have to restart the terminal.
+ string? envPathUser = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.User);
+ string? envPathMachine = Environment.GetEnvironmentVariable(Constants.PathEnvVar, EnvironmentVariableTarget.Machine);
+ string newPwshPathEnv = $"{envPathMachine};{envPathUser}";
+ this.SetVariable(EnvPath, newPwshPathEnv);
+
+ this.Write(StreamType.Verbose, $"PATH environment variable updated");
+ }
+
+ private void ValidateWhenAllUsers(bool allUsers)
+ {
+ if (allUsers)
+ {
+ if (Utilities.ExecutingAsSystem)
+ {
+ throw new NotSupportedException();
+ }
+
+ if (!Utilities.ExecutingAsAdministrator)
+ {
+ throw new WinGetRepairException(Resources.RepairAllUsersMessage);
+ }
+ }
+ }
+ }
+}