Skip to main content

Managing Packages

All examples below use IPackageManagementService from DI (see Getting Started). Every method accepts an optional CancellationToken; in-flight installs and downloads honor cancellation.

Searching

One call searches name, id, moniker, and tag across every configured source. Installed state is already correlated into each result — no second "list installed" call needed:

var results = await packages.Search("vscode");

foreach (var p in results)
{
if (p.IsInstalled && p.IsUpdateAvailable)
Console.WriteLine($"{p.Id}: {p.InstalledVersion} -> {p.AvailableVersion}");
}

Restrict to a single source:

var wingetOnly = await packages.Search("vscode", sourceName: "winget");

Listing installed packages

var installed = await packages.GetInstalled();
Non-WinGet software

Software installed outside WinGet appears with a raw ARP registry key as its Id (e.g. ARP\Machine\X64\Some App 1.0). Those entries cannot be targeted by id for install/upgrade — check for the ARP\ prefix before offering an Update button.

Listing available upgrades

The winget upgrade equivalent:

var upgrades = await packages.GetAvailableUpgrades();

Getting one package

var package = await packages.GetPackage("Microsoft.VisualStudioCode"); // null if not found
var details = await packages.GetDetails("Microsoft.VisualStudioCode"); // full manifest metadata

GetDetails returns the full catalog manifest: description, publisher URLs, license, copyright, release notes, agreements, documentation links, icons, tags, and every available version — plus Author, PrivacyUrl, InstallationNotes, and PurchaseUrl for manifests that populate them.

Installing

using SubZeroDev.WinGet.Models;

var result = await packages.Install("Microsoft.VisualStudioCode", new InstallRequest
{
Version = null, // null => latest applicable
Scope = PackageScope.User, // Any / User / System
Mode = PackageOperationMode.Silent, // Silent / Interactive / Default
Architecture = PackageArchitecture.Default, // or X64 / Arm64 / ...
InstallerType = PackageInstallerKind.Default, // or force Msi / Msix / Zip / ...
// PreferredInstallLocation = @"C:\Tools\App",
// OverrideArguments = "/S", // REPLACES installer args (--override)
// AdditionalArguments = "/NoShortcut", // appended args (--custom)
AcceptPackageAgreements = true,
},
progress: new Progress<PackageOperationProgress>(p =>
Console.WriteLine($"[{p.State}] {p.PercentComplete:F0}%")));

if (!result.Succeeded)
{
Console.WriteLine($"{result.Status}: {result.ErrorMessage} (0x{result.ExtendedErrorCode:X8})");
}

An empty InstallRequest (or null) reproduces a plain winget install <id>.

Advanced install options

Beyond what's shown above, InstallRequest also has:

PropertyMeaning
ForceBypass WinGet's applicability checks (hash mismatch, blocking pins, etc.)
AllowHashMismatchProceed even if the installer's hash doesn't match the manifest
SkipDependenciesDon't install declared dependencies first
LogOutputPathWhere the underlying installer should write its own log

Update shares this same request type, so all of the above apply to upgrades too.

Upgrading

var result = await packages.Update("Microsoft.VisualStudioCode");

Update takes the same InstallRequest as Install.

Uninstalling

var result = await packages.Uninstall("Microsoft.VisualStudioCode",
new UninstallRequest { Mode = PackageOperationMode.Silent });

UninstallRequest also has Scope (relevant only to MSIX packages), Force, LogOutputPath, and CorrelationData.

Download-only

Fetch the installer without running it (the winget download equivalent):

var result = await packages.Download("Microsoft.VisualStudioCode",
new DownloadRequest(@"C:\Installers"));

DownloadRequest accepts the same shape as InstallRequest (Version, Architecture, InstallerType, Scope, AllowHashMismatch, SkipDependencies, AcceptPackageAgreements, CorrelationData), plus two download-specific properties:

PropertyMeaning
LocalePreferred installer locale, if the manifest offers more than one
SkipMicrosoftStoreLicenseSkip downloading the license file for Microsoft Store packages

Repairing

The winget repair equivalent — requires the package's installer technology to support repair:

var result = await packages.Repair("Microsoft.VisualStudioCode");

RepairRequest has the same options as UninstallRequest (Mode, Scope, Force, LogOutputPath, CorrelationData), plus AllowHashMismatch and AcceptPackageAgreements.

Reading operation results

Every operation returns a PackageOperationResult:

PropertyMeaning
SucceededOverall outcome
StatusNormalized status enum (Ok, DownloadError, InstallError, NoApplicableInstallers, BlockedByPolicy, …)
ErrorMessageHuman-readable failure description
ExtendedErrorCodeThe WinGet HRESULT (APPINSTALLER_CLI_ERROR_*); well-known values are exposed on WinGetErrorCodes
InstallerErrorCodeThe native installer's own exit code, when the failure came from the installer
RebootRequiredWhether a restart is needed to finish

The built-in retry policy

IPackageManagementService applies a small, documented auto-retry policy:

  • Already installed / not newer (PACKAGE_ALREADY_INSTALLED, INSTALL_ALREADY_INSTALLED, INSTALL_DOWNGRADE, UPGRADE_VERSION_NOT_NEWER) → normalized to success.
  • No applicable installer under requested constraints (architecture / installer type / scope) → retried once without the constraints.
  • Installed version unknown during upgrade → retried once with AllowUpgradeToUnknownVersion.

If you don't want any of that, use IWinGetClient directly — same operations, single attempt, no normalization.

Method names differ at the client layer

IWinGetClient isn't just IPackageManagementService without the retry policy — several methods have different names: GetInstalledGetInstalledPackages, GetDetailsGetPackageDetails, UpdateUpgrade. Its Search also takes a required int limit where the service picks a default. See Architecture for the full layer breakdown.