Documentation Index
Fetch the complete documentation index at: https://mintlify.com/microsoft/winget-cli/llms.txt
Use this file to discover all available pages before exploring further.
Overview
PackageCatalog represents a searchable package source. Before using a catalog, you must first obtain a PackageCatalogReference and connect to it. Once connected, you can search for packages using various filters.
Class Definitions
PackageCatalogReference
runtimeclass PackageCatalogReference
{
Boolean IsComposite { get; };
PackageCatalogInfo Info { get; };
IAsyncOperation<ConnectResult> ConnectAsync();
ConnectResult Connect();
String AdditionalPackageCatalogArguments;
IVectorView<SourceAgreement> SourceAgreements { get; };
Boolean AcceptSourceAgreements;
TimeSpan PackageCatalogBackgroundUpdateInterval;
Boolean InstalledPackageInformationOnly;
AuthenticationArguments AuthenticationArguments;
AuthenticationInfo AuthenticationInfo { get; };
IAsyncOperationWithProgress<RefreshPackageCatalogResult, Double>
RefreshPackageCatalogAsync();
}
PackageCatalog
runtimeclass PackageCatalog
{
Boolean IsComposite { get; };
PackageCatalogInfo Info { get; };
IAsyncOperation<FindPackagesResult> FindPackagesAsync(FindPackagesOptions options);
FindPackagesResult FindPackages(FindPackagesOptions options);
}
PackageCatalogInfo
runtimeclass PackageCatalogInfo
{
String Id { get; };
String Name { get; };
String Type { get; };
String Argument { get; };
DateTime LastUpdateTime { get; };
PackageCatalogOrigin Origin { get; };
PackageCatalogTrustLevel TrustLevel { get; };
Boolean Explicit { get; };
Int32 Priority { get; };
}
Connecting to a Catalog
Basic Connection
var manager = new PackageManager();
var catalogRef = manager.GetPredefinedPackageCatalog(
PredefinedPackageCatalog.OpenWindowsCatalog
);
// Connect to catalog
var connectResult = await catalogRef.ConnectAsync();
if (connectResult.Status == ConnectResultStatus.Ok)
{
var catalog = connectResult.PackageCatalog;
Console.WriteLine("Connected to catalog");
// Now you can search
}
else
{
Console.WriteLine($"Connection failed: {connectResult.Status}");
Console.WriteLine($"Error: 0x{connectResult.ExtendedErrorCode:X}");
}
Connection with Agreement Acceptance
Some catalogs require accepting source agreements:
var catalogRef = manager.GetPackageCatalogByName("customsource");
// Check for required agreements
var agreements = catalogRef.SourceAgreements;
if (agreements.Count > 0)
{
Console.WriteLine("Source requires acceptance of agreements:");
foreach (var agreement in agreements)
{
Console.WriteLine($"- {agreement.Label}");
Console.WriteLine($" {agreement.Text}");
Console.WriteLine($" URL: {agreement.Url}");
}
// Accept agreements
catalogRef.AcceptSourceAgreements = true;
}
var connectResult = await catalogRef.ConnectAsync();
Authentication
For catalogs requiring authentication:
var catalogRef = manager.GetPackageCatalogByName("privatecatalog");
// Check authentication requirements
var authInfo = catalogRef.AuthenticationInfo;
if (authInfo != null && authInfo.AuthenticationType == AuthenticationType.MicrosoftEntraId)
{
// Set up authentication
var authArgs = new AuthenticationArguments()
{
AuthenticationMode = AuthenticationMode.SilentPreferred,
AuthenticationAccount = "user@contoso.com"
};
catalogRef.AuthenticationArguments = authArgs;
}
var connectResult = await catalogRef.ConnectAsync();
Searching for Packages
FindPackagesOptions
runtimeclass FindPackagesOptions
{
FindPackagesOptions();
IVector<PackageMatchFilter> Selectors { get; };
IVector<PackageMatchFilter> Filters { get; };
UInt32 ResultLimit;
}
Search Logic:
- Selectors - You must match at least ONE selector (OR logic)
- Filters - You must match ALL filters (AND logic)
- Final result =
(Selector1 OR Selector2 OR ...) AND Filter1 AND Filter2 AND ...
PackageMatchFilter
Field
PackageMatchField
required
The field to search
Option
PackageFieldMatchOption
required
How to match the value
PackageMatchField values:
CatalogDefault - Default search across all fields
Id - Package identifier
Name - Package name
Moniker - Package moniker (short name)
Command - Executable command
Tag - Package tags
PackageFamilyName - Package family name
ProductCode - Product code
PackageFieldMatchOption values:
Equals - Case-sensitive exact match
EqualsCaseInsensitive - Case-insensitive exact match
StartsWithCaseInsensitive - Case-insensitive prefix match
ContainsCaseInsensitive - Case-insensitive substring match
Basic Search
var options = new FindPackagesOptions();
// Search by package ID
var filter = new PackageMatchFilter()
{
Field = PackageMatchField.Id,
Value = "Microsoft.PowerToys",
Option = PackageFieldMatchOption.Equals
};
options.Selectors.Add(filter);
var result = await catalog.FindPackagesAsync(options);
if (result.Status == FindPackagesResultStatus.Ok)
{
Console.WriteLine($"Found {result.Matches.Count} packages");
foreach (var match in result.Matches)
{
var package = match.CatalogPackage;
Console.WriteLine($"ID: {package.Id}");
Console.WriteLine($"Name: {package.Name}");
Console.WriteLine($"Version: {package.DefaultInstallVersion.Version}");
}
if (result.WasLimitExceeded)
{
Console.WriteLine("Results were truncated");
}
}
Search by Name (Partial Match)
var options = new FindPackagesOptions();
// Search for packages containing "visual studio"
var filter = new PackageMatchFilter()
{
Field = PackageMatchField.Name,
Value = "visual studio",
Option = PackageFieldMatchOption.ContainsCaseInsensitive
};
options.Selectors.Add(filter);
// Limit results
options.ResultLimit = 10;
var result = await catalog.FindPackagesAsync(options);
Multiple Selectors (OR Logic)
var options = new FindPackagesOptions();
// Find by ID OR moniker
options.Selectors.Add(new PackageMatchFilter()
{
Field = PackageMatchField.Id,
Value = "Microsoft.VisualStudioCode",
Option = PackageFieldMatchOption.Equals
});
options.Selectors.Add(new PackageMatchFilter()
{
Field = PackageMatchField.Moniker,
Value = "vscode",
Option = PackageFieldMatchOption.EqualsCaseInsensitive
});
// This will find packages matching EITHER selector
var result = await catalog.FindPackagesAsync(options);
Using Filters (AND Logic)
var options = new FindPackagesOptions();
// Selector: search for packages with "microsoft" in name
options.Selectors.Add(new PackageMatchFilter()
{
Field = PackageMatchField.Name,
Value = "microsoft",
Option = PackageFieldMatchOption.ContainsCaseInsensitive
});
// Filter: only packages with specific tag
options.Filters.Add(new PackageMatchFilter()
{
Field = PackageMatchField.Tag,
Value = "developer-tools",
Option = PackageFieldMatchOption.Equals
});
// This finds packages with "microsoft" in name AND tag "developer-tools"
var result = await catalog.FindPackagesAsync(options);
Search All Packages
// Empty options returns all packages (up to ResultLimit)
var options = new FindPackagesOptions()
{
ResultLimit = 100 // Limit to 100 packages
};
var result = await catalog.FindPackagesAsync(options);
Console.WriteLine($"Total packages: {result.Matches.Count}");
if (result.WasLimitExceeded)
{
Console.WriteLine("More packages available, but limited to 100");
}
Working with Results
FindPackagesResult
runtimeclass FindPackagesResult
{
FindPackagesResultStatus Status { get; };
IVectorView<MatchResult> Matches { get; };
Boolean WasLimitExceeded { get; };
HRESULT ExtendedErrorCode { get; };
}
FindPackagesResultStatus values:
Ok - Search successful
BlockedByPolicy - Blocked by group policy
CatalogError - Catalog error occurred
InternalError - Internal error
InvalidOptions - Invalid search options
AuthenticationError - Authentication failed
AccessDenied - Access denied to catalog
MatchResult
runtimeclass MatchResult
{
CatalogPackage CatalogPackage { get; };
PackageMatchFilter MatchCriteria { get; };
}
foreach (var match in findResult.Matches)
{
var package = match.CatalogPackage;
var criteria = match.MatchCriteria;
Console.WriteLine($"Package: {package.Name}");
Console.WriteLine($"Matched on: {criteria.Field} = {criteria.Value}");
// Access package details
if (package.DefaultInstallVersion != null)
{
var version = package.DefaultInstallVersion;
Console.WriteLine($"Version: {version.Version}");
Console.WriteLine($"Publisher: {version.Publisher}");
Console.WriteLine($"Display Name: {version.DisplayName}");
}
// Check if update available
if (package.IsUpdateAvailable)
{
Console.WriteLine("Update available!");
}
}
CatalogPackage
runtimeclass CatalogPackage
{
String Id { get; };
String Name { get; };
PackageVersionInfo InstalledVersion { get; };
IVectorView<PackageVersionId> AvailableVersions { get; };
PackageVersionInfo DefaultInstallVersion { get; };
PackageVersionInfo GetPackageVersionInfo(PackageVersionId versionKey);
Boolean IsUpdateAvailable { get; };
IAsyncOperation<CheckInstalledStatusResult> CheckInstalledStatusAsync(InstalledStatusType checkTypes);
CheckInstalledStatusResult CheckInstalledStatus(InstalledStatusType checkTypes);
IReference<Int32> CatalogPriority { get; };
}
var package = match.CatalogPackage;
var version = package.DefaultInstallVersion;
// Get catalog metadata (requires contract v6+)
var metadata = version.GetCatalogPackageMetadata();
Console.WriteLine($"Publisher: {metadata.Publisher}");
Console.WriteLine($"License: {metadata.License}");
Console.WriteLine($"Description: {metadata.Description}");
Console.WriteLine($"Package URL: {metadata.PackageUrl}");
Console.WriteLine($"Publisher URL: {metadata.PublisherUrl}");
// Tags
if (metadata.Tags.Count > 0)
{
Console.WriteLine("Tags: " + string.Join(", ", metadata.Tags));
}
// Icons
foreach (var icon in metadata.Icons)
{
Console.WriteLine($"Icon: {icon.Url} ({icon.Resolution}, {icon.Theme})");
}
// Agreements
foreach (var agreement in metadata.Agreements)
{
Console.WriteLine($"Agreement: {agreement.Label}");
Console.WriteLine($" {agreement.Text}");
Console.WriteLine($" URL: {agreement.Url}");
}
Getting Specific Version
var package = match.CatalogPackage;
// List all available versions
foreach (var versionId in package.AvailableVersions)
{
Console.WriteLine($"Available: {versionId.Version} (Channel: {versionId.Channel})");
}
// Get specific version
if (package.AvailableVersions.Count > 0)
{
var versionKey = package.AvailableVersions[0];
var versionInfo = package.GetPackageVersionInfo(versionKey);
Console.WriteLine($"Version: {versionInfo.Version}");
Console.WriteLine($"Display Name: {versionInfo.DisplayName}");
Console.WriteLine($"Publisher: {versionInfo.Publisher}");
}
Composite Catalogs
Composite catalogs combine multiple sources for unified searching:
var manager = new PackageManager();
var options = new CreateCompositePackageCatalogOptions();
// Add catalogs to composite
options.Catalogs.Add(
manager.GetPredefinedPackageCatalog(PredefinedPackageCatalog.OpenWindowsCatalog)
);
options.Catalogs.Add(
manager.GetLocalPackageCatalog(LocalPackageCatalog.InstalledPackages)
);
// Set search behavior
options.CompositeSearchBehavior = CompositeSearchBehavior.RemotePackagesFromAllCatalogs;
// Set installed scope filter
options.InstalledScope = PackageInstallScope.User;
var compositeCatalog = manager.CreateCompositePackageCatalog(options);
var connectResult = await compositeCatalog.ConnectAsync();
if (connectResult.Status == ConnectResultStatus.Ok)
{
// Search across all catalogs
var findOptions = new FindPackagesOptions();
var result = await connectResult.PackageCatalog.FindPackagesAsync(findOptions);
foreach (var match in result.Matches)
{
var package = match.CatalogPackage;
// Check if installed
if (package.InstalledVersion != null)
{
Console.WriteLine($"{package.Name} (Installed: {package.InstalledVersion.Version})");
if (package.IsUpdateAvailable)
{
Console.WriteLine($" Update available: {package.DefaultInstallVersion.Version}");
}
}
else
{
Console.WriteLine($"{package.Name} (Not installed)");
}
}
}
CompositeSearchBehavior values:
LocalCatalogs - Search only local catalogs
RemotePackagesFromRemoteCatalogs - Search remote catalogs without checking installed status
RemotePackagesFromAllCatalogs - Search remote catalogs and check local catalogs for installed versions
AllCatalogs - Search both local and remote catalogs
Catalog Refresh
Update a catalog to get the latest package information:
var catalogRef = manager.GetPredefinedPackageCatalog(
PredefinedPackageCatalog.OpenWindowsCatalog
);
var operation = catalogRef.RefreshPackageCatalogAsync();
operation.Progress = (op, progress) =>
{
Console.WriteLine($"Refresh progress: {progress}%");
};
var result = await operation;
if (result.Status == RefreshPackageCatalogStatus.Ok)
{
Console.WriteLine("Catalog refreshed successfully");
}
else
{
Console.WriteLine($"Refresh failed: {result.Status}");
Console.WriteLine($"Error: 0x{result.ExtendedErrorCode:X}");
}