Skip to content

Commit c0387bb

Browse files
committed
Add PackageManagement.GetAppxProvisionedPackages().
1 parent 9609980 commit c0387bb

2 files changed

Lines changed: 298 additions & 0 deletions

File tree

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Windows.ApplicationModel;
7+
using Windows.ApplicationModel.Core;
8+
using Windows.Storage;
9+
10+
namespace PSADT.WindowsRuntime.Management.Deployment
11+
{
12+
/// <summary>
13+
/// Provides information about a package. We have to wrap this due to COM issues on the Dependencies property via Windows PowerShell 5.1...
14+
/// </summary>
15+
public sealed record PackageInformation
16+
{
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="PackageInformation"/> record based on the provided <see cref="Package"/>.
19+
/// </summary>
20+
/// <param name="package"></param>
21+
internal PackageInformation(Package package)
22+
{
23+
_package = package;
24+
}
25+
26+
/// <summary>
27+
/// Gets the packages on which the current package depends.
28+
/// </summary>
29+
public IReadOnlyList<PackageInformation> Dependencies => new ReadOnlyCollection<PackageInformation>([.. _package.Dependencies.Select(static p => new PackageInformation(p))]);
30+
31+
/// <summary>
32+
/// Gets the package identity of the current package.
33+
/// </summary>
34+
public PackageId Id => _package.Id;
35+
36+
/// <summary>
37+
/// Gets the current package's path in the original install folder for the current package.
38+
/// </summary>
39+
public StorageFolder InstalledLocation => _package.InstalledLocation;
40+
41+
/// <summary>
42+
/// Indicates whether other packages can declare a dependency on this package.
43+
/// </summary>
44+
public bool IsFramework => _package.IsFramework;
45+
46+
/// <summary>
47+
/// Gets the description of the package.
48+
/// </summary>
49+
public string Description => _package.Description;
50+
51+
/// <summary>
52+
/// Gets the display name of the package.
53+
/// </summary>
54+
public string DisplayName => _package.DisplayName;
55+
56+
/// <summary>
57+
/// Indicates whether the package is a bundle package.
58+
/// </summary>
59+
public bool IsBundle => _package.IsBundle;
60+
61+
/// <summary>
62+
/// Indicates whether the package is installed in development mode.
63+
/// </summary>
64+
public bool IsDevelopmentMode => _package.IsDevelopmentMode;
65+
66+
/// <summary>
67+
/// Indicates whether the package is a resource package.
68+
/// </summary>
69+
public bool IsResourcePackage => _package.IsResourcePackage;
70+
71+
/// <summary>
72+
/// Gets the logo of the package.
73+
/// </summary>
74+
public Uri Logo => _package.Logo;
75+
76+
/// <summary>
77+
/// Gets the publisher display name of the package.
78+
/// </summary>
79+
public string PublisherDisplayName => _package.PublisherDisplayName;
80+
81+
/// <summary>
82+
/// Gets the date on which the application package was installed or last updated.
83+
/// </summary>
84+
public DateTimeOffset InstalledDate => _package.InstalledDate;
85+
86+
/// <summary>
87+
/// Get the current status of the package for the user.
88+
/// </summary>
89+
public PackageStatus Status => _package.Status;
90+
91+
/// <summary>
92+
/// Indicates whether the package is optional.
93+
/// </summary>
94+
public bool IsOptional => _package.IsOptional;
95+
96+
/// <summary>
97+
/// How the app package is signed.
98+
/// </summary>
99+
public PackageSignatureKind SignatureKind => _package.SignatureKind;
100+
101+
/// <summary>
102+
/// Gets the effective location for the installed package, depending on how the app is declared in its package manifest. For details, see Remarks.
103+
/// </summary>
104+
public StorageFolder EffectiveLocation => _package.EffectiveLocation;
105+
106+
/// <summary>
107+
/// Gets the current package's path in the mutable folder for the installed package, if the app is declared to be mutable in its package manifest.
108+
/// </summary>
109+
public StorageFolder MutableLocation => _package.MutableLocation;
110+
111+
/// <summary>
112+
/// Gets the location of the machine-wide or per-user external folder specified in the package manifest for the current package, depending on how the app is installed.
113+
/// </summary>
114+
public StorageFolder EffectiveExternalLocation => _package.EffectiveExternalLocation;
115+
116+
/// <summary>
117+
/// Gets the location of the machine-wide or per-user external folder specified in the package manifest for the current package, depending on how the app is installed.
118+
/// </summary>
119+
public string EffectiveExternalPath => _package.EffectiveExternalPath;
120+
121+
/// <summary>
122+
/// Gets either the path of the installed folder or the mutable folder for the installed package, depending on whether the app is declared to be mutable in its package manifest.
123+
/// </summary>
124+
public string EffectivePath => _package.EffectivePath;
125+
126+
/// <summary>
127+
/// Gets the current package's path in the original install folder for the current package.
128+
/// </summary>
129+
public string InstalledPath => _package.InstalledPath;
130+
131+
/// <summary>
132+
/// Gets a value that indicates whether the application in the current package is a stub application.
133+
/// </summary>
134+
public bool IsStub => _package.IsStub;
135+
136+
/// <summary>
137+
/// Gets the location of the machine-wide external folder specified in the package manifest for the current package.
138+
/// </summary>
139+
public StorageFolder MachineExternalLocation => _package.MachineExternalLocation;
140+
141+
/// <summary>
142+
/// Gets the location of the machine-wide external folder specified in the package manifest for the current package.
143+
/// </summary>
144+
public string MachineExternalPath => _package.MachineExternalPath;
145+
146+
/// <summary>
147+
/// Gets the current package's path in the mutable folder for the installed package, if the app is declared to be mutable in its package manifest.
148+
/// </summary>
149+
public string MutablePath => _package.MutablePath;
150+
151+
/// <summary>
152+
/// Gets the location of the per-user external folder specified in the package manifest for the current package.
153+
/// </summary>
154+
public StorageFolder UserExternalLocation => _package.UserExternalLocation;
155+
156+
/// <summary>
157+
/// Gets the path of the per-user external folder specified in the package manifest for the current package.
158+
/// </summary>
159+
public string UserExternalPath => _package.UserExternalPath;
160+
161+
/// <summary>
162+
/// Contains the scheme part of the URI that was used to install the package.
163+
/// </summary>
164+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3996:URI properties should not be strings", Justification = "This is invalid.")]
165+
public string SourceUriSchemeName => _package.SourceUriSchemeName;
166+
167+
/// <summary>
168+
/// The CheckUpdateAvailabilityAsync method allows developers to check for updates to the main app package listed in the .appinstaller file. It allows the developer to determine if the updates are required due to .appinstaller policy. This method currently only works for applications installed via .appinstaller files.
169+
/// </summary>
170+
/// <returns>A PackageUpdateAvailabilityResult that indicates if an application has an update, and if the update is required.</returns>
171+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "There's no async in PowerShell.")]
172+
public PackageUpdateAvailabilityResult CheckUpdateAvailability()
173+
{
174+
return CheckUpdateAvailabilityAsync().ConfigureAwait(false).GetAwaiter().GetResult();
175+
}
176+
177+
/// <summary>
178+
/// The CheckUpdateAvailabilityAsync method allows developers to check for updates to the main app package listed in the .appinstaller file. It allows the developer to determine if the updates are required due to .appinstaller policy. This method currently only works for applications installed via .appinstaller files.
179+
/// </summary>
180+
/// <returns>A PackageUpdateAvailabilityResult that indicates if an application has an update, and if the update is required.</returns>
181+
public Task<PackageUpdateAvailabilityResult> CheckUpdateAvailabilityAsync()
182+
{
183+
return _package.CheckUpdateAvailabilityAsync().AsTask();
184+
}
185+
186+
/// <summary>
187+
/// The FindRelatedPackages method provides the dependencies and then dependents for a given package as a Package list. The list can be filtered by the type of dependency using the options parameter.
188+
/// </summary>
189+
/// <param name="options">The FindRelatedPackageOptions which defines the search options.</param>
190+
/// <returns>A read-only list of <see cref="PackageInformation"/> objects representing the related packages.</returns>
191+
public IReadOnlyList<PackageInformation> FindRelatedPackages(FindRelatedPackagesOptions options)
192+
{
193+
return new ReadOnlyCollection<PackageInformation>([.. _package.FindRelatedPackages(options).Select(static p => new PackageInformation(p))]);
194+
}
195+
196+
/// <summary>
197+
/// Returns the .appinstaller XML file location. Use this method when you need to retrieve the .appinstaller XML file location for your app. For example, this is useful if your app needs to share a URI to its associated .appinstaller file. You can optionally add arguments to the URI.
198+
/// </summary>
199+
/// <returns>The .appinstaller XML file location.</returns>
200+
public AppInstallerInfo GetAppInstallerInfo()
201+
{
202+
return _package.GetAppInstallerInfo();
203+
}
204+
205+
/// <summary>
206+
/// Enumerates the packaged apps on the device and returns the list synchronously. Only apps included in the current package are returned.
207+
/// </summary>
208+
/// <returns>A list of AppListEntry objects that specify the packaged apps along with their display name, description, and logo.</returns>
209+
public IReadOnlyList<AppListEntry> GetAppListEntries()
210+
{
211+
return _package.GetAppListEntries();
212+
}
213+
214+
/// <summary>
215+
/// Enumerates the packaged apps on the device and returns the list asynchronously. Only apps included in the current package are returned.
216+
/// </summary>
217+
/// <returns>A task that represents the asynchronous operation. The task result contains a list of AppListEntryInformation objects that specify the packaged apps along with their display name, description, and logo.</returns>
218+
public Task<IReadOnlyList<AppListEntry>> GetAppListEntriesAsync()
219+
{
220+
return _package.GetAppListEntriesAsync().AsTask();
221+
}
222+
223+
/// <summary>
224+
/// Provides information about the package content group such as its state, name, whether it is required, and so on.
225+
/// </summary>
226+
/// <param name="name">The name of the content group to get.</param>
227+
/// <returns>A PackageContentGroup that contains information such as whether the content group is required, its state, the package associated with the content group, and so on. Returns Null if the named content group is not part of this package.</returns>
228+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "There's no async in PowerShell.")]
229+
public PackageContentGroup GetContentGroup(string name)
230+
{
231+
return GetContentGroupAsync(name).ConfigureAwait(false).GetAwaiter().GetResult();
232+
}
233+
234+
/// <summary>
235+
/// Provides information about the package content group such as its state, name, whether it is required, and so on.
236+
/// </summary>
237+
/// <param name="name">The name of the content group to get.</param>
238+
/// <returns>A PackageContentGroup that contains information such as whether the content group is required, its state, the package associated with the content group, and so on. Returns Null if the named content group is not part of this package.</returns>
239+
public Task<PackageContentGroup> GetContentGroupAsync(string name)
240+
{
241+
return _package.GetContentGroupAsync(name).AsTask();
242+
}
243+
244+
/// <summary>
245+
/// Provides information about all of the package content groups in the app and their state, name, whether they are required, and so on.
246+
/// </summary>
247+
/// <returns>A list of package content group objects.</returns>
248+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "There's no async in PowerShell.")]
249+
public IReadOnlyList<PackageContentGroup> GetContentGroups()
250+
{
251+
return GetContentGroupsAsync().ConfigureAwait(false).GetAwaiter().GetResult();
252+
}
253+
254+
/// <summary>
255+
/// Provides information about all of the package content groups in the app and their state, name, whether they are required, and so on.
256+
/// </summary>
257+
/// <returns>A list of package content group objects.</returns>
258+
public async Task<IReadOnlyList<PackageContentGroup>> GetContentGroupsAsync()
259+
{
260+
return new ReadOnlyCollection<PackageContentGroup>(await _package.GetContentGroupsAsync().AsTask().ConfigureAwait(false));
261+
}
262+
263+
/// <summary>
264+
/// Ensures that the package has not been modified or tampered with before being loaded.
265+
/// </summary>
266+
/// <returns>true - the package has not been modified; false otherwise.</returns>
267+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", Justification = "There's no async in PowerShell.")]
268+
public bool VerifyContentIntegrity()
269+
{
270+
return VerifyContentIntegrityAsync().ConfigureAwait(false).GetAwaiter().GetResult();
271+
}
272+
273+
/// <summary>
274+
/// Ensures that the package has not been modified or tampered with before being loaded.
275+
/// </summary>
276+
/// <returns>true - the package has not been modified; false otherwise.</returns>
277+
public Task<bool> VerifyContentIntegrityAsync()
278+
{
279+
return _package.VerifyContentIntegrityAsync().AsTask();
280+
}
281+
282+
/// <summary>
283+
/// The underlying <see cref="Package"/> instance from which this <see cref="PackageInformation"/> wraps.
284+
/// </summary>
285+
private readonly Package _package;
286+
}
287+
}

