1. MSIX Package Management

January 26, 2026 ยท View on GitHub

This feature provides package management APIs comparable to those in namespace Windows.Management.Deployment but with additional functionality, improved developer experience and performance optimizations.

2. Background

Windows supports the ability to deploy and manage software as MSIX packages via WinRT APIs in the Windows.Management.Deployment namespace. These APIs provide the means to install, update, uninstall, enumerate and otherwise manage packages.

The package management APIs were originally introduced in Windows 8 and have continuously expanded to meet MSIX's growing demands over the past decade. However, as one of the earliest WinRT APIs they include some patterns out of step with current API practices and recommendations. Windows App SDK offers the opportunity to provide a new generation of package management APIs in line with the latest patterns and recommendations for an improved developer experience as well as functional enhancements and improved runtime efficiencies.

Microsoft-internal task 45952398

3. Description

This API provides enhanced access to Windows' package management capabilities, focusing on the following scenarios:

  • Stage a package
  • Register a package
  • Add/Update a package
  • Remove a package
  • Repair a package
  • Reset a package
  • Provision a package
  • Deprovision a package

Additional functionality includes:

  • IsReady* -- Is a package ready for use?
  • EnsureReady -- Is a package ready for use and, if not, make it so
  • IsPackageRegistrationPending -- Is there an update waiting to register?
  • PackageSets -- Batch operations
  • PackageRuntimeManager -- Batch operations for use at runtime via Dynamic Dependencies
  • Package validation -- Validate a package has expected identity, signature, etc. before adding/staging
  • Usability -- Quality-of-Life enhancements

3.1. API Structure

Methods to drive deployment activity typically follow the pattern:

<verb>Package[Set][By<Type>][Suffix]Async(target, options)

The following verbs are supported:

  • Is...Ready[OrNewerAvailable]
  • Ensure...Ready
  • Add
  • Stage
  • Register
  • Remove
  • Repair
  • Reset
  • Provision
  • Deprovision

These methods accept their target package(s) as their first parameter. This parameter can be an various types of information including:

  • Filename
  • Path
  • PackageFamilyName
  • PackageFullName
  • Uri

NOTE: Methods with a target of a URI are named ...ByUri....

NOTE: Methods with a target of a PackageFamilyName are named ...ByPackageFamilyName....

NOTE: Methods with a target of a PackageFullName are named ...ByPackageFullName....

NOTE: Methods with no ...By... qualifier accept a string which can contain one or more types of identifiers. These can vary for different verbs. See the per-method documentation for the specific target types supported by each method.

These methods accept options as a matching <verb>Package[Set]Options type, e.g. AddPackageAsync(string packageUri, AddPackageOptions options).

The following table shows the supported permutations of verbs and targets:

VerbPathFilenamePackageFamilyNamePackageFullNamefile:http(s):ms-uup:PackageSet
IsReadyXXOS/WASWASXXWASWAS
IsReadyOrNewerAvailableXXOS/WASWASXXWASWAS
EnsureReadyXXXXXXWASWAS
AddOS/WASXXXOS/WASOS/WASOS/WASWAS
StageOS/WASXXXOS/WASOS/WASOS/WASWAS
RegisterWASOS/WASOS/WASOS/WASOS/WASXOS/WASWAS
RemoveXXWASOS/WASXXOS/WASWAS
RepairXXWASWASXXWASWAS
ResetXXWASWASXXWASWAS
IsProvisionedXXOS/WASXXXWASWAS
ProvisionXXOS/WASXXXWASWAS
DeprovisionXXOS/WASXXXWASWAS

Legend:

  • OS = Supported by Windows (OS) APIs in the Windows.Management.Deployment.PackageManager namespace.
  • WAS = Supported by Windows App SDK APIs in the Microsoft.Windows.Management.Deployment.PackageDeploymentManager namespace.
  • X = Not supported

3.2. Is*Ready()

Is*Ready() methods determine if the target is installed (registered) and ready for use. Reasons why a package is not ready can include:

  • The package is not present on the machine
  • The package is present on the machine but not registered for the user
  • The package is registered for the user but is not in a healthy status e.g. its Package.Status=Tampered

Is*Ready() methods are a quick test to determine if more (costly) work is needed before the target can be used.

3.3. Is*ReadyOrNewerAvailable()

Is*ReadyOrNewerAvailable() methods determine if the target is installed (registered) and ready for use AND if a newer version is locally available. Reasons why a package is ready but a newer version is available can include:

  • The package is registered for the user but a newer version is available locally on the machine e.g. a user has package v1 registered and Windows Update downloaded and staged v2 in the background while app(s) are running using v1.

Is*ReadyOrNewerAvailable() methods are a quick test to determine if more (costly) work is needed before the target can be used.

NOTE: Is*ReadyOrNewerAvailable() can only determine a newer package is available than a package installed (registered) and ready for use. If Is*Ready() returns false then Is*ReadyOrNewerAvailable() will never return NewerAvailable.

NOTE: Is*ReadyOrNewerAvailable() does not require admin privilege. PackageManager.FindPackages() and PackageManager.FindPackagesForUser(user!=currentuser...) can enumerate packages regardless if staged or registered for the user but requires admin privilege.

3.4. Ensure*Ready()

Ensure*Ready() methods determine if the target is installed and ready for use and, if not, makes it so. This can include downloading the target, registering it for the user and remediating a package in an unhealthy state.

Thus EnsurePackageReady(pkg, options) is functionally equivalent to

var pdm = PackageDeploymentManager().GetDefault();
if (!pdm.IsPackageReady(pkg))
{
    var result = await pdm.AddPackageAsync(pkg, options);
}

3.4.1. Why Is*Ready() Given Ensure*Ready()?

Ensure*Ready() performs an 'is ready' check and returns if all is ready. There's no efficiency reasons to call Is*Ready() before Ensure*Ready() (in fact, it's less efficient as Is*Ready() would occur twice).

However, this can be useful if you need additional work before potentially performing deployment operations. For example, if you need to prompt the user for consent before installing the target e.g.

var pdm = PackageDeploymentManager().GetDefault();
if (!pdm.IsPackageReady(pkg))
{
    bool ok = AskUserForConsent(pkg);
    if (ok)
    {
        var options = new EnsureReadyOptions();
        var result = await pdm.EnsurePackageReadyAsync(pkg, options);
    }
}

3.4.2. EnsureReadyOptions.RegisterNewerIfAvailable

