protected sealed override async Task <int> ExecuteOnExtractedPackage(string directoryPath)
        {
            var manifestFile = Path.Combine(directoryPath, FileConstants.AppxManifestFile);

            if (!File.Exists(manifestFile))
            {
                throw new FileNotFoundException($"Manifest file {manifestFile} does not exist.");
            }

            XDocument document;
            int       result;
            {
                await using var fs = File.OpenRead(manifestFile);
                document           = await XDocument.LoadAsync(fs, LoadOptions.None, CancellationToken.None).ConfigureAwait(false);

                var rootNode = document.Root;
                if (rootNode?.Name.LocalName != "Package")
                {
                    throw new FormatException("XML file must contain root <Package /> element.");
                }

                result = await this.ExecuteOnManifest(document).ConfigureAwait(false);

                var brandingInjector = new MsixHeroBrandingInjector();
                await brandingInjector.Inject(document).ConfigureAwait(false);
            }

            var writer = new AppxDocumentWriter(document);
            await writer.WriteAsync(manifestFile).ConfigureAwait(false);

            return(result);
        }
        public async Task TestSimpleInjection()
        {
            var manifest = this.PrepareMockManifest();

            var injector = new MsixHeroBrandingInjector();
            await injector.Inject(manifest).ConfigureAwait(false);

            Assert.NotNull(GetBuildVersion(manifest, "MsixHero"));
            Assert.NotNull(GetBuildVersion(manifest, "OperatingSystem"));
            Assert.NotNull(GetBuildVersion(manifest, "SignTool.exe"));
            Assert.NotNull(GetBuildVersion(manifest, "MakePri.exe"));
            Assert.NotNull(GetBuildVersion(manifest, "MakeAppx.exe"));
        }
