SubZeroDev.WinGet 0.2.0

dotnet add package SubZeroDev.WinGet --version 0.2.0
                    
NuGet\Install-Package SubZeroDev.WinGet -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SubZeroDev.WinGet" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SubZeroDev.WinGet" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="SubZeroDev.WinGet" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SubZeroDev.WinGet --version 0.2.0
                    
#r "nuget: SubZeroDev.WinGet, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SubZeroDev.WinGet@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SubZeroDev.WinGet&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=SubZeroDev.WinGet&version=0.2.0
                    
Install as a Cake Tool

SubZeroDev.WinGet

Build

A C# client library for the WinGet COM API (Microsoft.Management.Deployment) — the same in-process API winget.exe itself is built on. Search, install, upgrade, uninstall, download, and repair packages; manage sources; pin packages; export/import package sets.

No console output parsing for anything the COM API can do, and no COM/WinRT types in the public surface — callers only ever see plain C# records, enums, and interfaces.

Features

Area Operations
Packages Search (all sources or one), list installed, list available upgrades, get package, get full manifest details (description, license, agreements, icons, versions)
Operations Install, upgrade, uninstall, download-only, repair — with progress reporting, cancellation, and full option control (version, scope, architecture, installer type, silent/interactive, custom arguments, install location)
Sources List, get, add, remove, refresh, edit (the winget source equivalent, via COM)
Pins List, add (including version gating and blocking), remove
Export/Import Snapshot installed packages to a winget import-compatible JSON file and restore
Resilience Elevation-aware COM activation fallback chain, unreachable-source recovery, typed WinGetUnavailableException, documented auto-retry policy for known-recoverable WinGet error codes

Pin management and export/import have no COM equivalent in WinGet (verified against the winget-cli IDL), so those two features — and only those — run winget.exe behind an isolated IWinGetCliClient interface. Everything else is pure COM.

Quick Start

using Microsoft.Extensions.DependencyInjection;
using SubZeroDev.WinGet;
using SubZeroDev.WinGet.Abstractions;
using SubZeroDev.WinGet.Models;

var services = new ServiceCollection()
    .AddLogging()
    .AddPackageManagement()
    .BuildServiceProvider();

var packages = services.GetRequiredService<IPackageManagementService>();

// Search across all configured sources (installed state included in results)
var results = await packages.Search("vscode");

// Install with options
var result = await packages.Install("Microsoft.VisualStudioCode", new InstallRequest
{
    Scope = PackageScope.User,
    Mode = PackageOperationMode.Silent
},
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})");
}

// What can be upgraded?
var upgrades = await packages.GetAvailableUpgrades();

// Sources
var sources = services.GetRequiredService<IPackageSourceService>();
var configured = await sources.GetSources();

Prefer raw, single-attempt behavior without the service layer's retry policy? Use IWinGetClient / IWinGetSourceClient / IWinGetCliClient directly — they are registered by AddPackageManagement() too.

Runnable examples

SubZeroDev.WinGet.Examples has a runnable example for every public API:

cd SubZeroDev.WinGet.Examples
dotnet run                       # lists all examples
dotnet run -- search terminal    # read-only examples run live
dotnet run -- install <id>       # mutating examples require explicit arguments

Read-only examples (search, installed, upgrades, details, sources, pins, export, version) run safely against your machine; anything that would change it (install, uninstall, pin, source add/remove, import) refuses to run without explicit arguments.

Requirements

  • Windows 10/11 with WinGet (App Installer) installed
  • .NET 8 or newer — the package targets net8.0-windows10.0.26100, so it also runs on net9/net10 apps
  • An explicit supported architecture: x64 or ARM64. The package supplies the matching native WinGet DLL and WinMD; see Architecture configuration for what each is checked against.

Architecture configuration

A package consumer needs only SubZeroDev.WinGet. Its transitive build target supplies the matching x64 or ARM64 Microsoft.Management.Deployment.dll and WinMD to build and publish output. Select the architecture explicitly with RuntimeIdentifier (win-x64 or win-arm64) or PlatformTarget/Platform (x64 or ARM64); ambiguous AnyCPU and unsupported platforms fail at build time.

Both architectures are package-contract-checked: ArchitectureTest verifies the PE shape of each executable/test host, and PackageTest verifies that the packed consumer's build/publish output selects the correct native DLL and WinMD for its RuntimeIdentifier/Platform. Windows x64 selection is additionally executed live — MachineStateTest and PackedConsumerSmokeTest run against a real packed consumer on a GitHub-hosted Windows x64 runner. ARM64 selection has the same package-contract checks but has not run on ARM64 hardware.