Ensure*Ready() performs an 'is ready' check via Is*ReadyOrNewerAvailable() if EnsureReadyOptions.RegisterNewerIfAvailable = true.

There's no efficiency reasons to call Is*ReadyOrNewerAvailable() before Ensure*Ready(...options.RegisterNewerIfAvailable=true) (in fact, it's less efficient as Is*ReadyOrNewerAvailable() would occur twice).

However, this can be useful if you need additional work before potentially performing deployment operations. For example, if you need to prompt the user for consent before registering ('installing') or updating the package e.g.

var pdm = PackageDeploymentManager().GetDefault();
var status = pdm.IsPackageReadyOrNewerAvailable(pkg);
if (status != PackageReadyOrNewerAvailableStatus.Ready)
{
    bool ok = AskUserForConsent(pkg, status);
    if (ok)
    {
        var options = new EnsureReadyOptions();
        options.RegisterNewerIfAvailable = true;
        var result = await pdm.EnsurePackageReadyAsync(pkg, options);
    }
}

3.5. Repair

PackageDeploymentManager offers Repair APIs providing the same functionality as available interactively via Settings' Repair button on the detail page for an app (via Apps > Installed Apps > ... menu's Advanced options).

3.6. Reset

PackageDeploymentManager offers Reset APIs providing the same functionality as available interactively via Settings' Reset button on the detail page for an app (via Apps > Installed Apps > ... menu's Advanced options).

3.7. IsPackageRegistrationPending

IsPackageRegistrationPending() detects if package registration is pending for the specified target. For example, if a package is in use and AddPackageByUriAsync() is called with a newer version and the option DeferRegistrationWhenPackagesAreInUse=true then the registration is delayed until the package is no longer in use and can be updated. In such cases IsPackageRegistrationPending() returns true.

3.8. PackageSet

A PackageSet is a group of packages to be operated on with one request. Package sets provide a convenient means to perform multiple operations.

NOTE: There is no ordering guarantee of items processed in a PackageSet.

For example, IsPackageSetReady(ps) returns true only if all packages referenced by the PackageSet are ready for use. For another example, AddPackageSetAsync(ps, options) is functionally equivalent to

var pdm = PackageDeploymentManager().GetDefault();
foreach (PackageSetItem psi in ps.Items)
{
    var result = await pdm.AddPackageAsync(psi.PackageUri, options)
    if (result.Status != PackageDeploymentStatus.CompletedSuccess)
    {
        return result;
    }
}
return new PackageDeploymentResult(PackageDeploymentStatus.CompletedSuccess);

3.8.1. PackageSet Properties

Id is optional. This is used primarily for logging and troubleshooting.

Items is required to contain 1+ item.

PackageUri is optional. This is used if a PackageUri is needed for a PackageSetItem but the PackageSetItem.PackageUri is not specified.

3.8.2. PackageSetItem Properties

Id is required and used primarily for logging and troubleshooting.

MinVersion is optional. If not set the default value is 0.0.0.0. Some verbs use this property (see below).

PackageFamilyName is optional. Some verbs require this property (see below).

PackageUri is optional. If a PackageUri is needed and this is not set the PackageSet's PackageUri property is used. Some verbs require this property (see below).

ProcessorArchitectureFilter is optional. If not set the default value is Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyProcessorArchitectures.None. Only some verbs use this property (see below).

VerbMinVersionPackageFamilyNamePackageUriProcessorArchitectureFilter
IsReadyUsedRequiredN/AOptional
IsReadyOrNewerAvailableUsedRequiredN/AOptional
EnsureReadyUsedRequiredUsedOptional
AddN/AN/AUsedN/A
StageN/AN/AUsedN/A
RegisterN/AUsed-if-no-PackageUriOptionalN/A
RemoveN/AUsed-if-no-PackageUriOptionalN/A
RepairN/AUsed-if-no-PackageUriOptionalN/A
ResetN/AUsed-if-no-PackageUriOptionalN/A
IsProvisionedN/AUsedOptionalN/A
ProvisionN/AUsed-if-no-PackageUriOptionalN/A
DeprovisionN/AUsed-if-no-PackageUriOptionalN/A

Legend:

  • N/A = Not applicable. This property is not used.
  • Optional = This property is used, if specified.
  • Required = This property is required.
  • Used = This property is used; if not specified, the default value is used.

3.9. PackageRuntimeManager

The PackageRuntimeManager API provides Dynamic Dependency support for PackageSet operations, especially when the caller may not know the exact package(s) involved (for instance, when targeting packages via ms-uup:). PackageRuntimeManager determines the packages involved for a PackageSet and dynamically adds them to the caller's package graph.

3.10. PackageVolume Repair

Packages are typically1 installed to a PackageVolume, For example, C:\Program Files\WindowsApps is the default PackageVolume on a new Windows system.

Windows pairs a PackageVolume with the underlying storage volume's media ID to identify the PackageVolume even when mount points change. For example, insert USB flash key and it's mount point is E:, then remove the USB flash key and later reinsert it but now it's mounted as K:. The PackageVolume is recognized at K: now because it volume K: has the media ID associated with the PackageVolume.

It's possible this tracking information can be invalidated, e.g. backup a drive's content, replace the drive with a new one and then restore the content. The packages installed on this drive's PackageVolume(s) aren't recognized by Windows because the new drive has a different media ID.

The Windows App SDK's new PackageVolume.Repair() will attempt to detect these and other like conditions and correct them.

PackageVolume.IsRepairNeeded() checks if the PackageVolume is OK or in need of repair.