Exemple #3
0
        public async Task PackFiles(
            string directory,
            string packagePath,
            AppxPackerOptions options           = 0,
            CancellationToken cancellationToken = default,
            IProgress <ProgressData> progress   = default)
        {
            var manifestFile = Path.Combine(directory, FileConstants.AppxManifestFile);

            if (!File.Exists(manifestFile))
            {
                throw new FileNotFoundException("Manifest file has not been found.", manifestFile);
            }

            XDocument xmlDocument;

            await using (var stream = File.OpenRead(manifestFile))
            {
                using var streamReader = new StreamReader(stream);
                xmlDocument            = await XDocument.LoadAsync(streamReader, LoadOptions.None, cancellationToken).ConfigureAwait(false);
            }

            var injector = new MsixHeroBrandingInjector();
            await injector.Inject(xmlDocument).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            await File.WriteAllTextAsync(manifestFile, xmlDocument.ToString(), Encoding.UTF8, cancellationToken).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            var compress = !options.HasFlag(AppxPackerOptions.NoCompress);
            var validate = !options.HasFlag(AppxPackerOptions.NoValidation);

            var allDirs = new DirectoryInfo(directory).EnumerateDirectories("*", SearchOption.AllDirectories);

            foreach (var emptyDir in allDirs.Where(d =>
                                                   !d.EnumerateFiles("*", SearchOption.TopDirectoryOnly).Any() &&
                                                   !d.EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Any()))
            {
                // this means we have an empty folder, which requires some special handling
                await File.WriteAllBytesAsync(Path.Combine(emptyDir.FullName, "GeneratedFile.txt"), Array.Empty <byte>(), cancellationToken).ConfigureAwait(false);
            }

            await new MakeAppxWrapper().PackPackageDirectory(directory, packagePath, compress, validate, cancellationToken, progress).ConfigureAwait(false);
        }
        public async Task TestOverridingDefault()
        {
            var existingValues = new Dictionary <string, string>
            {
                { "MsixHero", "91.0" },
                { "OperatingSystem", "92.0" },
                { "MakePri.exe", "93.0" },
                { "SignTool.exe", "94.0" },
                { "MakeAppx.exe", "95.0" },
            };

            var manifest = this.PrepareMockManifest(existingValues);

            var injector = new MsixHeroBrandingInjector();
            await injector.Inject(manifest);

            Assert.AreNotEqual("91.0", GetBuildVersion(manifest, "MsixHero"), "By default this value must be overridden.");
            Assert.AreEqual("92.0", GetBuildVersion(manifest, "OperatingSystem"), "By default this value must not be overridden.");
            Assert.AreEqual("93.0", GetBuildVersion(manifest, "MakePri.exe"), "By default this value must not be overridden.");
            Assert.AreNotEqual("94.0", GetBuildVersion(manifest, "SignTool.exe"), "By default this value must be overridden.");
            Assert.AreNotEqual("95.0", GetBuildVersion(manifest, "MakeAppx.exe"), "By default this value must be overridden.");
        }
        public async Task TestOverridingPreferExisting()
        {
            var existingValues = new Dictionary <string, string>
            {
                { "MsixHero", "91.0" },
                { "OperatingSystem", "92.0" },
                { "MakePri.exe", "93.0" },
                { "SignTool.exe", "94.0" },
                { "MakeAppx.exe", "95.0" },
            };

            var manifest = this.PrepareMockManifest(existingValues);

            var injector = new MsixHeroBrandingInjector();
            await injector.Inject(manifest, MsixHeroBrandingInjector.BrandingInjectorOverrideOption.PreferExisting);

            Assert.AreNotEqual("91.0", GetBuildVersion(manifest, "MsixHero"), "This value must be always overridden.");
            Assert.AreEqual("92.0", GetBuildVersion(manifest, "OperatingSystem"), "This value must not be overridden.");
            Assert.AreEqual("93.0", GetBuildVersion(manifest, "MakePri.exe"), "This value must not be overridden.");
            Assert.AreEqual("94.0", GetBuildVersion(manifest, "SignTool.exe"), "This value must not be overridden.");
            Assert.AreEqual("95.0", GetBuildVersion(manifest, "MakeAppx.exe"), "This value must not be overridden.");

            var existingIncompleteValues = new Dictionary <string, string>
            {
                { "SignTool.exe", "94.0" },
                { "MakeAppx.exe", "95.0" },
            };

            manifest = this.PrepareMockManifest(existingIncompleteValues);

            await injector.Inject(manifest, MsixHeroBrandingInjector.BrandingInjectorOverrideOption.PreferExisting);

            Assert.NotNull(GetBuildVersion(manifest, "MsixHero"));
            Assert.NotNull(GetBuildVersion(manifest, "OperatingSystem"));
            Assert.NotNull(GetBuildVersion(manifest, "MakePri.exe"));
            Assert.AreEqual("94.0", GetBuildVersion(manifest, "SignTool.exe"), "This value must not be overridden.");
            Assert.AreEqual("95.0", GetBuildVersion(manifest, "MakeAppx.exe"), "This value must not be overridden.");
        }