The library's managed assembly is IL-only AnyCPU. ArchitectureTest and PackageTest verify that shape and the packed layout for both architectures. On Windows x64, PackedConsumerSmokeTest goes further: it builds, publishes, and runs a real packed consumer against the AnyCPU assembly and observes a non-null WinGet version back, so that package shape is confirmed rather than left open. ARM64 has the same package-contract checks but no hardware execution.

If you consume the repository project through a ProjectReference instead of the packed NuGet package, retain a direct Microsoft.WindowsPackageManager.ComInterop reference on the executable project. Its build assets do not flow through ProjectReference.

Installing from GitHub Packages

Released versions are published to this repo's public GitHub Packages NuGet feed. Add it as a source (once), then install:

dotnet nuget add source https://nuget.pkg.github.com/The-Running-Dev/index.json --name github-trd
dotnet add package SubZeroDev.WinGet

GitHub requires authentication even for public-feed reads — use a personal access token with the read:packages scope as the source's password when prompted.

Building & Testing

dotnet build SubZeroDev.WinGet.sln
dotnet test  SubZeroDev.WinGet.sln                                    # mocked unit tests, no COM
./build.ps1 MachineStateTest                 # 7 local-machine live checks, read-only, needs WinGet
./build.ps1 CatalogIntegrationTest           # 6 remote-catalog live checks, read-only, needs WinGet
./build.ps1 IntegrationTest                  # all 13 live checks

The integration tests are [Explicit], read-only by design, and run against the machine's real WinGet catalog.

CI runs the same steps through a generic Nuke build (build/Build.cs) instead of hand-written dotnet CLI steps. Equivalent locally:

./build.ps1 Test Coverage ArchitectureTest PackageTest

The library, tests, and examples target .NET 8 (net8.0-windows10.0.26100). The Nuke build tooling (build/) targets .NET 10 because Nuke.Common 10.x is net10-only — it's isolated from the product and not in the solution. So building via Nuke needs both SDKs (net8 to build/run the product, net10 to run Nuke); a plain dotnet build/dotnet test needs only the .NET 8 SDK.

See docs/testing.md for the full target list.

CI: .github/workflows/build.yml runs on every push to main and every pull request. It runs Test Coverage ArchitectureTest PackageTest before release: architecture checks verify the managed/executable PE shapes, and package checks build/publish direct and two-hop consumers without live COM activation. Pull requests never publish.

Publishing happens only after the build+test job passes:

  • GitHub Packages — automatic, on two triggers. A push to main (every merged PR) publishes a distinct prerelease 0.1.0-<n>; pushing a v* tag (git push origin v0.1.0) publishes the stable 0.1.0. The version comes from GitVersion via GitVersion.yml, which derives it from git history rather than the .csproj. Auth uses the built-in GITHUB_TOKEN, so no secret setup is needed.
  • NuGet.orgoff by default; runs only on a manual workflow_dispatch with the push_to_nuget input checked, and requires a NUGET_API_KEY repository secret. Publishes the version pinned in the .csproj.

Documentation

winget.subzerodev.com — the hosted docs site (built from docs/ via Docusaurus, website/). The same content is also readable directly on GitHub under docs/; each section below links both.

Topic Site GitHub
Introduction — why this library, feature overview, the one deliberate CLI exception Read docs/intro.md
Getting Started — install, requirements, and explicit architecture configuration Read docs/getting-started.md
Managing Packages — search, install, upgrade, uninstall, download, repair, the retry policy Read docs/usage/packages.md
Managing Sources — the winget source equivalent Read docs/usage/sources.md
Pins, Export & Import — the CLI-backed features Read docs/usage/pins-export-import.md
Running the Examples — a runnable example for every public API Read docs/examples.md
Architecture — layers, retry policy, verified COM API findings Read docs/architecture.md
Building & Testing — Nuke targets, coverage, publishing Read docs/testing.md
Documentation System — the containerised docs-template image, its gate and deploy Read docs/documentation-system.md
Troubleshooting — common runtime errors and fixes Read docs/troubleshooting.md

Design Notes

The full design document — including the verified COM API findings (OR'd selectors vs AND'd filters, the CsWinRT collection enumeration bug, activation quirks in elevated hosts) and the research summarized from winget-cli, UniGetUI, and Winget-AutoUpdate — lives in SPECIFICATION.md.

Roadmap

Known gaps and planned work — correctness fixes, threading, packaging, API expansion, and new capabilities — are tracked as phases in ROADMAP.md.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0-windows10.0.26100 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 46 9/5/2026