NOTE: Repair() requires admin privilege (IsRepairNeeded() doesn't).

1 RegisterPackageOptions.DevelopmentMode, AddPackageOptions.StageInPlace and other options canalter the typical behavior and install packages to a non-PackageVolume location.

3.11. Usability

The package management API in Windows App SDK provides several quality-of-life enhancements over the package management APIs in Windows (e.g. Windows.Management.Deployment.PackageManager) including:

  • PackageManager.AddPackageByUriAsync(p) fails returning ERROR_INSTALL_PACKAGE_DOWNGRADE if a newer version of the package is already installed. PackageDeploymentManager succeeds as it treats the request as "install this package or higher version", as dependencies and other package references are routinely handled.
  • PackageManager.AddPackageByUriAsync(p) fails returning ERROR_PACKAGE_ALREADY_EXISTS if that exact version of the package is already installed. PackageDeploymentManager succeeds as the requested package is installed.
  • Many PackageManager operations accept a target package as a file but require it expressed as a Uri. PackageDeploymentManager provides overrides also accepting it as a String.
  • PackageManager.RemovePackageByFullNameAsync(p) fails if the specified package isn't found. PackageDeploymentManager succeeds as the requested package is not present at the end of the operation.
    • This follows the core deployment principle "'Tis not the journey that matters but the destination". In short, it doesn't matter the current state of the system, only the desired end state is achieved.
  • PackageManager methods accept inconsistent (and often inconvenient) permutations of expressing a target package. For example, PackageManager supports removing a package by PackageFullName but not PackageFamilyName. PackageDeploymentManager provides a richer API accepting additional identifiers.

3.12. Is*Provisioned()

Is*Provisioned*() methods determine if the target is provisioned.

These methods require administrative privileges.

3.13. Package Validation

This API allows callers to verify that packages being processed by Add*, Ensure*, and Stage* APIs of PackageDeploymentManager match what are expected from their URI.

When adding or staging a package from an external source such as HTTP URI or uncontrolled file location, a malicious actor might perform a man-in-the-middle attack to intercept and tamper with the package data being read, causing a malicious package to be installed instead of the expected one. The package might also be tampered at the source through supply-chain attacks. Verifying the identity and signature of target packages helps ensure that such attacks have not happened.

The following package validators are available for use directly through their runtimeclasses:

  • PackageFamilyNameValidator: Validates that the package has the expected package family name.
  • PackageMinimumVersionValidator: Validates that the package has at least the expected minimum version number.
  • PackageCertificateEkuValidator: Validates that the certificate used to sign the package contains the expected Extended Key Usage (EKU) value.

Package validators can be customized to verify any part of packages' footprint data (manifest, block map, and digital signature). Custom package validators can be implemented as handlers for the PackageValidationEventSource.ValidationRequested event. The PackageValidationHandler runtimeclass provides a standard implementation of such a handler, and accepts any implementation class derived from the IPackageValidator interface.

4. Examples

4.1. AddPackageAsync()

Fabrikam app installing Contoso's Muffin package from a .msix file.

void Install()
{
    var package = "d:\\contoso\\muffin.msix";
    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new AddPackageOptions();
    var deploymentResult = await packageDeploymentManager.AddPackageAsync(package, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

4.2. AddPackageByUriAsync()

Fabrikam app installing Contoso's Muffin package from an https: source.

void Install()
{
    var package = new Uri("https://contoso.com/muffin.msix");
    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new AddPackageOptions();
    var deploymentResult = await packageDeploymentManager.AddPackageByUriAsync(package, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

NOTE: This differs from the AddPackageAsync() example by the method name (AddPackageByUriAsync() instead of AddPackageAsync()) and the target type (https: source as URI instead of filename as string).

4.3. AddPackageSetAsync()

Fabrikam app installing Contoso's Muffin and Waffle packages via a PackageSet.

void Install()
{
    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageUri = new Uri("c:\\contoso\\muffin-1.2.3.4.msix") },
                { new PackageSetItem() { PackageUri = new Uri("https://contoso.com/waffle-2.4.6.8.msix") } };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new AddPackageOptions();
    var deploymentResult = await packageDeploymentManager.AddPackageByUriAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

NOTE: This differs from the AddPackageByUriAsync() example by the method name (AddPackageSetAsync instead of AddPackageByUriAsync()), the target type (PackageSet containing 2 URIs instead of a URI), and installing 2 packages instead of 1.

4.4. EnsurePackageSetReadyAsync()

Fabrikam app installing Contoso's Muffin and Waffle packages if necessary via a PackageSet.

void Install()
{
    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageFamilyName = "contoso.muffin_1234567890abc",
                                         MinVersion = ToVersion(1, 2, 3, 4),
                                         PackageUri = new Uri("c:\\contoso\\muffin-1.2.3.4.msix") },
                { new PackageSetItem() { PackageFamilyName = "contoso.waffle_1234567890abc",
                                         MinVersion = ToVersion(2, 4, 6, 8),
                                         PackageUri = new Uri("https://contoso.com/waffle-2.4.6.8.msix") } };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new EnsureReadyOptions();
    var deploymentResult = await packageDeploymentManager.EnsurePackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) =>
    new PackageVersion {
        Major = checked((ushort)major),
        Minor = checked((ushort)minor),
        Build = checked((ushort)build),
        Revision = checked((ushort)revision)
    };

NOTE: This differs from the AddPackageBySetAsync() example by the method name (EnsurePackageSetReadyAsync() instead of AddPackageSetAsync), the addition of PackageFamilyName and MinVersion for each item in the PackageSet and the packages will only be installed if necessary.

4.5. IsPackageSetReady() and EnsurePackageSetReadyAsync()

Fabrikam app installing Contoso's Muffin and Waffle packages if necessary, and with explicit user confirmation before the installation.

void Install()
{
    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageFamilyName = "contoso.muffin_1234567890abc",
                                         MinVersion = ToVersion(1, 2, 3, 4),
                                         PackageUri = new Uri("c:\\contoso\\muffin-1.2.3.4.msix") },
                { new PackageSetItem() { PackageFamilyName = "contoso.waffle_1234567890abc",
                                         MinVersion = ToVersion(2, 4, 6, 8),
                                         PackageUri = new Uri("https://contoso.com/waffle-2.4.6.8.msix") } };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    if (!packageDeploymentManager.IsPackageSetReady(packageSet))
    {
        bool ok = PromptUserForConfirmation();
        if (!ok)
        {
            return;
        }
    }

    var options = new EnsureReadyOptions();
    var deploymentResult = await packageDeploymentManager.EnsurePackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) =>
    new PackageVersion {
        Major = checked((ushort)major),
        Minor = checked((ushort)minor),
        Build = checked((ushort)build),
        Revision = checked((ushort)revision)
    };

NOTE: This differs from the EnsurePackageSetReadyAsync() example checking if EnsurePackageSetReadyAsync() will need to do any work and prompting the user to confirm it's OK to proceed.

4.6. PackageRuntimeManager.AddPackageSet()

Fabrikam app uses Contoso's Muffin and Waffle packages via Dynamic Dependencies, installing them if necessary. These packages are added to the package graph and not explicitly removed (they stay in the package graph until process termination).

void AddMuffinsAndWafflesToThePackageGraph()
{
    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageFamilyName = "contoso.muffin_1234567890abc",
                                         MinVersion = ToVersion(1, 2, 3, 4),
                                         PackageUri = new Uri("c:\\contoso\\muffin-1.2.3.4.msix") },
                { new PackageSetItem() { PackageFamilyName = "contoso.waffle_1234567890abc",
                                         MinVersion = ToVersion(2, 4, 6, 8),
                                         PackageUri = new Uri("https://contoso.com/waffle-2.4.6.8.msix") } };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new EnsureReadyOptions();
    var deploymentResult = await packageDeploymentManager.EnsurePackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }

    var packageRuntimeManager = PackageRuntimeManager.GetDefault();
    var packageSetRuntimeDisposition = packageRuntimeManager.AddPackageSet(packageSet);
}

PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) =>
    new PackageVersion {
        Major = checked((ushort)major),
        Minor = checked((ushort)minor),
        Build = checked((ushort)build),
        Revision = checked((ushort)revision)
    };

