public void TestMismatchedExtension() { GuardTempDirectory(tempDirectory => { // Build an APPX package which is in reality an appx bundle. var tempFile = Path.Combine(tempDirectory.FullName, "bundle.appx"); using (var fileStream = File.OpenWrite(tempFile)) { using (var zip = new ZipArchive(fileStream, ZipArchiveMode.Create, true)) { var entry = zip.CreateEntry(FileConstants.AppxBundleManifestFilePath); var entryStream = entry.Open(); var embeddedResourceName = this.GetType().Assembly.GetManifestResourceNames().First(rn => rn.Contains("resources.appxbundlemanifest.xml", StringComparison.OrdinalIgnoreCase)); using var bundleManifest = this.GetType().Assembly.GetManifestResourceStream(embeddedResourceName); // ReSharper disable once PossibleNullReferenceException bundleManifest.CopyTo(entryStream); } } IAppxIdentityReader reader = new AppxIdentityReader(); Assert.Throws <ArgumentException>(() => { GuardAggregateExceptions(() => { reader.GetIdentity(tempFile).Wait(); }); }, "This must throw, because the file on a disk has an APPX extension but the content is a bundle."); using (var fileStream = File.OpenRead(tempFile)) { Assert.Throws <ArgumentException>(() => { GuardAggregateExceptions(() => { // ReSharper disable once AccessToDisposedClosure reader.GetIdentity(fileStream).Wait(); }); }, "This must throw, because file stream points to a concrete file on a disk which has an APPX extension but the content is a bundle."); } using var memoryStream = new MemoryStream(File.ReadAllBytes(tempFile)); // The following may not throw, because a memory stream will be tried for various options and asserted to be an APPX bundle. reader.GetIdentity(memoryStream).Wait(); }); }
public void TestInvalidXmlFile() { var invalidContent = @"<?xml version=""1.0""?> <NotSupportedRoot xmlns=""http://schemas.microsoft.com/appx/manifest/foundation/windows10""> <Identity Name=""SampleProduct"" Publisher=""CN=me"" Version=""1.2.3.4"" ProcessorArchitecture=""x64"" /> </NotSupportedRoot> "; var utfEncoding = new UTF8Encoding(false, false); var xmlStream = new MemoryStream(utfEncoding.GetBytes(invalidContent)); IAppxIdentityReader reader = new AppxIdentityReader(); Assert.Throws <ArgumentException>(() => { GuardAggregateExceptions(() => { reader.GetIdentity(xmlStream).Wait(); }); }, "This must throw because the file is definitely not in MSIX, APPX or any other supported format."); }
public void TestInvalidZipFile() { using var memoryStream = new MemoryStream(); using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) { // add some dummy file = not a manifest var dummyFile = zipArchive.CreateEntry("dummyFile.xml"); var s = dummyFile.Open(); s.WriteByte(128); } IAppxIdentityReader reader = new AppxIdentityReader(); Assert.Throws <ArgumentException>(() => { GuardAggregateExceptions(() => { // ReSharper disable once AccessToDisposedClosure reader.GetIdentity(memoryStream).Wait(); }); }, "This must throw because the file is a ZIP-like but contains no manifest."); }
public async Task Add(string filePath, AddAppxPackageOptions options = 0, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = default) { this.SideloadingConfigurator.AssertSideloadingEnabled(); Logger.Info("Installing package {0}", filePath); if (filePath == null) { throw new ArgumentNullException(nameof(filePath)); } if (string.Equals(Path.GetFileName(filePath), FileConstants.AppxManifestFile, StringComparison.OrdinalIgnoreCase)) { if (options.HasFlag(AddAppxPackageOptions.AllBundleResources)) { throw new ArgumentException("Cannot use the flag AllBundleResources with non-bundle packages.", nameof(options)); } var reader = await AppxManifestSummaryReader.FromManifest(filePath).ConfigureAwait(false); DeploymentOptions deploymentOptions = 0; if (options.HasFlag(AddAppxPackageOptions.AllowDowngrade)) { deploymentOptions |= DeploymentOptions.ForceUpdateFromAnyVersion; } if (options.HasFlag(AddAppxPackageOptions.KillRunningApps)) { deploymentOptions |= DeploymentOptions.ForceApplicationShutdown; deploymentOptions |= DeploymentOptions.ForceTargetApplicationShutdown; } deploymentOptions |= DeploymentOptions.DevelopmentMode; await AsyncOperationHelper.ConvertToTask( PackageManagerWrapper.Instance.RegisterPackageAsync(new Uri(filePath), Enumerable.Empty <Uri>(), deploymentOptions), $"Installing {reader.DisplayName} {reader.Version}...", cancellationToken, progress).ConfigureAwait(false); } else if (string.Equals(FileConstants.AppInstallerExtension, Path.GetExtension(filePath), StringComparison.OrdinalIgnoreCase)) { if (options.HasFlag(AddAppxPackageOptions.AllUsers)) { throw new ArgumentException("Cannot install a package from .appinstaller for all users.", nameof(options)); } if (options.HasFlag(AddAppxPackageOptions.AllBundleResources)) { throw new ArgumentException("Cannot use the flag AllBundleResources with non-bundle packages.", nameof(options)); } if (options.HasFlag(AddAppxPackageOptions.AllowDowngrade)) { throw new ArgumentException("Cannot force a downgrade with .appinstaller. The .appinstaller defines on its own whether the downgrade is allowed.", nameof(options)); } AddPackageByAppInstallerOptions deploymentOptions = 0; if (options.HasFlag(AddAppxPackageOptions.KillRunningApps)) { deploymentOptions |= AddPackageByAppInstallerOptions.ForceTargetAppShutdown; } var volume = PackageManagerWrapper.Instance.GetDefaultPackageVolume(); await AsyncOperationHelper.ConvertToTask( PackageManagerWrapper.Instance.AddPackageByAppInstallerFileAsync(new Uri(filePath, UriKind.Absolute), deploymentOptions, volume), "Installing from " + Path.GetFileName(filePath) + "...", cancellationToken, progress).ConfigureAwait(false); } else { string name, version, publisher; DeploymentOptions deploymentOptions = 0; switch (Path.GetExtension(filePath)) { case FileConstants.AppxBundleExtension: case FileConstants.MsixBundleExtension: { IAppxIdentityReader reader = new AppxIdentityReader(); var identity = await reader.GetIdentity(filePath, cancellationToken).ConfigureAwait(false); name = identity.Name; publisher = identity.Publisher; version = identity.Version; if (options.HasFlag(AddAppxPackageOptions.AllBundleResources)) { deploymentOptions |= DeploymentOptions.InstallAllResources; } break; } default: { if (options.HasFlag(AddAppxPackageOptions.AllBundleResources)) { throw new ArgumentException("Cannot use the flag AllBundleResources with non-bundle packages.", nameof(options)); } var reader = await AppxManifestSummaryReader.FromMsix(filePath).ConfigureAwait(false); name = reader.DisplayName; version = reader.Version; publisher = reader.Publisher; break; } } if (options.HasFlag(AddAppxPackageOptions.AllowDowngrade)) { deploymentOptions |= DeploymentOptions.ForceUpdateFromAnyVersion; } if (options.HasFlag(AddAppxPackageOptions.KillRunningApps)) { deploymentOptions |= DeploymentOptions.ForceApplicationShutdown; deploymentOptions |= DeploymentOptions.ForceTargetApplicationShutdown; } if (options.HasFlag(AddAppxPackageOptions.AllUsers)) { var deploymentResult = await AsyncOperationHelper.ConvertToTask( PackageManagerWrapper.Instance.AddPackageAsync(new Uri(filePath, UriKind.Absolute), Enumerable.Empty <Uri>(), deploymentOptions), $"Installing {name} {version}...", cancellationToken, progress).ConfigureAwait(false); if (!deploymentResult.IsRegistered) { throw new InvalidOperationException("The package could not be registered."); } var findInstalled = PackageManagerWrapper.Instance.FindPackages(name, publisher).FirstOrDefault(); if (findInstalled == null) { throw new InvalidOperationException("The package could not be registered."); } var familyName = findInstalled.Id.FamilyName; await AsyncOperationHelper.ConvertToTask( PackageManagerWrapper.Instance.ProvisionPackageForAllUsersAsync(familyName), $"Provisioning {name} {version}...", cancellationToken, progress).ConfigureAwait(false); } else { var deploymentResult = await AsyncOperationHelper.ConvertToTask( PackageManagerWrapper.Instance.AddPackageAsync(new Uri(filePath, UriKind.Absolute), Enumerable.Empty <Uri>(), deploymentOptions), "Installing " + name + "...", cancellationToken, progress).ConfigureAwait(false); if (!deploymentResult.IsRegistered) { var message = "Could not install " + name + " " + version + "."; if (!string.IsNullOrEmpty(deploymentResult.ErrorText)) { message += " " + deploymentResult.ErrorText; } if (deploymentResult.ExtendedErrorCode != null) { throw new InvalidOperationException(message, deploymentResult.ExtendedErrorCode); } throw new InvalidOperationException(message); } } } }
public AppInstallerConfig Build(PackageType packageType = PackageType.Package) { var appIns = new AppInstallerConfig(); appIns.UpdateSettings = new UpdateSettings(); switch (this.CheckForUpdates) { case AppInstallerUpdateCheckingMethod.Never: appIns.UpdateSettings.OnLaunch = null; appIns.UpdateSettings.AutomaticBackgroundTask = null; break; case AppInstallerUpdateCheckingMethod.Launch: appIns.UpdateSettings.OnLaunch = new OnLaunchSettings(); appIns.UpdateSettings.AutomaticBackgroundTask = null; break; case AppInstallerUpdateCheckingMethod.LaunchAndBackground: appIns.UpdateSettings.OnLaunch = new OnLaunchSettings(); appIns.UpdateSettings.AutomaticBackgroundTask = new AutomaticBackgroundTaskSettings(); break; case AppInstallerUpdateCheckingMethod.Background: appIns.UpdateSettings.OnLaunch = null; appIns.UpdateSettings.AutomaticBackgroundTask = new AutomaticBackgroundTaskSettings(); break; default: throw new ArgumentOutOfRangeException(); } if (this.AllowDowngrades) { appIns.UpdateSettings.ForceUpdateFromAnyVersion = true; } appIns.UpdateSettings.ForceUpdateFromAnyVersion = this.AllowDowngrades; if (appIns.UpdateSettings.OnLaunch != null) { appIns.UpdateSettings.OnLaunch.UpdateBlocksActivation = this.UpdateBlocksActivation; appIns.UpdateSettings.OnLaunch.ShowPrompt = this.ShowPrompt; if (this.HoursBetweenUpdateChecks != 24) { appIns.UpdateSettings.OnLaunch.HoursBetweenUpdateChecks = this.HoursBetweenUpdateChecks; } } if (this.MainPackageSource != null) { AppxIdentity identity; var identityReader = new AppxIdentityReader(); try { identity = identityReader.GetIdentity(this.MainPackageSource.FullName).Result; } catch (AggregateException e) { throw e.GetBaseException(); } if (packageType == PackageType.Bundle) { appIns.MainBundle = new AppInstallerBundleEntry { Name = identity.Name, Version = identity.Version, Publisher = identity.Publisher, Uri = this.MainPackageUri?.ToString() }; } else { appIns.MainPackage = new AppInstallerPackageEntry { Name = identity.Name, Version = identity.Version, Publisher = identity.Publisher, Uri = this.MainPackageUri?.ToString() }; if (identity.Architectures?.Any() != true) { appIns.MainPackage.Architecture = AppInstallerPackageArchitecture.neutral; } else { var arch = identity.Architectures.First().ToString("G"); if (Enum.TryParse(arch, true, out AppInstallerPackageArchitecture parsed)) { appIns.MainPackage.Architecture = parsed; } } } } else { if (packageType == PackageType.Bundle) { appIns.MainBundle = new AppInstallerBundleEntry { Name = this.MainPackageName, Version = this.MainPackageVersion, Publisher = MainPackagePublisher, Uri = this.MainPackageUri?.ToString() }; } else if (packageType == PackageType.Package) { appIns.MainPackage = new AppInstallerPackageEntry { Name = this.MainPackageName, Version = this.MainPackageVersion, Publisher = MainPackagePublisher, Uri = this.MainPackageUri?.ToString(), Architecture = (AppInstallerPackageArchitecture)Enum.Parse(typeof(AppInstallerPackageArchitecture), this.MainPackageArchitecture.ToString("G"), true) }; } } if (!appIns.UpdateSettings.ForceUpdateFromAnyVersion && appIns.UpdateSettings.OnLaunch == null && appIns.UpdateSettings.AutomaticBackgroundTask == null) { appIns.UpdateSettings = null; } if (this.RedirectUri != null) { appIns.Uri = this.RedirectUri.ToString(); } appIns.Version = this.Version ?? "1.0.0.0"; return(appIns); }
public void TestAppxBundleManifest() { // in a manifest, from memory GuardAggregateExceptions(() => { IAppxIdentityReader reader = new AppxIdentityReader(); var embeddedResourceName = this.GetType().Assembly.GetManifestResourceNames().First(rn => rn.Contains("resources.appxbundlemanifest.xml", StringComparison.OrdinalIgnoreCase)); using var bundleManifest = this.GetType().Assembly.GetManifestResourceStream(embeddedResourceName); var identity = reader.GetIdentity(bundleManifest).Result; Assert.AreEqual("Microsoft.DesktopAppInstaller", identity.Name); Assert.AreEqual("CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", identity.Publisher); Assert.AreEqual("2021.119.2316.0", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(3, identity.Architectures.Length); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.Arm)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x64)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x86)); }); // in a manifest, saved on disk GuardTempDirectory(tempDirectory => { IAppxIdentityReader reader = new AppxIdentityReader(); var manifestFile = Path.Combine(tempDirectory.FullName, FileConstants.AppxBundleManifestFile); using (var fs = File.OpenWrite(manifestFile)) { var embeddedResourceName = this.GetType().Assembly.GetManifestResourceNames().First(rn => rn.Contains("resources.appxbundlemanifest.xml", StringComparison.OrdinalIgnoreCase)); using var bundleManifest = this.GetType().Assembly.GetManifestResourceStream(embeddedResourceName); // ReSharper disable once PossibleNullReferenceException bundleManifest.CopyTo(fs); fs.Flush(); } var identity = reader.GetIdentity(manifestFile).Result; Assert.AreEqual("Microsoft.DesktopAppInstaller", identity.Name); Assert.AreEqual("CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", identity.Publisher); Assert.AreEqual("2021.119.2316.0", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(3, identity.Architectures.Length); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.Arm)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x64)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x86)); }); // in a zip file GuardAggregateExceptions(() => { using var memStream = new MemoryStream(); // build package resembling MSIX structure using (var stream = new ZipArchive(memStream, ZipArchiveMode.Create, true)) { var entry = stream.CreateEntry(FileConstants.AppxBundleManifestFilePath); var entryStream = entry.Open(); var embeddedResourceName = this.GetType().Assembly.GetManifestResourceNames().First(rn => rn.Contains("resources.appxbundlemanifest.xml", StringComparison.OrdinalIgnoreCase)); using var bundleManifest = this.GetType().Assembly.GetManifestResourceStream(embeddedResourceName); // ReSharper disable once PossibleNullReferenceException bundleManifest.CopyTo(entryStream); } memStream.Seek(0, SeekOrigin.Begin); IAppxIdentityReader reader = new AppxIdentityReader(); var identity = reader.GetIdentity(memStream).Result; Assert.AreEqual("Microsoft.DesktopAppInstaller", identity.Name); Assert.AreEqual("CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", identity.Publisher); Assert.AreEqual("2021.119.2316.0", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(3, identity.Architectures.Length); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.Arm)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x64)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x86)); }); // in a zip file, saved on disk GuardTempDirectory(tempDirectory => { var tempFile = Path.Combine(tempDirectory.FullName, "testpackage.appxbundle"); using (var tempFileStream = File.OpenWrite(tempFile)) { // build package resembling MSIX structure using var stream = new ZipArchive(tempFileStream, ZipArchiveMode.Create, false); var entry = stream.CreateEntry(FileConstants.AppxBundleManifestFilePath); var entryStream = entry.Open(); var embeddedResourceName = this.GetType().Assembly.GetManifestResourceNames().First(rn => rn.Contains("resources.appxbundlemanifest.xml", StringComparison.OrdinalIgnoreCase)); using var bundleManifest = this.GetType().Assembly.GetManifestResourceStream(embeddedResourceName); // ReSharper disable once PossibleNullReferenceException bundleManifest.CopyTo(entryStream); } IAppxIdentityReader reader = new AppxIdentityReader(); var identity = reader.GetIdentity(tempFile).Result; Assert.AreEqual("Microsoft.DesktopAppInstaller", identity.Name); Assert.AreEqual("CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US", identity.Publisher); Assert.AreEqual("2021.119.2316.0", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(3, identity.Architectures.Length); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.Arm)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x64)); Assert.IsTrue(identity.Architectures.Contains(AppxPackageArchitecture.x86)); }); }
public void TestAppxManifest() { // in a manifest, from memory GuardAggregateExceptions(() => { IAppxIdentityReader reader = new AppxIdentityReader(); var utfEncoding = new UTF8Encoding(false, false); var stream = new MemoryStream(utfEncoding.GetBytes(SimpleAppxManifestContent)); var identity = reader.GetIdentity(stream).Result; Assert.AreEqual("SampleProduct", identity.Name); Assert.AreEqual("CN=me", identity.Publisher); Assert.AreEqual("1.2.3.4", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(1, identity.Architectures.Length); Assert.AreEqual(AppxPackageArchitecture.x64, identity.Architectures[0]); }); // in a manifest, saved on disk GuardTempDirectory(tempDirectory => { IAppxIdentityReader reader = new AppxIdentityReader(); var manifestFile = Path.Combine(tempDirectory.FullName, FileConstants.AppxManifestFile); var utfEncoding = new UTF8Encoding(false, false); File.WriteAllText(manifestFile, SimpleAppxManifestContent, utfEncoding); var identity = reader.GetIdentity(manifestFile).Result; Assert.AreEqual("SampleProduct", identity.Name); Assert.AreEqual("CN=me", identity.Publisher); Assert.AreEqual("1.2.3.4", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(1, identity.Architectures.Length); Assert.AreEqual(AppxPackageArchitecture.x64, identity.Architectures[0]); }); // in a zip file GuardAggregateExceptions(() => { using var memStream = new MemoryStream(); // build package resembling MSIX structure using (var stream = new ZipArchive(memStream, ZipArchiveMode.Create, true)) { var entry = stream.CreateEntry(FileConstants.AppxManifestFile); var entryStream = entry.Open(); var utfEncoding = new UTF8Encoding(false, false); using (var streamWriter = new StreamWriter(entryStream, utfEncoding, leaveOpen: true)) { streamWriter.Write(SimpleAppxManifestContent); } } memStream.Seek(0, SeekOrigin.Begin); IAppxIdentityReader reader = new AppxIdentityReader(); var identity = reader.GetIdentity(memStream).Result; Assert.AreEqual("SampleProduct", identity.Name); Assert.AreEqual("CN=me", identity.Publisher); Assert.AreEqual("1.2.3.4", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(1, identity.Architectures.Length); Assert.AreEqual(AppxPackageArchitecture.x64, identity.Architectures[0]); }); // in a zip file, saved on disk GuardTempDirectory(tempDirectory => { var tempFile = Path.Combine(tempDirectory.FullName, "testpackage.appx"); using (var tempFileStream = File.OpenWrite(tempFile)) { // build package resembling MSIX structure using (var stream = new ZipArchive(tempFileStream, ZipArchiveMode.Create, false)) { var entry = stream.CreateEntry(FileConstants.AppxManifestFile); var entryStream = entry.Open(); var utfEncoding = new UTF8Encoding(false, false); using (var streamWriter = new StreamWriter(entryStream, utfEncoding, leaveOpen: true)) { streamWriter.Write(SimpleAppxManifestContent); } } } IAppxIdentityReader reader = new AppxIdentityReader(); var identity = reader.GetIdentity(tempFile).Result; Assert.AreEqual("SampleProduct", identity.Name); Assert.AreEqual("CN=me", identity.Publisher); Assert.AreEqual("1.2.3.4", identity.Version); Assert.NotNull(identity.Architectures); Assert.AreEqual(1, identity.Architectures.Length); Assert.AreEqual(AppxPackageArchitecture.x64, identity.Architectures[0]); }); }