public override async Task <int> Execute() { try { string file; ModificationPackageBuilderAction action; var config = new ModificationPackageConfig { Name = this.Verb.Name, Publisher = this.Verb.PublisherName, DisplayName = this.Verb.DisplayName, DisplayPublisher = this.Verb.PublisherDisplayName, Version = this.Verb.Version, IncludeVfsFolders = this.Verb.CopyFolderStructure }; if (string.Equals(".msix", Path.GetExtension(this.Verb.OutputPath), StringComparison.OrdinalIgnoreCase)) { file = this.Verb.OutputPath; action = ModificationPackageBuilderAction.Msix; } else { // ReSharper disable once AssignNullToNotNullAttribute file = Path.Combine(this.Verb.OutputPath, "AppxManifest.xml"); action = ModificationPackageBuilderAction.Manifest; } config.ParentPackagePath = this.Verb.ParentPackagePath; config.ParentName = this.Verb.ParentName; config.ParentPublisher = this.Verb.ParentPublisher; if (!string.IsNullOrEmpty(this.Verb.IncludeRegFile)) { config.IncludeRegistry = new FileInfo(this.Verb.IncludeRegFile); } if (!string.IsNullOrEmpty(this.Verb.IncludeFolder)) { config.IncludeFolder = new DirectoryInfo(this.Verb.IncludeFolder); } await this.appxContentBuilder.Create(config, file, action).ConfigureAwait(false); await this.Console.WriteSuccess($"Modification package created in {file}.").ConfigureAwait(false); return(0); } catch (Exception e) { Logger.Error(e); await this.Console.WriteError(e.Message).ConfigureAwait(false); return(1); } }
public async Task Create(ModificationPackageConfig config, string filePath, ModificationPackageBuilderAction action, CancellationToken cancellation = default, IProgress <ProgressData> progress = default) { var fileInfo = new FileInfo(filePath); if (fileInfo.Directory != null && !fileInfo.Directory.Exists) { fileInfo.Directory.Create(); } var modPackageTemplate = GetBundledResourcePath("ModificationPackage.AppxManifest.xml"); var logoPath = GetBundledResourcePath("Logo.png"); string manifestContent; using (var fs = File.OpenRead(modPackageTemplate)) { var xmlDoc = await XDocument.LoadAsync(fs, LoadOptions.None, cancellationToken : cancellation).ConfigureAwait(false); await this.PrepareModificationPackage(xmlDoc, config).ConfigureAwait(false); manifestContent = xmlDoc.ToString(SaveOptions.OmitDuplicateNamespaces); } if (action == ModificationPackageBuilderAction.Manifest) { using (var sourceStream = File.OpenRead(logoPath)) { // ReSharper disable once AssignNullToNotNullAttribute var assetsDirectory = Path.Combine(Path.GetDirectoryName(filePath), "Assets"); if (!Directory.Exists(assetsDirectory)) { Directory.CreateDirectory(assetsDirectory); } using (var targetStream = File.OpenWrite(Path.Combine(assetsDirectory, "Logo.png"))) { await sourceStream.CopyToAsync(targetStream, cancellation).ConfigureAwait(false); } } if (config.IncludeVfsFolders && config.ParentPackagePath != null) { // ReSharper disable once AssignNullToNotNullAttribute this.CopyVfsStructure(config.ParentPackagePath, new DirectoryInfo(Path.GetDirectoryName(filePath))); } if (config.IncludeFolder != null) { if (!config.IncludeFolder.Exists) { throw new DirectoryNotFoundException($"The directory folder '{config.IncludeFolder.FullName}' does not exist."); } // ReSharper disable once AssignNullToNotNullAttribute await this.CopyFolder(config.IncludeFolder, new DirectoryInfo(Path.GetDirectoryName(filePath)), cancellation).ConfigureAwait(false); } if (config.IncludeRegistry?.Exists == true) { if (!config.IncludeRegistry.Exists) { throw new FileNotFoundException( $"The file '{config.IncludeRegistry.FullName}' does not exist."); } // ReSharper disable once AssignNullToNotNullAttribute await this.CopyRegistry(config.IncludeRegistry, new DirectoryInfo(Path.GetDirectoryName(filePath))).ConfigureAwait(false); } await File.WriteAllTextAsync(filePath, manifestContent, Encoding.UTF8, cancellation).ConfigureAwait(false); return; } var tempFolder = Environment.ExpandEnvironmentVariables(@"%temp%\msix-hero-" + Guid.NewGuid().ToString("N").Substring(10)); try { using (var sourceStream = File.OpenRead(logoPath)) { var assetsFolder = Path.Combine(tempFolder, "Assets"); if (!Directory.Exists(assetsFolder)) { Directory.CreateDirectory(assetsFolder); } using (var targetStream = File.OpenWrite(Path.Combine(assetsFolder, "Logo.png"))) { await sourceStream.CopyToAsync(targetStream, cancellation).ConfigureAwait(false); } } if (config.IncludeVfsFolders && config.ParentPackagePath != null) { // ReSharper disable once AssignNullToNotNullAttribute this.CopyVfsStructure(config.ParentPackagePath, new DirectoryInfo(tempFolder)); } if (config.IncludeFolder != null) { if (!config.IncludeFolder.Exists) { throw new DirectoryNotFoundException($"The directory folder '{config.IncludeFolder.FullName}' does not exist."); } // ReSharper disable once AssignNullToNotNullAttribute await this.CopyFolder(config.IncludeFolder, new DirectoryInfo(tempFolder), cancellation).ConfigureAwait(false); } if (config.IncludeRegistry != null) { if (!config.IncludeRegistry.Exists) { throw new FileNotFoundException($"The file '{config.IncludeRegistry.FullName}' does not exist."); } await this.CopyRegistry(config.IncludeRegistry, new DirectoryInfo(tempFolder)).ConfigureAwait(false); } var manifestPath = new FileInfo(Path.Join(tempFolder, FileConstants.AppxManifestFile)); if (manifestPath.Exists) { manifestPath.Delete(); } else if (manifestPath.Directory?.Exists == false) { manifestPath.Directory.Create(); } await File.WriteAllTextAsync(manifestPath.FullName, manifestContent, Encoding.UTF8, cancellation).ConfigureAwait(false); await this.packer.PackFiles(tempFolder, filePath, 0, cancellation, progress).ConfigureAwait(false); } finally { try { if (Directory.Exists(tempFolder)) { Directory.Delete(tempFolder, true); } } catch (Exception e) { Logger.Warn(e, "Clean-up failed."); } } }
private async Task PrepareModificationPackage(XDocument template, ModificationPackageConfig config) { XNamespace nsUap4 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/4"; XNamespace nsUap6 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/6"; XNamespace nsRescap = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"; XNamespace nsRescap6 = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/6"; XNamespace nsBuild = "http://schemas.microsoft.com/developer/appx/2015/build"; XNamespace defaultNamespace = "http://schemas.microsoft.com/appx/manifest/foundation/windows10"; var root = template.Root; if (root == null) { root = new XElement(defaultNamespace + "Package"); template.Add(root); } else { defaultNamespace = root.GetDefaultNamespace(); } if (root.GetPrefixOfNamespace(nsUap4) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap4", nsUap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsUap6) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap6", nsUap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsRescap) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "rescap", nsRescap.NamespaceName)); } if (root.GetPrefixOfNamespace(nsRescap6) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "rescap6", nsRescap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsBuild) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "build", nsBuild.NamespaceName)); } var package = GetOrCreateNode(template, "Package", defaultNamespace); var dependencies = GetOrCreateNode(package, "Dependencies", defaultNamespace); var dependency = new XElement(nsUap4 + "MainPackageDependency"); dependencies.Add(dependency); var parentName = config.ParentName; var parentPublisher = config.ParentPublisher; if (string.IsNullOrEmpty(parentPublisher) || string.IsNullOrEmpty(parentName)) { IAppxFileReader reader = null; try { if (string.Equals(FileConstants.AppxManifestFile, Path.GetFileName(config.ParentPackagePath), StringComparison.OrdinalIgnoreCase)) { reader = new FileInfoFileReaderAdapter(config.ParentPackagePath); } else { reader = new ZipArchiveFileReaderAdapter(config.ParentPackagePath); } var manifestReader = new AppxManifestReader(); var read = await manifestReader.Read(reader).ConfigureAwait(false); if (string.IsNullOrEmpty(parentPublisher)) { parentPublisher = read.Publisher; } if (string.IsNullOrEmpty(parentName)) { parentName = read.Name; } } finally { reader?.Dispose(); } } dependency.SetAttributeValue("Name", parentName); dependency.SetAttributeValue("Publisher", parentPublisher); var identity = GetOrCreateNode(package, "Identity", defaultNamespace); identity.SetAttributeValue("Name", config.Name); identity.SetAttributeValue("Publisher", config.Publisher); var fixVersion = Version.Parse(config.Version); var major = fixVersion.Major; var minor = fixVersion.Minor; var build = fixVersion.Build; var revision = fixVersion.Revision; if (major < 0) { throw new FormatException("Invalid version format, major version is required."); } if (minor < 0) { throw new FormatException("Invalid version format, major version is required."); } if (revision < 0) { revision = 0; } if (build < 0) { build = 0; } identity.SetAttributeValue("Version", new Version(major, minor, build, revision).ToString(4)); var properties = GetOrCreateNode(package, "Properties", defaultNamespace); GetOrCreateNode(properties, "DisplayName", defaultNamespace).Value = config.DisplayName ?? "Modification Package Name"; GetOrCreateNode(properties, "PublisherDisplayName", defaultNamespace).Value = config.DisplayPublisher ?? "Modification Package Publisher Name"; GetOrCreateNode(properties, "Description", defaultNamespace).Value = "Modification Package for " + parentName; GetOrCreateNode(properties, "Logo", defaultNamespace).Value = "Assets\\Logo.png"; GetOrCreateNode(properties, "ModificationPackage", nsRescap6).Value = "true"; var branding = new MsixHeroBrandingInjector(); branding.Inject(template); }
protected override async Task <bool> Save(CancellationToken cancellationToken, IProgress <ProgressData> progress) { if (!this.IsValid) { return(false); } // ReSharper disable once NotAccessedVariable string selectedPath; switch (this.Create.CurrentValue) { case ModificationPackageBuilderAction.Manifest: if (!this.interactionService.SelectFolder(out selectedPath)) { return(false); } selectedPath = Path.Join(selectedPath, "AppxManifest.xml"); break; case ModificationPackageBuilderAction.Msix: case ModificationPackageBuilderAction.SignedMsix: if (!this.interactionService.SaveFile(FileDialogSettings.FromFilterString("MSIX Modification Packages|*.msix"), out selectedPath)) { return(false); } break; default: throw new ArgumentOutOfRangeException(); } var modificationPkgCreationRequest = new ModificationPackageConfig { DisplayName = this.DisplayName.CurrentValue, Name = this.Name.CurrentValue, Publisher = this.PublisherName.CurrentValue, DisplayPublisher = this.PublisherDisplayName.CurrentValue, Version = this.Version.CurrentValue, ParentName = this.ParentName.CurrentValue, ParentPublisher = this.ParentPublisher.CurrentValue, IncludeVfsFolders = this.IncludeVfsFolders.CurrentValue && this.IsIncludeVfsFoldersEnabled, IncludeFolder = this.IncludeFiles.CurrentValue && !string.IsNullOrEmpty(this.SourceFolder.CurrentValue) ? new DirectoryInfo(this.SourceFolder.CurrentValue) : null, IncludeRegistry = this.IncludeRegistry.CurrentValue && !string.IsNullOrEmpty(this.SourceRegistryFile.CurrentValue) ? new FileInfo(this.SourceRegistryFile.CurrentValue) : null, ParentPackagePath = this.SourcePath.CurrentValue }; await this.contentBuilder.Create(modificationPkgCreationRequest, selectedPath, this.Create.CurrentValue, cancellationToken, progress).ConfigureAwait(false); switch (this.Create.CurrentValue) { case ModificationPackageBuilderAction.Manifest: this.Result = selectedPath; break; case ModificationPackageBuilderAction.Msix: this.Result = selectedPath; break; case ModificationPackageBuilderAction.SignedMsix: var manager = await this.signingManagerFactory.GetProxyFor(SelfElevationLevel.AsInvoker, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); switch (this.TabCertificate.Store.CurrentValue) { case CertificateSource.Pfx: await manager.SignPackageWithPfx(selectedPath, true, this.TabCertificate.PfxPath.CurrentValue, this.TabCertificate.Password.CurrentValue, this.TabCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress).ConfigureAwait(false); break; case CertificateSource.Personal: await manager.SignPackageWithInstalled(selectedPath, true, this.TabCertificate.SelectedPersonalCertificate?.CurrentValue?.Model, this.TabCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress).ConfigureAwait(false); break; case CertificateSource.DeviceGuard: await manager.SignPackageWithDeviceGuardFromUi(selectedPath, this.TabCertificate.DeviceGuard.CurrentValue, this.TabCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress).ConfigureAwait(false); break; } this.Result = selectedPath; break; } return(true); }
public override async Task <int> Execute() { try { string file; ModificationPackageBuilderAction action; var config = new ModificationPackageConfig { Name = this.Verb.Name, Publisher = this.Verb.PublisherName, DisplayName = this.Verb.DisplayName, DisplayPublisher = this.Verb.PublisherDisplayName, Version = this.Verb.Version, IncludeVfsFolders = this.Verb.CopyFolderStructure }; switch (Path.GetExtension(this.Verb.OutputPath)?.ToLowerInvariant()) { case FileConstants.MsixExtension: case FileConstants.AppxExtension: { file = this.Verb.OutputPath; action = ModificationPackageBuilderAction.Msix; break; } default: { // ReSharper disable once AssignNullToNotNullAttribute file = Path.Combine(this.Verb.OutputPath, FileConstants.AppxManifestFile); action = ModificationPackageBuilderAction.Manifest; break; } } config.ParentPackagePath = this.Verb.ParentPackagePath; config.ParentName = this.Verb.ParentName; config.ParentPublisher = this.Verb.ParentPublisher; if (!string.IsNullOrEmpty(this.Verb.IncludeRegFile)) { config.IncludeRegistry = new FileInfo(this.Verb.IncludeRegFile); } if (!string.IsNullOrEmpty(this.Verb.IncludeFolder)) { config.IncludeFolder = new DirectoryInfo(this.Verb.IncludeFolder); } await this.modificationPackageBuilder.Create(config, file, action).ConfigureAwait(false); await this.Console.WriteSuccess($"Modification package created in {file}.").ConfigureAwait(false); return(StandardExitCodes.ErrorSuccess); } catch (Exception e) { Logger.Error(e); await this.Console.WriteError(e.Message).ConfigureAwait(false); return(StandardExitCodes.ErrorGeneric); } }