NOTE: This differs from the EnsurePackageSetReadyAsync() example adding the packages referenced by the PackageSet to the process' package graph for subsequent access of the content.

4.7. PackageRuntimeManager.RemovePackageset()

Fabrikam app uses Contoso's Muffin and Waffle packages via Dynamic Dependencies, installing them if necessary. These packages are added to the package graph and later removed when no longer needed.

void DoAwesomeStuffUsingMuffinsAndWaffles()
{
    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageFamilyName = "contoso.muffin_1234567890abc",
                                         MinVersion = ToVersion(1, 2, 3, 4),
                                         PackageUri = new Uri("c:\\contoso\\muffin-1.2.3.4.msix") },
                { new PackageSetItem() { PackageFamilyName = "contoso.waffle_1234567890abc",
                                         MinVersion = ToVersion(2, 4, 6, 8),
                                         PackageUri = new Uri("https://contoso.com/waffle-2.4.6.8.msix") } };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    var options = new EnsureReadyOptions();
    var deploymentResult = await packageDeploymentManager.EnsurePackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("OK");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }

    var packageRuntimeManager = PackageRuntimeManager.GetDefault();
    var packageSetRuntimeDisposition = packageRuntimeManager.AddPackageSet(packageSet);
    DoAwesomeStuff();
    packageRuntimeManager.RemovePackageSet(packageSetRuntimeDisposition);
}

PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) =>
    new PackageVersion {
        Major = checked((ushort)major),
        Minor = checked((ushort)minor),
        Build = checked((ushort)build),
        Revision = checked((ushort)revision)
    };

NOTE: This differs from the PackageRuntimeManager.AddPackageSet()() example by explicitly removing the packages dynamically added to the package graph when no longer needed.

4.8. PackageVolume.Repair()

Fabrikam app checks if a PackageVolume is OK and if not, prompts the user to confirm it should proceed to repair the PackageVolume.

void CheckAndFixPackageVolume(string packageStorePath)
{
    var packageVolume = PackageVolume.FindPackageVolumeByPath(packageStorePath);
    if (packageVolume.IsRepairNeeded())
    {
        bool ok = PromptUserForConfirmation();
        if (!ok)
        {
            return;
        }
    }
    packageVolume.Repair();
}

4.9. IsPackageProvisioned()

Fabrikam app installing Contoso's Muffin and Waffle packages for all users if necessary, and with explicit user confirmation before the installation.

void Install()
{
    // We want to check what's provisioned by PackageFamilyName. If something's
    // not provisioned we'll also need MinVersion and PackageUri to Stage and
    // Provision. But checking if a family is provisioned only supports some
    // URI schemes (notably, not the one we need for our staging work). So we'll
    // define the PackageSet with the families we want checked and if something's
    // not provisioned we'll add the additional properties needed.

    var packageSet = new PackageSet() {
        Items = { new PackageSetItem() { PackageFamilyName = "contoso.muffin_1234567890abc" },
                { new PackageSetItem() { PackageFamilyName = "contoso.waffle_1234567890abc" }
        }
    };

    var packageDeploymentManager = PackageDeploymentManager.GetDefault();
    if (packageDeploymentManager.IsPackageSetProvisioned(packageSet))
    {
        return;
    }

    bool ok = PromptUserForConfirmation();
    if (!ok)
    {
        return;
    }

    packageSet.Items()[0].MinVersion(ToVersion(1, 2, 3, 4));
    packageSet.Items()[0].PackageUri(new Uri("c:\\contoso\\muffin-1.2.3.4.msix"));
    packageSet.Items()[1].MinVersion(ToVersion(2, 4, 6, 8));
    packageSet.Items()[1].PackageUri(new Uri("https://contoso.com/waffle-2.4.6.8.msix"));

    var stageOptions = new StagePackageOptions();
    var deploymentResult = await packageDeploymentManager.StagePackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("Staged");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
        return;
    }

    var options = new ProvisionPackageOptions();
    var deploymentResult = await packageDeploymentManager.ProvisionPackageSetReadyAsync(packageSet, options);
    if (deplymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("Provisioned");
    }
    else
    {
        Console.WriteLine("Error:{} ExtendedError:{} {}",
            deploymentResult.Error.HResult, deploymentResult.ExtendedError.HResult, deploymentResult.ErrorText);
    }
}

PackageVersion ToVersion(uint major, uint minor, uint build, uint revision) =>
    new PackageVersion {
        Major = checked((ushort)major),
        Minor = checked((ushort)minor),
        Build = checked((ushort)build),
        Revision = checked((ushort)revision)
    };

4.9. Package Validation

4.9.1. Using built-in package validators

This example shows how to use built-in package validators to verify package family name, minimum version, and certificate EKU.

using Microsoft.Windows.Management.Deployment;

var pdm = PackageDeploymentManager().GetDefault();
var packageUri = new Uri("https://contoso.com/package.msix");

var options = new AddPackageOptions();
var validators = options.GetValidationEventSourceForUri(packageUri).ValidationRequested;
validators += new PackageValidationHandler(new PackageFamilyNameValidator("ExpectedFamilyName_1234567890abc")).Handler;
validators += new PackageValidationHandler(new PackageMinimumVersionValidator(new Windows.ApplicationModel.PackageVersion(2, 0, 0, 0))).Handler;
validators += new PackageValidationHandler(new PackageCertificateEkuValidator("1.3.6.1.4.1.311.2.1.11")).Handler;