Exemple #6
0
        public async Task Pack(string directory, string packagePath, AppxPackerOptions options = 0, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = null)
        {
            if (!Directory.Exists(directory))
            {
                throw new DirectoryNotFoundException($"Folder {directory} does not exist.");
            }

            var fileInfo = new FileInfo(packagePath);

            if (fileInfo.Directory == null)
            {
                throw new ArgumentException($"File path {packagePath} is not supported.", nameof(packagePath));
            }

            if (!fileInfo.Directory.Exists)
            {
                fileInfo.Directory.Create();
            }

            var tempFile          = Path.GetTempFileName();
            var tempManifest      = Path.GetTempFileName();
            var tempAutoGenerated = Path.GetTempFileName();

            try
            {
                var inputDirectory = new DirectoryInfo(directory);

                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("[Files]");

                foreach (var item in inputDirectory.EnumerateFiles("*", SearchOption.AllDirectories))
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var relativePath = Path.GetRelativePath(directory, item.FullName);

                    if (string.IsNullOrEmpty(relativePath))
                    {
                        continue;
                    }

                    // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                    if (string.Equals(FileConstants.AppxManifestFile, relativePath, StringComparison.OrdinalIgnoreCase))
                    {
                        stringBuilder.AppendLine($"\"{tempManifest}\"\t\"{relativePath}\"");
                        item.CopyTo(tempManifest, true);
                        continue;
                    }

                    if (
                        string.Equals("AppxBlockMap.xml", relativePath, StringComparison.OrdinalIgnoreCase) ||
                        string.Equals("AppxSignature.p7x", relativePath, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    stringBuilder.AppendLine($"\"{item.FullName}\"\t\"{relativePath}\"");
                }

                var allDirs = inputDirectory.EnumerateDirectories("*", SearchOption.AllDirectories);
                foreach (var emptyDir in allDirs.Where(d =>
                                                       !d.EnumerateFiles("*", SearchOption.TopDirectoryOnly).Any() &&
                                                       !d.EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Any()))
                {
                    // this means we have an empty folder, which requires some special handling
                    if (new FileInfo(tempAutoGenerated).Length == 0)
                    {
                        await File.WriteAllBytesAsync(tempAutoGenerated, new byte[0], cancellationToken).ConfigureAwait(false);
                    }

                    var relativePath = Path.GetRelativePath(inputDirectory.FullName, emptyDir.FullName);
                    stringBuilder.AppendLine($"\"{tempAutoGenerated}\"\t\"{relativePath}\\GeneratedFile.txt\"");
                }

                await File.WriteAllTextAsync(tempFile, stringBuilder.ToString(), Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                var xmlDocument = XDocument.Load(tempManifest);
                var injector    = new MsixHeroBrandingInjector();
                injector.Inject(xmlDocument);

                cancellationToken.ThrowIfCancellationRequested();

                await File.WriteAllTextAsync(tempManifest, xmlDocument.ToString(), Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                var compress = !options.HasFlag(AppxPackerOptions.NoCompress);
                var validate = !options.HasFlag(AppxPackerOptions.NoValidation);

                await new MsixSdkWrapper().PackPackageFiles(tempFile, packagePath, compress, validate, cancellationToken, progress).ConfigureAwait(false);
            }
            finally
            {
                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }

                if (File.Exists(tempManifest))
                {
                    File.Delete(tempManifest);
                }

                if (File.Exists(tempAutoGenerated))
                {
                    File.Delete(tempAutoGenerated);
                }
            }
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        public async Task Pack(
            string directory,
            string packagePath,
            IDictionary <string, string> extraFiles,
            AppxPackerOptions options           = 0,
            CancellationToken cancellationToken = default,
            IProgress <ProgressData> progress   = null)
        {
            if (!Directory.Exists(directory))
            {
                throw new DirectoryNotFoundException($"Folder {directory} does not exist.");
            }

            var fileInfo = new FileInfo(packagePath);

            if (fileInfo.Directory == null)
            {
                throw new ArgumentException($"File path {packagePath} is not supported.", nameof(packagePath));
            }

            if (!fileInfo.Directory.Exists)
            {
                fileInfo.Directory.Create();
            }

            var tempFile             = Path.GetTempFileName();
            var tempManifestFilePath = Path.GetTempFileName();
            var tempAutoGenerated    = Path.GetTempFileName();

            try
            {
                var inputDirectory = new DirectoryInfo(directory);

                var listBuilder = new PackageFileListBuilder();

                foreach (var item in inputDirectory.EnumerateFiles("*", SearchOption.AllDirectories))
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var relativePath = Path.GetRelativePath(directory, item.FullName);

                    if (string.IsNullOrEmpty(relativePath))
                    {
                        continue;
                    }

                    // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                    if (string.Equals(FileConstants.AppxManifestFile, relativePath, StringComparison.OrdinalIgnoreCase))
                    {
                        listBuilder.AddManifest(tempManifestFilePath);
                        item.CopyTo(tempManifestFilePath, true);
                        continue;
                    }

                    listBuilder.AddFile(item.FullName, relativePath);
                }

                if (extraFiles != null)
                {
                    foreach (var item in extraFiles)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        if (string.Equals(Path.GetFileName(item.Key), FileConstants.AppxManifestFile, StringComparison.OrdinalIgnoreCase))
                        {
                            tempManifestFilePath = item.Value;
                            listBuilder.AddFile(item.Value, item.Key);
                        }
                        else
                        {
                            listBuilder.AddFile(item.Value, item.Key);
                        }
                    }
                }

                var allDirs = inputDirectory.EnumerateDirectories("*", SearchOption.AllDirectories);
                foreach (var emptyDir in allDirs.Where(d =>
                                                       !d.EnumerateFiles("*", SearchOption.TopDirectoryOnly).Any() &&
                                                       !d.EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Any()))
                {
                    // this means we have an empty folder, which requires some special handling
                    if (new FileInfo(tempAutoGenerated).Length == 0)
                    {
                        await File.WriteAllBytesAsync(tempAutoGenerated, Array.Empty <byte>(), cancellationToken).ConfigureAwait(false);
                    }

                    var relativePath = Path.GetRelativePath(inputDirectory.FullName, emptyDir.FullName);
                    listBuilder.AddFile(tempAutoGenerated, $"{relativePath}\\GeneratedFile.txt\"");
                }

                await File.WriteAllTextAsync(tempFile, listBuilder.ToString(), Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                XDocument xmlManifestDocument;
                await using (var tempManifestStream = File.OpenRead(tempManifestFilePath))
                {
                    using var tempManifestReader = new StreamReader(tempManifestStream);
                    xmlManifestDocument          = await XDocument.LoadAsync(tempManifestReader, LoadOptions.None, cancellationToken).ConfigureAwait(false);

                    var injector = new MsixHeroBrandingInjector();
                    await injector.Inject(xmlManifestDocument).ConfigureAwait(false);
                }

                cancellationToken.ThrowIfCancellationRequested();
                var appxWriter = new AppxDocumentWriter(xmlManifestDocument);
                await appxWriter.WriteAsync(tempManifestFilePath).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested();

                var compress = !options.HasFlag(AppxPackerOptions.NoCompress);
                var validate = !options.HasFlag(AppxPackerOptions.NoValidation);

                await new MakeAppxWrapper().PackPackageFiles(tempFile, packagePath, compress, validate, cancellationToken, progress).ConfigureAwait(false);
            }
            finally
            {
                if (File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }

                if (File.Exists(tempManifestFilePath))
                {
                    File.Delete(tempManifestFilePath);
                }

                if (File.Exists(tempAutoGenerated))
                {
                    File.Delete(tempAutoGenerated);
                }
            }
        }
        private async Task AdjustManifest(XDocument template, AppxManifestCreatorOptions config, DirectoryInfo baseDirectory, string[] entryPoints)
        {
            XNamespace nsUap = "http://schemas.microsoft.com/appx/manifest/uap/windows10";
            XNamespace nsUap4 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/4";
            XNamespace nsUap6 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/6";
            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();
            }

            // Add capability
            var addCapability = new AddCapability("runFullTrust");
            var capabilityExecutor = new AddCapabilityExecutor(template);
            await capabilityExecutor.Execute(addCapability).ConfigureAwait(false);

            // Set identity
            var setIdentity = new SetPackageIdentity
            {
                Name = config.PackageName,
                Publisher = config.PublisherName,
                ProcessorArchitecture = config.PackageArchitecture.ToString("G").ToLowerInvariant()
            };

            var major = config.Version.Major;
            var minor = config.Version.Minor;
            var build = config.Version.Build;
            var revision = config.Version.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;
            }

            setIdentity.Version = new Version(major, minor, build, revision).ToString();
            var executor = new SetPackageIdentityExecutor(template);
            await executor.Execute(setIdentity).ConfigureAwait(false);

            // Add namespaces (legacy)
            if (root.GetPrefixOfNamespace(nsUap) == null)
            {
                root.Add(new XAttribute(XNamespace.Xmlns + "uap", nsUap.NamespaceName));
            }

            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));
            }
            
            var package = GetOrCreateNode(template, "Package", defaultNamespace);
            
            var properties = GetOrCreateNode(package, "Properties", defaultNamespace);
            GetOrCreateNode(properties, "DisplayName", defaultNamespace).Value = config.PackageDisplayName ?? config.PackageName ?? "DisplayName";
            GetOrCreateNode(properties, "Description", defaultNamespace).Value = config.PackageDisplayName ?? config.PackageName ?? "Description";
            GetOrCreateNode(properties, "PublisherDisplayName", defaultNamespace).Value = config.PublisherDisplayName ?? config.PublisherName ?? "Publisher";
            GetOrCreateNode(properties, "Logo", defaultNamespace).Value = "Assets\\Logo.png";
            var applicationsNode = GetOrCreateNode(package, "Applications", defaultNamespace);

            var usedNames = new HashSet<string>();
            foreach (var item in entryPoints)
            {
                var applicationNode = this.CreateApplicationNodeFromExe(baseDirectory, item);
                applicationsNode.Add(applicationNode);

                var idCandidate = Regex.Replace(Path.GetFileNameWithoutExtension(item), "[^a-zA-z0-9_]+", string.Empty);
                if (!usedNames.Add(idCandidate))
                {
                    var index = 1;
                    var baseIdCandidate = idCandidate;
                    while (!usedNames.Add(baseIdCandidate + "_" + index))
                    {
                        index++;
                    }

                    idCandidate = baseIdCandidate + "_" + index;
                }

                applicationNode.SetAttributeValue("Id", idCandidate);
            }

            var branding = new MsixHeroBrandingInjector();
            await branding.Inject(template, MsixHeroBrandingInjector.BrandingInjectorOverrideOption.PreferIncoming).ConfigureAwait(false);
        }
        protected override async Task <bool> Save(CancellationToken cancellationToken, IProgress <ProgressData> progress)
        {
            var temporaryFiles = new List <string>();

            try
            {
                var fileListBuilder = new PackageFileListBuilder();
                fileListBuilder.AddDirectory(this.InputPath.CurrentValue, true, null);

                if (this.PrePackOptions != null && !this.PrePackOptions.ManifestPresent)
                {
                    if (!this.PrePackOptions.CanConvert)
                    {
                        throw new InvalidOperationException("The selected folder does not contain a manifest file and any executable files. It cannot be packed to MSIX format.");
                    }

                    if (!string.IsNullOrEmpty(this.InputPath.CurrentValue))
                    {
                        progress.Report(new ProgressData(0, "Creating manifest file..."));
                        var options = new AppxManifestCreatorOptions
                        {
                            CreateLogo         = this.PrePackOptions.CreateLogo,
                            EntryPoints        = this.PrePackOptions.EntryPoints.Where(e => e.IsChecked).Select(e => e.Value).ToArray(),
                            PackageDisplayName = Path.GetFileName(this.InputPath.CurrentValue),
                            RegistryFile       = this.PrePackOptions.SelectedRegistry?.FilePath == null ? null : new FileInfo(this.PrePackOptions.SelectedRegistry.FilePath)
                        };

                        // ReSharper disable once AssignNullToNotNullAttribute
                        await foreach (var result in this.manifestCreator.CreateManifestForDirectory(new DirectoryInfo(this.InputPath.CurrentValue), options, cancellationToken).ConfigureAwait(false))
                        {
                            temporaryFiles.Add(result.SourcePath);

                            if (result.PackageRelativePath == null)
                            {
                                continue;
                            }

                            fileListBuilder.AddFile(result.SourcePath, result.PackageRelativePath);
                        }
                    }
                }

                using var progressWrapper = new WrappedProgress(progress);
                var progress1 = progressWrapper.GetChildProgress(50);
                var progress2 = this.Sign.CurrentValue ? progressWrapper.GetChildProgress(30) : null;

                var tempFileList = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".list");
                temporaryFiles.Add(tempFileList);

                var tempManifestPath = Path.Combine(Path.GetTempPath(), "AppxManifest-" + Guid.NewGuid().ToString("N") + ".xml");
                temporaryFiles.Add(tempManifestPath);

                var srcManifest = fileListBuilder.GetManifestSourcePath();
                if (srcManifest == null || !File.Exists(srcManifest))
                {
                    throw new InvalidOperationException("The selected folder cannot be packed because it has no manifest, and MSIX Hero was unable to create one. A manifest can be only created if the selected folder contains any executable file.");
                }

                // Copy manifest to a temporary file
                var injector = new MsixHeroBrandingInjector();
                await using (var manifestStream = File.OpenRead(fileListBuilder.GetManifestSourcePath()))
                {
                    var xml = await XDocument.LoadAsync(manifestStream, LoadOptions.None, cancellationToken).ConfigureAwait(false);

                    await injector.Inject(xml).ConfigureAwait(false);

                    await File.WriteAllTextAsync(tempManifestPath, xml.ToString(SaveOptions.None), cancellationToken);

                    fileListBuilder.AddManifest(tempManifestPath);
                }

                await File.WriteAllTextAsync(tempFileList, fileListBuilder.ToString(), cancellationToken).ConfigureAwait(false);

                var sdk = new MakeAppxWrapper();
                await sdk.PackPackageFiles(tempFileList, this.OutputPath.CurrentValue, this.Compress.CurrentValue, this.Validate.CurrentValue, cancellationToken, progress1).ConfigureAwait(false);

                if (this.Sign.CurrentValue)
                {
                    var manager = await this.signingManagerFactory.GetProxyFor(SelfElevationLevel.HighestAvailable, cancellationToken).ConfigureAwait(false);

                    string timeStampUrl;
                    switch (this.SelectedCertificate.TimeStampSelectionMode.CurrentValue)
                    {
                    case TimeStampSelectionMode.None:
                        timeStampUrl = null;
                        break;

                    case TimeStampSelectionMode.Auto:
                        timeStampUrl = "auto";
                        break;

                    case TimeStampSelectionMode.Url:
                        timeStampUrl = this.SelectedCertificate.TimeStamp.CurrentValue;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (this.SelectedCertificate.Store.CurrentValue)
                    {
                    case CertificateSource.Personal:
                        await manager.SignPackageWithInstalled(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.SelectedPersonalCertificate.CurrentValue?.Model, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.Pfx:
                        await manager.SignPackageWithPfx(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.PfxPath.CurrentValue, this.SelectedCertificate.Password.CurrentValue, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.DeviceGuard:
                        await manager.SignPackageWithDeviceGuardFromUi(this.OutputPath.CurrentValue, this.SelectedCertificate.DeviceGuard.CurrentValue, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;
                    }
                }

                if (this.RemoveDirectory.CurrentValue)
                {
                    ExceptionGuard.Guard(() => Directory.Delete(this.InputPath.CurrentValue, true));
                }

                return(true);
            }
            finally
            {
                foreach (var tempFile in temporaryFiles)
                {
                    ExceptionGuard.Guard(() => File.Delete(tempFile));
                }
            }
        }
        public override async Task <int> Execute()
        {
            try
            {
                await this.OnBegin().ConfigureAwait(false);

                if (!File.Exists(this.package) && !Directory.Exists(this.package))
                {
                    await this.Console.WriteError($"The path {this.package} does not exist.");

                    return(10);
                }

                var validation = await this.Validate().ConfigureAwait(false);

                if (validation != 0)
                {
                    return(validation);
                }

                if (File.Exists(this.package))
                {
                    // This is a file...
                    if (string.Equals(Path.GetFileName(this.package), FileConstants.AppxManifestFile, StringComparison.OrdinalIgnoreCase))
                    {
                        // .. a manifest file
                        var result = await this.ExecuteOnExtractedPackage(Path.GetDirectoryName(this.package)).ConfigureAwait(false);

                        await this.OnFinished().ConfigureAwait(false);

                        return(result);
                    }

                    if (string.Equals(".msix", Path.GetExtension(this.package)))
                    {
                        // .. an MSIX package
                        var msixMgr    = new MakeAppxWrapper();
                        var tempFolder = Path.Combine(Path.GetTempPath(), "msixhero-" + Guid.NewGuid().ToString("N").Substring(0, 8));

                        try
                        {
                            await this.Console.WriteInfo($"Opening {Path.GetFileName(this.package)}...").ConfigureAwait(false);

                            // 1) Unpack first
                            await msixMgr.UnpackPackage(this.package, tempFolder, false).ConfigureAwait(false);

                            // 2) Make edit
                            var result = await this.ExecuteOnExtractedPackage(tempFolder).ConfigureAwait(false);

                            if (result != StandardExitCodes.ErrorSuccess)
                            {
                                await this.Console.WriteWarning($"The package has not been updated due to previous errors.").ConfigureAwait(false);

                                return(result);
                            }

                            // 3) Add branding
                            XDocument document;
                            await using (var fs = File.OpenRead(Path.Combine(tempFolder, "AppxManifest.xml")))
                            {
                                document = await XDocument.LoadAsync(fs, LoadOptions.None, CancellationToken.None).ConfigureAwait(false);
                            }

                            var inject = new MsixHeroBrandingInjector();
                            await inject.Inject(document).ConfigureAwait(false);

                            var writer = new AppxDocumentWriter(document);
                            await writer.WriteAsync(Path.Combine(tempFolder, "AppxManifest.xml")).ConfigureAwait(false);

                            if (result == StandardExitCodes.ErrorSuccess)
                            {
                                await this.Console.WriteInfo($"Saving {Path.GetFileName(this.package)}...").ConfigureAwait(false);

                                // 3) Pack again
                                await msixMgr.PackPackageDirectory(tempFolder, this.package, false, false);

                                await this.OnFinished().ConfigureAwait(false);
                            }

                            return(result);
                        }
                        finally
                        {
                            if (Directory.Exists(tempFolder))
                            {
                                ExceptionGuard.Guard(() => Directory.Delete(tempFolder, true));
                            }
                        }
                    }
                }
                else if (Directory.Exists(this.package))
                {
                    // this is extracted directory
                    var manifestPath = Path.Combine(this.package, FileConstants.AppxManifestFile);
                    if (File.Exists(manifestPath))
                    {
                        var result = await this.ExecuteOnExtractedPackage(this.package).ConfigureAwait(false);

                        XDocument document;
                        await using (var fs = File.OpenRead(manifestPath))
                        {
                            document = await XDocument.LoadAsync(fs, LoadOptions.None, CancellationToken.None).ConfigureAwait(false);
                        }

                        var inject = new MsixHeroBrandingInjector();
                        await inject.Inject(document).ConfigureAwait(false);

                        var writer = new AppxDocumentWriter(document);
                        await writer.WriteAsync(manifestPath).ConfigureAwait(false);

                        await this.OnFinished().ConfigureAwait(false);

                        return(result);
                    }
                }

                await this.Console.WriteError($"The path {this.package} is neither a directory with extracted MSIX, an .MSIX package or a manifest file.").ConfigureAwait(false);

                return(StandardExitCodes.ErrorParameter);
            }
            catch (Exception e)
            {
                await this.Console.WriteError(e.Message).ConfigureAwait(false);

                return(StandardExitCodes.ErrorGeneric);
            }
        }