src/PSADT/PSADT.WindowsRuntime/Management/Deployment/PackageManagement.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
34
using System.IO;
45
using System.IO.Compression;
6+
using System.Linq;
57
using System.Runtime.InteropServices;
68
using System.Threading;
79
using System.Threading.Tasks;
@@ -17,6 +19,15 @@ namespace PSADT.WindowsRuntime.Management.Deployment
1719
/// </summary>
1820
public static class PackageManagement
1921
{
22+
/// <summary>
23+
/// Retrieves a list of all provisioned Appx/Msix packages on the system using the PackageManager API.
24+
/// </summary>
25+
/// <returns>A list of provisioned packages.</returns>
26+
public static IReadOnlyList<PackageInformation> GetAppxProvisionedPackages()
27+
{
28+
return new ReadOnlyCollection<PackageInformation>([.. new PackageManager().FindProvisionedPackages().Select(static p => new PackageInformation(p))]);
29+
}
30+
2031
/// <summary>
2132
/// Provisions the specified Appx/Msix package for all users on the system by staging the package and then provisioning it using the PackageManager API. Validates the input package URI and checks for the existence of the package file before attempting to stage and provision. Retrieves the package family name from the package manifest to use for provisioning. Throws exceptions if any step of the staging or provisioning process fails, or if the input package URI is invalid or does not point to an existing file.
2233
/// </summary>

0 commit comments

Comments
 (0)