var deploymentResult = await pdm.AddPackageAsync(packageUri, options);
if (deploymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
{
    Console.WriteLine("Success");
}
else // deploymentResult.Status == PackageDeploymentStatus.CompletedFailure
{
    var error = deploymentResult.Error.HResult;
    if (error = 0x80080219 /*APPX_E_DIGEST_MISMATCH*/)
    {
        Console.WriteLine("The package retrieved from the specified URI doesn't have the expected family name, version, or certificate EKU");
    }
    else
    {
        var extendedError = deploymentResult.ExtendedError.HResult;
        var message = deploymentResult.MessageText;
        Console.WriteLine($"An error occurred while adding the package. Error 0x{error:X08} ExtendedError 0x{extendedError:X08} {message}");
    }
}

4.9.2. Using IPackageValidator to implement custom package validator

This example shows how to implement and use a custom package validator derived from the IPackageValidator interface to validate a .msix package.

using Microsoft.Windows.Management.Deployment;

// Consuming COM APIs for IAppxPackageReader, IAppxManifestReader, etc. requires C# interop definitions.
// Assume standard interop definitions exist for relevant APIs in AppxPackaging.h.
[Guid("b5c49650-99bc-481c-9a34-3d53a4106708"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppxPackageReader { ... }

// Implementation of the custom package validator
// This example validates that the package has no capabilities declared in its manifest.
class PackageCapabilitiesValidator : IPackageValidator
{
    public bool IsPackageValid(object package)
    {
        var packageReader = package as IAppxPackageReader;
        if (packageReader == null)
        {
            // object is not a .msix package as expected (i.e. it is a bundle), reject it
            return false;
        }

        var manifestReader = packageReader.GetManifest() as IAppxManifestReader3;
        var capabilitiesEnumerator = manifestReader.GetCapabilitiesByCapabilityClass(APPX_CAPABILITY_CLASS_ALL);
        bool hasCapabilities = capabilitiesEnumerator.GetHasCurrent();
        return !hasCapabilities;
    }
}

// Code that utilizes the custom package validator
void InstallPackageWithCustomValidation()
{
    var pdm = PackageDeploymentManager().GetDefault();
    var packageUri = new Uri("https://contoso.com/package.msix");

    var options = new AddPackageOptions();
    options.GetValidationEventSourceForUri(packageUri).ValidationRequested += new PackageValidationHandler(new PackageCapabilitiesValidator()).Handler;

    var deploymentResult = await pdm.AddPackageAsync(packageUri, options);
    if (deploymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("Success");
    }
    else // deploymentResult.Status == PackageDeploymentStatus.CompletedFailure
    {
        var error = deploymentResult.Error.HResult;
        if (error = 0x80080219 /*APPX_E_DIGEST_MISMATCH*/)
        {
            Console.WriteLine("The package retrieved from the specified URI did not pass validation for capabilities");
        }
        else
        {
            var extendedError = deploymentResult.ExtendedError.HResult;
            var message = deploymentResult.MessageText;
            Console.WriteLine($"An error occurred while adding the package. Error 0x{error:X08} ExtendedError 0x{extendedError:X08} {message}");
        }
    }
}

4.9.3. Using custom package validator as event handler

This example shows how to implement and use a custom package validator as an event handler for the PackageValidationEventSource.ValidationRequested event to validate a .msix package.

using Microsoft.Windows.Management.Deployment;

// Consuming COM APIs for IAppxPackageReader, IAppxManifestReader, etc. requires C# interop definitions.
// Assume standard interop definitions exist for relevant APIs in AppxPackaging.h.
[Guid("b5c49650-99bc-481c-9a34-3d53a4106708"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppxPackageReader { ... }

// Implementation of the custom package validator
// This example validates that the package has no capabilities declared in its manifest.
void MyPackageValidationHandler(object sender, PackageValidationEventArgs args)
{
    var deferral = args.GetDeferral();

    bool isValid = false;
    try
    {
        var packageReader = args.Package as IAppxPackageReader;
        if (packageReader == null)
        {
            // object is not a .msix package as expected (i.e. it is a bundle), reject it
            return false;
        }

        var manifestReader = packageReader.GetManifest() as IAppxManifestReader3;
        var capabilitiesEnumerator = manifestReader.GetCapabilitiesByCapabilityClass(APPX_CAPABILITY_CLASS_ALL);
        bool hasCapabilities = capabilitiesEnumerator.GetHasCurrent();
        isValid = !hasCapabilities;
    }
    finally
    {
        if (isValid)
        {
            Log("Package at URI is valid: " + args.PackageUri);
        }
        else
        {
            Log("Package at URI is not valid: " + args.PackageUri);
            args.Cancel = true;
        }

        deferral.Complete();
    }
}

// Code that utilizes the custom package validator
void InstallPackageWithCustomValidation()
{
    var pdm = PackageDeploymentManager().GetDefault();
    var packageUri = new Uri("https://contoso.com/package.msix");

    var options = new AddPackageOptions();
    options.GetValidationEventSourceForUri(packageUri).ValidationRequested += MyPackageValidationHandler;

    var deploymentResult = await pdm.AddPackageAsync(packageUri, options);
    if (deploymentResult.Status == PackageDeploymentStatus.CompletedSuccess)
    {
        Console.WriteLine("Success");
    }
    else // deploymentResult.Status == PackageDeploymentStatus.CompletedFailure
    {
        var error = deploymentResult.Error.HResult;
        if (error = 0x80080219 /*APPX_E_DIGEST_MISMATCH*/)
        {
            Console.WriteLine("The package retrieved from the specified URI did not pass validation for capabilities");
        }
        else
        {
            var extendedError = deploymentResult.ExtendedError.HResult;
            var message = deploymentResult.MessageText;
            Console.WriteLine($"An error occurred while adding the package. Error 0x{error:X08} ExtendedError 0x{extendedError:X08} {message}");
        }
    }
}

5. Remarks

5.1. Platform Support

This API is only available on Windows >= 10.0.19041.0 (aka 2004 aka 20H1).

A subset of functionality is available on newer releases, e.g. AddPackageOptions.ExpectedDigests requires Windows >= 10.0.22621.0 (aka Win11 22H2). Any functionality requiring newer releases of windows than then 20H1 baseline has affordances to detect at runtime if the current platform supports the feature e.g.

var options = new AddPackageOptions();
if (options.IsLimitToExistingPackagesSupported)
{
    options.LimitToExistingPackages = true;
}

6. API Details

namespace Microsoft.Windows.Management.Deployment
{
    [contractversion(3)]
    apicontract PackageDeploymentContract{};

    /// Represents a package storage volume.
    /// @note A volume 'name' is the volume's media ID (you can treat 'Volume Name' == 'Volume Media ID').
    /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume
    /// @see https://learn.microsoft.com/windows/win32/properties/props-system-volumeid
    /// @see https://learn.microsoft.com/sysinternals/downloads/volumeid
    /// @see https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-getvolumenameforvolumemountpointw
    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageVolume
    {
        /// Gets all the known volumes, regardless of their current state.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolumes
        static IVector<PackageVolume> FindPackageVolumes();

        /// Get the specified volume.
        /// @param packageStorePath a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\"
        ///                         and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid.
        /// @note The packageStorePath parameter is used to identify the device Volume.
        ///       The actual path for packages in a PackageVolume is defined by Windows.
        /// @return the volume or null if not found.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume
        /// @see GetPackageVolumeByPath()
        ///
        /// @note This API is deprecated and will be removed in a future release.
        ///       Use GetPackageVolumeByPath().
        static PackageVolume FindPackageVolumeByPath(String packageStorePath);

        /// Get the specified volume.
        /// @param path a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\"
        ///             and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid.
        /// @note The path parameter is used to identify the device Volume.
        ///       The actual path for packages in a PackageVolume is defined by Windows.
        /// @return the volume or null if not found.
        /// @see GetPackageVolumeByName()
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume
        [contract(PackageDeploymentContract, 3)]
        static PackageVolume GetPackageVolumeByPath(String path);

        /// Get the specified volume.
        /// @name The volume media ID (a GUID value)
        /// @see GetPackageVolumeByName()
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume
        ///
        /// @note This API is deprecated and will be removed in a future release.
        ///       Use GetPackageVolumeByName().
        static PackageVolume FindPackageVolumeByName(String name);

        /// Get the specified volume.
        /// @name The volume media ID (a GUID value)
        /// @see GetPackageVolumeByPath()
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume
        [contract(PackageDeploymentContract, 3)]
        static PackageVolume GetPackageVolumeByName(String name);

        /// Return true if the package volume is an internal system volume mapped to the %SYSTEMDRIVER% environment variable.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.issystemvolume
        Boolean IsSystemVolume{ get; };

        /// Get the path of the last known mount point for the package volume.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.mountpoint
        String MountPoint{ get; };

        /// Get the media ID of the package volume.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.name
        String Name{ get; };

        /// Get the absolute path for the Package store on the volume.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.packagestorepath
        String PackageStorePath{ get; };

        /// Return true if the package volume supports the creation of hard links in its file system.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.supportshardlinks
        Boolean SupportsHardLinks{ get; };

        /// Return true if APPX installing is supported.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported
        Boolean IsAppxInstallSupported{ get; };

        /// Return true if full-trust packages are supported.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isfulltrustpackagesupported
        Boolean IsFullTrustPackageSupported{ get; };

        /// Return true if the package volume is in an offline state.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isoffline
        [contract(PackageDeploymentContract, 3)]
        Boolean IsOffline();

        /// Return true if the package volume is damaged and needs to be repaired.
        Boolean IsRepairNeeded();

        /// Repair the package volume (if necessary).
        void Repair();

        [contract(PackageDeploymentContract, 3)]
        static Boolean IsFeatureSupported(PackageVolumeFeature feature);

        /// Return the default package volume.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.getdefaultpackagevolume
        [contract(PackageDeploymentContract, 3)]
        static PackageVolume GetDefault();

        /// Set the default package volume.
        /// @see //learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setdefaultpackagevolume
        [contract(PackageDeploymentContract, 3)]
        void SetDefault();

        /// Create a new package volume.
        /// @param packageStorePath The absolute path of the Package store.
        /// @note This requires admin privilege.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.addpackagevolumeasync
        [contract(PackageDeploymentContract, 3)]
        static Windows.Foundation.IAsyncOperation<PackageVolume> AddAsync(String packageStorePath);

        /// @note The caller must be running with Medium IL (or higher)
        ///       OR running in an AppContainer with the packageManagement restricted capability
        ///       OR caller has package identity and the publisher matches the publisher of the volume being removed.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.removepackagevolumeasync
        [contract(PackageDeploymentContract, 3)]
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress> RemoveAsync();

        /// Set the package volume to an offline state.
        /// @note This requires admin privilege.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeofflineasync
        [contract(PackageDeploymentContract, 3)]
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress> SetOfflineAsync();

        /// Set the package volume to an online state.
        /// @note This requires admin privilege.
        /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeonlineasync
        [contract(PackageDeploymentContract, 3)]
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress> SetOnlineAsync();

        /// Get the available space (bytes).
        /// @see https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.packagevolume.getavailablespaceasync?view=winrt-26100
        [contract(PackageDeploymentContract, 3)]
        Windows.Foundation.IAsyncOperation<UInt64> GetAvailableSpaceAsync();
    };

    /// Defines the stub behavior for an app package that is being added or staged.
    /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.stubpackageoption
    [contract(PackageDeploymentContract, 1)]
    enum StubPackageOption
    {
        Default,
        InstallFull,
        InstallStub,
        UsePreference,
    };

    /// Defines the stub behavior for an app package that is being added or staged.
    [contract(PackageDeploymentContract, 2)]
    enum PackageReadyOrNewerAvailableStatus
    {
        NotReady             = 0,
        Ready                = 1,
        NewerAvailable       = 2,
    };

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageValidationEventArgs
    {
        Windows.Foundation.Uri PackageUri{ get; };
        IInspectable AppxPackagingObject{ get; };
        Boolean Cancel;

        Windows.Foundation.Deferral GetDeferral();
    }

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageValidationEventSource
    {
        event Windows.Foundation.TypedEventHandler<PackageValidationEventSource, PackageValidationEventArgs> ValidationRequested;
    }

    [contract(PackageDeploymentContract, 3)]
    interface IPackageValidator
    {
        // This IInspectable will support QueryInterface into either IAppxPackageReader or
        // IAppxBundleReader (these are COM interfaces from AppxPackaging.h).
        // One of these interfaces will be available depending on the type of file being validated.
        Boolean IsPackageValid(IInspectable appxPackagingObject);
    }

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageValidationHandler
    {
        PackageValidationHandler(IPackageValidator validator);
        Windows.Foundation.TypedEventHandler<PackageValidationEventSource, PackageValidationEventArgs> Handler{ get; };
    }

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageFamilyNameValidator : [default] IPackageValidator
    {
        PackageFamilyNameValidator(String expectedPackageFamilyName);
    }

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageMinimumVersionValidator : [default] IPackageValidator
    {
        PackageMinimumVersionValidator(Windows.ApplicationModel.PackageVersion minimumVersion);
    }

    [contract(PackageDeploymentContract, 3)]
    runtimeclass PackageCertificateEkuValidator : [default] IPackageValidator
    {
        PackageCertificateEkuValidator(String expectedCertificateEku);
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageSetItem
    {
        PackageSetItem();

        String Id;
        String PackageFamilyName;
        Windows.ApplicationModel.PackageVersion MinVersion;
        Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyProcessorArchitectures ProcessorArchitectureFilter;
        Windows.Foundation.Uri PackageUri;
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageSet
    {
        PackageSet();

        String Id;
        Windows.Foundation.Uri PackageUri;
        IVector<PackageSetItem> Items { get; };
    }

    // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1)
    [contract(PackageDeploymentContract, 1)]
    runtimeclass AddPackageOptions
    {
        AddPackageOptions();

        PackageVolume TargetVolume;
        IVector<Windows.Foundation.Uri> DependencyPackageUris { get; };
        IVector<String> OptionalPackageFamilyNames { get; };
        IVector<Windows.Foundation.Uri> OptionalPackageUris { get; };
        IVector<Windows.Foundation.Uri> RelatedPackageUris { get; };
        Windows.Foundation.Uri ExternalLocationUri;
        StubPackageOption StubPackageOption;
        Boolean AllowUnsigned;
        Boolean DeveloperMode;
        Boolean ForceAppShutdown;
        Boolean ForceTargetAppShutdown;
        Boolean ForceUpdateFromAnyVersion;
        Boolean InstallAllResources;
        Boolean RequiredContentGroupOnly;
        Boolean RetainFilesOnFailure;
        Boolean StageInPlace;
        Boolean DeferRegistrationWhenPackagesAreInUse;

        Boolean IsExpectedDigestsSupported { get; };            // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
        IMap<Windows.Foundation.Uri, String> ExpectedDigests{ get; };

        Boolean IsLimitToExistingPackagesSupported { get; };    // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
        Boolean LimitToExistingPackages;

        [contract(PackageDeploymentContract, 3)]
        Boolean IsPackageValidationSupported{ get; };

        [contract(PackageDeploymentContract, 3)]
        IMapView<Windows.Foundation.Uri, PackageValidationEventSource> PackageValidators{ get; };

        [contract(PackageDeploymentContract, 3)]
        PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri);
    }

    // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1)
    [contract(PackageDeploymentContract, 1)]
    runtimeclass StagePackageOptions
    {
        StagePackageOptions();

        PackageVolume TargetVolume;
        IVector<Windows.Foundation.Uri> DependencyPackageUris { get; };
        IVector<String> OptionalPackageFamilyNames { get; };
        IVector<Windows.Foundation.Uri> OptionalPackageUris { get; };
        IVector<Windows.Foundation.Uri> RelatedPackageUris { get; };
        Windows.Foundation.Uri ExternalLocationUri;
        StubPackageOption StubPackageOption;
        Boolean DeveloperMode;
        Boolean ForceUpdateFromAnyVersion;
        Boolean InstallAllResources;
        Boolean RequiredContentGroupOnly;
        Boolean StageInPlace;
        Boolean AllowUnsigned;

        Boolean IsExpectedDigestsSupported { get; };            // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
        IMap<Windows.Foundation.Uri, String> ExpectedDigests{ get; };

        [contract(PackageDeploymentContract, 3)]
        Boolean IsPackageValidationSupported{ get; };

        [contract(PackageDeploymentContract, 3)]
        IMapView<Windows.Foundation.Uri, PackageValidationEventSource> PackageValidators{ get; };

        [contract(PackageDeploymentContract, 3)]
        PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri);
    }

    // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1)
    [contract(PackageDeploymentContract, 1)]
    runtimeclass RegisterPackageOptions
    {
        RegisterPackageOptions();

        PackageVolume AppDataVolume;
        IVector<String> DependencyPackageFamilyNames { get; };
        IVector<Windows.Foundation.Uri> DependencyPackageUris { get; };
        IVector<String> OptionalPackageFamilyNames { get; };
        Windows.Foundation.Uri ExternalLocationUri;
        Boolean AllowUnsigned;
        Boolean DeveloperMode;
        Boolean ForceAppShutdown;
        Boolean ForceTargetAppShutdown;
        Boolean ForceUpdateFromAnyVersion;
        Boolean InstallAllResources;
        Boolean StageInPlace;
        Boolean DeferRegistrationWhenPackagesAreInUse;

        Boolean IsExpectedDigestsSupported { get; };            // Requires Windows >= 10.0.22621.0 (aka Win11 22H2)
        IMap<Windows.Foundation.Uri, String> ExpectedDigests{ get; };
    }

    // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1)
    [contract(PackageDeploymentContract, 1)]
    runtimeclass RemovePackageOptions
    {
        RemovePackageOptions();

        Boolean FailIfNotFound;
        Boolean PreserveApplicationData;
        Boolean PreserveRoamableApplicationData;
        Boolean RemoveForAllUsers;
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass ProvisionPackageOptions
    {
        ProvisionPackageOptions();

        Boolean IsOptionalPackageFamilyNamesSupported{ get; };  // Requires Windows >= 10.0.22000.0 (aka Win11 21H2)
        IVector<String> OptionalPackageFamilyNames { get; };

        Boolean IsProjectionOrderPackageFamilyNamesSupported{ get; };   // Requires Windows >= 10.0.22000.0 (aka Win11 21H2)
        IVector<String> ProjectionOrderPackageFamilyNames { get; };
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass EnsureReadyOptions
    {
        EnsureReadyOptions();

        AddPackageOptions AddPackageOptions { get; };

        [contract(PackageDeploymentContract, 2)]
        Boolean RegisterNewerIfAvailable;
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageDeploymentManager
    {
        // Get an instance of the manager
        static PackageDeploymentManager GetDefault();

        //-------------------------------------------------------------
        // IsPackageDeploymentFeatureSupported

        [contract(PackageDeploymentContract, 2)]
        static Boolean IsPackageDeploymentFeatureSupported(PackageDeploymentFeature feature);

        //-------------------------------------------------------------
        // IsReady

        // Return true if the package(s) are present and available for use
        Boolean IsPackageReady(String package);

        // Return true if the package(s) are present and available for use
        Boolean IsPackageReadyByUri(Windows.Foundation.Uri packageUri);

        // Return true if the package(s) are present and available for use
        /// @note packageSet[Item].PackageUri is optional
        Boolean IsPackageSetReady(PackageSet packageSet);

        //-------------------------------------------------------------
        // IsReadyOrNewerAvailable

        // Return true if the package(s) are present and available for use
        [contract(PackageDeploymentContract, 2)]
        PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailable(String package);

        // Return true if the package(s) are present and available for use
        [contract(PackageDeploymentContract, 2)]
        PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailableByUri(Windows.Foundation.Uri packageUri);

        // Return true if the package(s) are present and available for use
        /// @note packageSet[Item].PackageUri is optional
        [contract(PackageDeploymentContract, 2)]
        PackageReadyOrNewerAvailableStatus IsPackageSetReadyOrNewerAvailable(PackageSet packageSet);

        //-------------------------------------------------------------
        // EnsureReady

        // Check if the necessary package(s) are present
        // and available for use and if not then Make It So.
        // If the necessary packages(s) are not present on the system
        // then make them available (download, install, etc).
        // If the necessary packages are present and available this is equivalent to IsReady(id).

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        EnsurePackageReadyAsync(String package, EnsureReadyOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        EnsurePackageReadyByUriAsync(Windows.Foundation.Uri packageUri, EnsureReadyOptions options);

        /// @note packageSet[Item].PackageUri is required
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        EnsurePackageSetReadyAsync(PackageSet packageSet, EnsureReadyOptions options);

        //-------------------------------------------------------------
        // Add packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        AddPackageAsync(String package, AddPackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        AddPackageByUriAsync(Windows.Foundation.Uri packageUri, AddPackageOptions options);

        /// @note packageSet[Item].PackageUri is required
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        AddPackageSetAsync(PackageSet packageSet, AddPackageOptions options);

        //-------------------------------------------------------------
        // Stage packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        StagePackageAsync(String package, StagePackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        StagePackageByUriAsync(Windows.Foundation.Uri packageUri, StagePackageOptions options);

        /// @note packageSet[Item].PackageUri is required
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        StagePackageSetAsync(PackageSet packageSet, StagePackageOptions options);

        //-------------------------------------------------------------
        // Register packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RegisterPackageAsync(String package, RegisterPackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RegisterPackageByUriAsync(Windows.Foundation.Uri packageUri, RegisterPackageOptions options);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RegisterPackageSetAsync(PackageSet packageSet, RegisterPackageOptions options);

        //-------------------------------------------------------------
        // Remove packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RemovePackageAsync(String package, RemovePackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RemovePackageByFullNameAsync(String packageFullName, RemovePackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RemovePackageByFamilyNameAsync(String packageFamilyName, RemovePackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RemovePackageByUriAsync(Windows.Foundation.Uri packageUri, RemovePackageOptions options);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RemovePackageSetAsync(PackageSet packageSet, RemovePackageOptions options);

        //-------------------------------------------------------------
        // Reset packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ResetPackageAsync(String package);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ResetPackageByUriAsync(Windows.Foundation.Uri packageUri);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ResetPackageSetAsync(PackageSet packageSet);

        //-------------------------------------------------------------
        // Repair packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RepairPackageAsync(String package);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RepairPackageByUriAsync(Windows.Foundation.Uri packageUri);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        RepairPackageSetAsync(PackageSet packageSet);

        //-------------------------------------------------------------
        // IsProvisioned

        // Return true if the package(s) are provisioned
        [contract(PackageDeploymentContract, 2)]
        Boolean IsPackageProvisioned(String package);

        // Return true if the package(s) are provisioned
        [contract(PackageDeploymentContract, 2)]
        Boolean IsPackageProvisionedByUri(Windows.Foundation.Uri packageUri);

        // Return true if the package(s) are provisioned
        /// @note packageSet[Item].PackageUri is optional
        [contract(PackageDeploymentContract, 2)]
        Boolean IsPackageSetProvisioned(PackageSet packageSet);

        //-------------------------------------------------------------
        // Provision packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ProvisionPackageAsync(String package, ProvisionPackageOptions options);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ProvisionPackageByUriAsync(Windows.Foundation.Uri packageUri, ProvisionPackageOptions options);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        ProvisionPackageSetAsync(PackageSet packageSet, ProvisionPackageOptions options);

        //-------------------------------------------------------------
        // Deprovision packages

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        DeprovisionPackageAsync(String package);

        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        DeprovisionPackageByUriAsync(Windows.Foundation.Uri packageUri);

        /// @note packageSet[Item].PackageUri is optional
        Windows.Foundation.IAsyncOperationWithProgress<PackageDeploymentResult, PackageDeploymentProgress>
        DeprovisionPackageSetAsync(PackageSet packageSet);

        //-------------------------------------------------------------
        // IsRegistrationPending

        /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356.
        ///          Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name.
        Boolean IsPackageRegistrationPending(String packageFamilyName);

        /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356.
        ///          Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name.
        Boolean IsPackageRegistrationPendingForUser(String userSecurityId, String packageFamilyName);
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageSetItemRuntimeDisposition
    {
        PackageSetItemRuntimeDisposition();

        String PackageSetItemId{ get; };
        String PackageFullName{ get; };
        String PackageDependencyId{ get; };
        Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependencyContextId PackageDependencyContextId{ get; };
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageSetRuntimeDisposition
    {
        PackageSetRuntimeDisposition();

        String PackageSetId;
        IVector<PackageSetItemRuntimeDisposition> PackageSetItemRuntimeDispositions { get; };
    }

    [contract(PackageDeploymentContract, 1)]
    runtimeclass PackageRuntimeManager
    {
        // Get an instance of the manager
        static PackageRuntimeManager GetDefault();

        // Make the package(s) in the package set available to the calling process
        // i.e. dynamically add the package(s) in the package set to the caller's package graph.
        // This is equivalent to
        //   FOREACH psi IN packageSet.Items
        //       pd = TryCreatePackageDependency(psi)
        //       AddPackageDependency(pd)

        Microsoft.Windows.Management.Deployment.PackageSetRuntimeDisposition AddPackageSet(
            PackageSet packageSet);

        [method_name("AddPackageSetWithOptions")]
        Microsoft.Windows.Management.Deployment.PackageSetRuntimeDisposition AddPackageSet(
            PackageSet packageSet,
            Microsoft.Windows.ApplicationModel.DynamicDependency.CreatePackageDependencyOptions createOptions,
            Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions addOptions);

        void RemovePackageSet(
            Microsoft.Windows.Management.Deployment.PackageSetRuntimeDisposition packageSetRuntimeDisposition);
    }
}