Exemple #1
0
        public static HashSet <CompDBXmlClass.CompDB> GetCompDBsFromUUPFiles(string UUPPath)
        {
            HashSet <CompDBXmlClass.CompDB> compDBs = new HashSet <CompDBXmlClass.CompDB>();

            try
            {
                if (Directory.EnumerateFiles(UUPPath, "*aggregatedmetadata*").Count() > 0)
                {
                    using (CabinetHandler cabinet = new CabinetHandler(File.OpenRead(Directory.EnumerateFiles(UUPPath, "*aggregatedmetadata*").First())))
                    {
                        foreach (var file in cabinet.Files.Where(x => x.EndsWith(".xml.cab", StringComparison.InvariantCultureIgnoreCase)))
                        {
                            try
                            {
                                using (CabinetHandler cabinet2 = new CabinetHandler(cabinet.OpenFile(file)))
                                {
                                    string xmlfile = cabinet2.Files.First();
                                    using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
                                    {
                                        compDBs.Add(CompDBXmlClass.DeserializeCompDB(xmlstream));
                                    }
                                }
                            }
                            catch { }
                        }
                    }
                }
                else
                {
                    IEnumerable <string> files = Directory.EnumerateFiles(UUPPath).Select(x => Path.GetFileName(x)).Where(x => x.EndsWith(".xml.cab", StringComparison.InvariantCultureIgnoreCase));

                    foreach (var file in files)
                    {
                        try
                        {
                            using (CabinetHandler cabinet2 = new CabinetHandler(File.OpenRead(Path.Combine(UUPPath, file))))
                            {
                                string xmlfile = cabinet2.Files.First();
                                using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
                                {
                                    compDBs.Add(CompDBXmlClass.DeserializeCompDB(xmlstream));
                                }
                            }
                        }
                        catch { }
                    }
                }
            }
            catch { }

            return(compDBs);
        }
Exemple #2
0
        private static string ConvertCABToESD(string cabFilePath, ProgressCallback progressCallback, int progressoffset, int progressscale)
        {
            string esdFilePath = Path.ChangeExtension(cabFilePath, "esd");

            if (File.Exists(esdFilePath))
            {
                return(esdFilePath);
            }

            progressCallback?.Invoke(Common.ProcessPhase.PreparingFiles, false, progressoffset, "Unpacking...");

            var tmp = Path.GetTempFileName();

            File.Delete(tmp);

            string tempExtractionPath = Path.Combine(tmp, "Package");
            int    progressScaleHalf  = progressscale / 2;

            void ProgressCallback(int percent, string file)
            {
                progressCallback?.Invoke(Common.ProcessPhase.PreparingFiles, false, progressoffset + (int)Math.Round((double)percent / 100 * progressScaleHalf), "Unpacking " + file + "...");
            };

            CabinetHandler.ExpandFiles(cabFilePath, tempExtractionPath, ProgressCallback);

            void callback(string Operation, int ProgressPercentage, bool IsIndeterminate)
            {
                progressCallback?.Invoke(Common.ProcessPhase.PreparingFiles, IsIndeterminate, progressoffset + progressScaleHalf + (int)Math.Round((double)ProgressPercentage / 100 * progressScaleHalf), Operation);
            };

            bool result = imagingInterface.CaptureImage(esdFilePath, "Metadata ESD", null, null, tempExtractionPath, compressionType: WimCompressionType.None, PreserveACL: false, progressCallback: callback);

            Directory.Delete(tmp, true);

            if (!result)
            {
                return(null);
            }

            return(esdFilePath);
        }
        public async static Task <string> GetBuildStringAsync(this UpdateData update)
        {
            try
            {
                CExtendedUpdateInfoXml.File deploymentCab = null;

                foreach (var file in update.Xml.Files.File)
                {
                    if (file.FileName.EndsWith("desktopdeployment.cab", StringComparison.InvariantCultureIgnoreCase))
                    {
                        deploymentCab = file;
                        break;
                    }
                }

                if (deploymentCab == null)
                {
                    return(null);
                }

                var fileDownloadInfo = await FE3Handler.GetFileUrl(update, deploymentCab.Digest);

                if (fileDownloadInfo == null)
                {
                    return(null);
                }

                string deploymentCabTemp = Path.GetTempFileName();
                await client.DownloadFileTaskAsync(new Uri(fileDownloadInfo.DownloadUrl), deploymentCabTemp);

                if (fileDownloadInfo.IsEncrypted)
                {
                    if (!fileDownloadInfo.Decrypt(deploymentCabTemp, deploymentCabTemp + ".decrypted"))
                    {
                        return(null);
                    }
                    File.Delete(deploymentCabTemp);
                    File.Move(deploymentCabTemp + ".decrypted", deploymentCabTemp);
                }

                string result = null;

                try
                {
                    using (var cabinet = new CabinetHandler(File.OpenRead(deploymentCabTemp)))
                    {
                        foreach (var file in cabinet.Files)
                        {
                            if (file.Equals("UpdateAgent.dll", StringComparison.InvariantCultureIgnoreCase))
                            {
                                byte[] buffer;
                                using (var dllstream = cabinet.OpenFile(file))
                                {
                                    buffer = new byte[dllstream.Length];
                                    await dllstream.ReadAsync(buffer, 0, (int)dllstream.Length);
                                }
                                result = GetBuildStringFromUpdateAgent(buffer);
                                break;
                            }
                        }
                    }
                }
                catch { }

                var reportedBuildNumberFromService = update.Xml.ExtendedProperties.ReleaseVersion.Split('.')[2];
                if (!string.IsNullOrEmpty(result) && result.Count(x => x == '.') >= 2)
                {
                    var elements = result.Split('.');
                    elements[2] = reportedBuildNumberFromService;
                    result      = string.Join(".", elements);
                }

                File.Delete(deploymentCabTemp);
                return(result);
            }
            catch
            {
                return(null);
            }
        }
        private static async Task <HashSet <CompDBXmlClass.CompDB> > GetCompDBs(UpdateData update)
        {
            HashSet <CompDBXmlClass.CompDB>       neutralCompDB = new HashSet <CompDBXmlClass.CompDB>();
            HashSet <CExtendedUpdateInfoXml.File> metadataCabs  = new HashSet <CExtendedUpdateInfoXml.File>();

            foreach (CExtendedUpdateInfoXml.File file in update.Xml.Files.File)
            {
                if (file.PatchingType.Equals("metadata", StringComparison.InvariantCultureIgnoreCase))
                {
                    metadataCabs.Add(file);
                }
            }

            if (metadataCabs.Count == 0)
            {
                return(neutralCompDB);
            }

            if (metadataCabs.Count == 1 && metadataCabs.First().FileName.Contains("metadata", StringComparison.InvariantCultureIgnoreCase))
            {
                // This is the new metadata format where all metadata is in a single cab

                if (string.IsNullOrEmpty(update.CachedMetadata))
                {
                    var fileDownloadInfo = await FE3Handler.GetFileUrl(update, metadataCabs.First().Digest);

                    if (fileDownloadInfo == null)
                    {
                        return(neutralCompDB);
                    }

                    string metadataCabTemp = Path.GetTempFileName();

                    // Download the file
                    await client.DownloadFileTaskAsync(new Uri(fileDownloadInfo.DownloadUrl), metadataCabTemp);

                    if (fileDownloadInfo.IsEncrypted)
                    {
                        if (!fileDownloadInfo.Decrypt(metadataCabTemp, metadataCabTemp + ".decrypted"))
                        {
                            return(neutralCompDB);
                        }
                        metadataCabTemp += ".decrypted";
                    }

                    update.CachedMetadata = metadataCabTemp;
                }

                using (CabinetHandler cabinet = new CabinetHandler(File.OpenRead(update.CachedMetadata)))
                {
                    foreach (string file in cabinet.Files)
                    {
                        using (CabinetHandler cabinet2 = new CabinetHandler(cabinet.OpenFile(file)))
                        {
                            string xmlfile = cabinet2.Files.First();

                            using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
                            {
                                neutralCompDB.Add(CompDBXmlClass.DeserializeCompDB(xmlstream));
                            }
                        }
                    }
                }
            }
            else
            {
                // This is the old format, each cab is a file in WU
                foreach (CExtendedUpdateInfoXml.File file in metadataCabs)
                {
                    var fileDownloadInfo = await FE3Handler.GetFileUrl(update, file.Digest);

                    if (fileDownloadInfo == null)
                    {
                        continue;
                    }

                    string metadataCabTemp = Path.GetTempFileName();

                    // Download the file
                    await client.DownloadFileTaskAsync(new Uri(fileDownloadInfo.DownloadUrl), metadataCabTemp);

                    if (fileDownloadInfo.IsEncrypted)
                    {
                        if (!fileDownloadInfo.Decrypt(metadataCabTemp, metadataCabTemp + ".decrypted"))
                        {
                            continue;
                        }
                        metadataCabTemp += ".decrypted";
                    }

                    update.CachedMetadata = metadataCabTemp;

                    using (CabinetHandler cabinet2 = new CabinetHandler(File.OpenRead(update.CachedMetadata)))
                    {
                        string xmlfile = cabinet2.Files.First();
                        using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
                        {
                            neutralCompDB.Add(CompDBXmlClass.DeserializeCompDB(xmlstream));
                        }
                    }
                }
            }

            return(neutralCompDB);
        }
Exemple #5
0
        /*private static void ProvisionMissingApps()
         * {
         *  string SourceEdition = "Professional";
         *  string TargetEdition = "PPIPro";
         *  string UUPPath = @"C:\Users\Gus\Downloads\19635.1_amd64_en-us_multi_6d892fb5\UUPs";
         *
         *  CompDBXmlClass.CompDB neutralCompDB = null;
         *
         *  if (Directory.EnumerateFiles(UUPPath, "*aggregatedmetadata*").Count() > 0)
         *  {
         *      using (CabinetHandler cabinet = new CabinetHandler(File.OpenRead(Directory.EnumerateFiles(UUPPath, "*aggregatedmetadata*").First())))
         *      {
         *          IEnumerable<string> potentialNeutralFiles = cabinet.Files.Where(x =>
         *          x.ToLower().Contains($"desktoptargetcompdb_neutral"));
         *
         *          if (potentialNeutralFiles.Count() == 0)
         *              goto exit;
         *
         *          using (CabinetHandler cabinet2 = new CabinetHandler(cabinet.OpenFile(potentialNeutralFiles.First())))
         *          {
         *              string xmlfile = cabinet2.Files.First();
         *              using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
         *              {
         *                  neutralCompDB = CompDBXmlClass.DeserializeCompDB(xmlstream);
         *              }
         *          }
         *      }
         *  }
         *  else
         *  {
         *      IEnumerable<string> files = Directory.EnumerateFiles(UUPPath).Select(x => Path.GetFileName(x));
         *
         *      IEnumerable<string> potentialNeutralFiles = files.Where(x =>
         *             x.ToLower().Contains($"desktoptargetcompdb_neutral"));
         *
         *      if (potentialNeutralFiles.Count() == 0)
         *          goto exit;
         *
         *      using (CabinetHandler cabinet2 = new CabinetHandler(File.OpenRead(Path.Combine(UUPPath, potentialNeutralFiles.First()))))
         *      {
         *          string xmlfile = cabinet2.Files.First();
         *          using (Stream xmlstream = cabinet2.OpenFile(xmlfile))
         *          {
         *              neutralCompDB = CompDBXmlClass.DeserializeCompDB(xmlstream);
         *          }
         *      }
         *  }
         *
         *  var apppackages = neutralCompDB.Features.Feature.First(x => x.FeatureID == "BaseNeutral").Packages.Package.Select(x => x.ID.Split('_').Last()).Where(x => x.StartsWith("Microsoft.ModernApps.", StringComparison.InvariantCultureIgnoreCase));
         *
         *  bool sourceneedsclientpack = !SourceEdition.StartsWith("enterpriseg", StringComparison.InvariantCultureIgnoreCase) && !SourceEdition.StartsWith("ppipro", StringComparison.InvariantCultureIgnoreCase);
         *  bool sourceneedsclientnpack = SourceEdition.EndsWith("n", StringComparison.InvariantCultureIgnoreCase) || SourceEdition.EndsWith("neval", StringComparison.InvariantCultureIgnoreCase);
         *
         *  bool targetneedsclientpack = !TargetEdition.StartsWith("enterpriseg", StringComparison.InvariantCultureIgnoreCase) && !SourceEdition.StartsWith("ppipro", StringComparison.InvariantCultureIgnoreCase);
         *  bool targetneedsclientnpack = TargetEdition.EndsWith("n", StringComparison.InvariantCultureIgnoreCase) || TargetEdition.EndsWith("neval", StringComparison.InvariantCultureIgnoreCase);
         *
         *  List<string> SourceEditionApps = new List<string>();
         *  List<string> TargetEditionApps = new List<string>();
         *
         *  var potentialSourceEditionAppPackages = apppackages.Where(x => x.ToLower().Contains(SourceEdition.ToLower().TrimEnd('n')));
         *  if (potentialSourceEditionAppPackages.Count() > 0)
         *  {
         *      var apppackage = potentialSourceEditionAppPackages.First();
         *      string[] entries;
         *      imagingInterface.EnumerateFiles(Path.Combine(UUPPath, apppackage + ".esd"), 1, "", out entries);
         *      foreach (var entry in entries)
         *      {
         *          if (entry.ToLower() != "$filehashes$.dat")
         *          {
         *              string[] entries2;
         *              imagingInterface.EnumerateFiles(Path.Combine(UUPPath, apppackage + ".esd"), 1, entry, out entries2);
         *              var pkg = entries2.Where(x => x.ToLower() != "appxsignature.p7x" && x.ToLower() != "appxblockmap.xml" && x.ToLower() != "appxmetadata").First();
         *              var newpkg = pkg.Split('_')[0] + "_" + pkg.Split('_')[1] + "_neutral_~_" + pkg.Split('_')[4];
         *              bool isbundle = entries2.Any(x => x.ToLower() == "appxmetadata");
         *              SourceEditionApps.Add($"{entry}|{pkg}|{pkg.Split('_')[0]}|{newpkg}|{isbundle}");
         *          }
         *      }
         *  }
         *
         *  if (sourceneedsclientpack)
         *  {
         *      string package = "microsoft.modernapps.client.all.esd";
         *      if (sourceneedsclientnpack)
         *      {
         *          package = "microsoft.modernapps.clientn.all.esd";
         *      }
         *
         *      string[] entries;
         *      imagingInterface.EnumerateFiles(Path.Combine(UUPPath, package), 1, "", out entries);
         *      foreach (var entry in entries)
         *      {
         *          if (entry.ToLower() != "$filehashes$.dat")
         *          {
         *              string[] entries2;
         *              imagingInterface.EnumerateFiles(Path.Combine(UUPPath, package), 1, entry, out entries2);
         *              var pkg = entries2.Where(x => x.ToLower() != "appxsignature.p7x" && x.ToLower() != "appxblockmap.xml" && x.ToLower() != "appxmetadata").First();
         *              var newpkg = pkg.Split('_')[0] + "_" + pkg.Split('_')[1] + "_neutral_~_" + pkg.Split('_')[4];
         *              bool isbundle = entries2.Any(x => x.ToLower() == "appxmetadata");
         *              SourceEditionApps.Add($"{entry}|{pkg}|{pkg.Split('_')[0]}|{newpkg}|{isbundle}");
         *          }
         *      }
         *  }
         *
         *  var potentialTargetEditionAppPackages = apppackages.Where(x => x.ToLower().Contains(TargetEdition.ToLower().TrimEnd('n')));
         *  if (potentialTargetEditionAppPackages.Count() > 0)
         *  {
         *      var apppackage = potentialTargetEditionAppPackages.First();
         *      string[] entries;
         *      imagingInterface.EnumerateFiles(Path.Combine(UUPPath, apppackage + ".esd"), 1, "", out entries);
         *      foreach (var entry in entries)
         *      {
         *          if (entry.ToLower() != "$filehashes$.dat")
         *          {
         *              string[] entries2;
         *              imagingInterface.EnumerateFiles(Path.Combine(UUPPath, apppackage + ".esd"), 1, entry, out entries2);
         *              var pkg = entries2.Where(x => x.ToLower() != "appxsignature.p7x" && x.ToLower() != "appxblockmap.xml" && x.ToLower() != "appxmetadata").First();
         *              var newpkg = pkg.Split('_')[0] + "_" + pkg.Split('_')[1] + "_neutral_~_" + pkg.Split('_')[4];
         *              bool isbundle = entries2.Any(x => x.ToLower() == "appxmetadata");
         *              TargetEditionApps.Add($"{entry}|{pkg}|{pkg.Split('_')[0]}|{newpkg}|{isbundle}");
         *          }
         *      }
         *  }
         *
         *  if (targetneedsclientpack)
         *  {
         *      string package = "microsoft.modernapps.client.all.esd";
         *      if (targetneedsclientnpack)
         *      {
         *          package = "microsoft.modernapps.clientn.all.esd";
         *      }
         *
         *      string[] entries;
         *      imagingInterface.EnumerateFiles(Path.Combine(UUPPath, package), 1, "", out entries);
         *      foreach (var entry in entries)
         *      {
         *          if (entry.ToLower() != "$filehashes$.dat")
         *          {
         *              string[] entries2;
         *              imagingInterface.EnumerateFiles(Path.Combine(UUPPath, package), 1, entry, out entries2);
         *              var pkg = entries2.Where(x => x.ToLower() != "appxsignature.p7x" && x.ToLower() != "appxblockmap.xml" && x.ToLower() != "appxmetadata").First();
         *              var newpkg = pkg.Split('_')[0] + "_" + pkg.Split('_')[1] + "_neutral_~_" + pkg.Split('_')[4];
         *              bool isbundle = entries2.Any(x => x.ToLower() == "appxmetadata");
         *              TargetEditionApps.Add($"{entry}|{pkg}|{pkg.Split('_')[0]}|{newpkg}|{isbundle}");
         *          }
         *      }
         *  }
         *
         *  SourceEditionApps.Sort();
         *  TargetEditionApps.Sort();
         *
         *  Console.WriteLine("Source apps (" + SourceEdition + ")");
         *  foreach (var app in SourceEditionApps)
         *  {
         *      Console.WriteLine(app);
         *  }
         *  Console.WriteLine();
         *
         *  Console.WriteLine("Target apps (" + TargetEdition + ")");
         *  foreach (var app in TargetEditionApps)
         *  {
         *      Console.WriteLine(app);
         *  }
         *  Console.WriteLine();
         *
         *  var common = TargetEditionApps.Intersect(SourceEditionApps);
         *
         *  Console.WriteLine("The following apps must be uninstalled");
         *  foreach (var app in SourceEditionApps.Except(common))
         *  {
         *      Console.WriteLine(app);
         *  }
         *  Console.WriteLine();
         *
         *  Console.WriteLine("The following apps must be installed");
         *  foreach (var app in TargetEditionApps.Except(common))
         *  {
         *      Console.WriteLine(app);
         *  }
         *  Console.WriteLine();
         *
         * exit:
         *  return;
         * }*/

        public static bool CreateHackedEditionFromMountedImage(
            string UUPPath,
            string MediaPath,
            string MountedImagePath,
            string EditionID,
            string OutputInstallImage,
            Common.CompressionType CompressionType,
            ProgressCallback progressCallback = null)
        {
            bool result = true;

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Applying " + EditionID + " - Package Swap");

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Getting serial for " + EditionID);
            string productinifilepath = Path.Combine(MediaPath, "sources", "product.ini");

            var     parser = new FileIniDataParser();
            IniData data   = parser.ReadFile(productinifilepath);

            string serial = data["cmi"].First(x => x.KeyName.ToLower() == EditionID.ToLower()).Value;

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Serial: " + serial);

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Getting current edition");
            string SourceEdition = DismOperations.GetCurrentEdition(MountedImagePath);

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Current edition is: " + SourceEdition);

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Getting wim info for: " + OutputInstallImage);
            WIMInformationXML.WIM wiminfo;
            result = imagingInterface.GetWIMInformation(OutputInstallImage, out wiminfo);
            if (!result)
            {
                goto exit;
            }

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Searching index for : " + SourceEdition);
            var srcimage = wiminfo.IMAGE.First(x =>
            {
                var img = x;
                var win = img.WINDOWS;
                var ed  = win.EDITIONID;
                return(ed.Equals(SourceEdition, StringComparison.InvariantCultureIgnoreCase));
            });
            var index        = int.Parse(srcimage.INDEX);
            var languagecode = srcimage.WINDOWS.LANGUAGES.DEFAULT;

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Source index: " + index);
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Source language: " + languagecode);

            WimCompressionType compression = WimCompressionType.None;

            switch (CompressionType)
            {
            case Common.CompressionType.LZMS:
                compression = WimCompressionType.Lzms;
                break;

            case Common.CompressionType.LZX:
                compression = WimCompressionType.Lzx;
                break;

            case Common.CompressionType.XPRESS:
                compression = WimCompressionType.Xpress;
                break;
            }

            //
            // Perform edition hack
            //
            string servicingPath = Path.Combine(MountedImagePath, "Windows", "servicing", "Packages");
            string manifest      = $"Microsoft-Windows-{SourceEdition}Edition~31bf3856ad364e35~*~~10.0.*.*.mum";
            string catalog       = $"Microsoft-Windows-{SourceEdition}Edition~31bf3856ad364e35~*~~10.0.*.*.cat";
            string manifestPath  = Directory.EnumerateFiles(servicingPath, manifest).First();
            string catalogPath   = Directory.EnumerateFiles(servicingPath, catalog).First();

            bool LTSB = false;

            if (EditionID.ToLower().StartsWith("enterpriseg") ||
                EditionID.ToLower().StartsWith("enterprises") ||
                EditionID.ToLower().StartsWith("iotenterprises"))
            {
                LTSB = true;
            }

            bool HasEditionPack = Directory.EnumerateFiles(UUPPath, "*.esd", SearchOption.AllDirectories).Any(x =>
                                                                                                              Path.GetFileName(x).Equals($"microsoft-windows-editionpack-{EditionID}-package.esd", StringComparison.InvariantCulture)
                                                                                                              );

            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Has edition pack: " + HasEditionPack);

            string TemporaryFolder = Path.GetTempFileName();

            File.Delete(TemporaryFolder);
            Directory.CreateDirectory(TemporaryFolder);

            string SxSFolder = Path.Combine(TemporaryFolder, "SxS");

            Directory.CreateDirectory(SxSFolder);

            //
            // Build reconstructed edition xml
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Generating edition manifest");
            string packageFilter = $"microsoft-windows-edition*{EditionID}-*.esd";
            var    packages      = Directory.EnumerateFiles(UUPPath, packageFilter, SearchOption.AllDirectories);

            string manifestFileName = Path.GetFileName(manifestPath).Replace(SourceEdition, EditionID);
            string catalogFileName  = Path.GetFileName(catalogPath).Replace(SourceEdition, EditionID);

            string newManifestPath = Path.Combine(SxSFolder, manifestFileName);
            string newCatalogPath  = Path.Combine(SxSFolder, catalogFileName);

            File.Copy(manifestPath, newManifestPath);
            File.Copy(catalogPath, newCatalogPath);

            string ManifestContent = File.ReadAllText(newManifestPath);

            ManifestContent = ManifestContent.Replace($"EditionSpecific-{SourceEdition}", $"EditionSpecific-{EditionID}").Replace($"Windows {SourceEdition} Edition", $"Windows {EditionID} Edition").Replace($"Microsoft-Windows-{SourceEdition}Edition", $"Microsoft-Windows-{EditionID}Edition");

            if (HasEditionPack)
            {
                ManifestContent = ManifestContent.Replace($"EditionPack-{SourceEdition}", $"EditionPack-{EditionID}");
            }

            File.WriteAllText(newManifestPath, ManifestContent);

            if (LTSB)
            {
                AssemblyManifestHandler.RemoveNonLTSBPackages(newManifestPath);
            }

            // Cleanup WOW64
            if (!packages.Any(x => x.Equals($"microsoft-windows-editionspecific-{EditionID}-wow64-package.esd", StringComparison.InvariantCultureIgnoreCase)))
            {
                progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Cleaning up WOW64");
                AssemblyManifestHandler.RemoveWOW64Package(newManifestPath, $"microsoft-windows-editionspecific-{EditionID}-wow64-package");
            }

            //
            // Expand LP to folder
            //
            if (LPFolder == null)
            {
                LPFolder = Path.GetTempFileName();
                File.Delete(LPFolder);
                Directory.CreateDirectory(LPFolder);

                string lpfilter1 = $"*fre_client_{languagecode}_lp.cab";
                var    paths     = Directory.EnumerateFiles(UUPPath, lpfilter1, SearchOption.AllDirectories);
                if (paths.Count() > 0)
                {
                    string lppackage = paths.First();
                    void ProgressCallback(int percent, string file)
                    {
                        progressCallback?.Invoke(Common.ProcessPhase.PreparingFiles, false, percent, "Unpacking " + file + "...");
                    };

                    CabinetHandler.ExpandFiles(lppackage, LPFolder, ProgressCallback);
                }
                else
                {
                    string lpfilter2 = $"microsoft-windows-client-languagepack-package_{languagecode}-*-{languagecode}.esd";
                    string lppackage = "";
                    if (Directory.EnumerateFiles(UUPPath, lpfilter2, SearchOption.AllDirectories).Count() > 0)
                    {
                        lppackage = Directory.EnumerateFiles(UUPPath, lpfilter2, SearchOption.AllDirectories).First();
                    }
                    else
                    {
                        lpfilter2 = $"microsoft-windows-client-languagepack-package_{languagecode}~*~{languagecode}~.esd";
                        lppackage = Directory.EnumerateFiles(UUPPath, lpfilter2, SearchOption.AllDirectories).First();
                    }

                    result = imagingInterface.ApplyImage(lppackage, 1, LPFolder, PreserveACL: false, progressCallback: callback2);
                    if (!result)
                    {
                        goto exit;
                    }
                }
            }

            //
            // Expand Edition related packages to SxS folder
            //
            foreach (var package in packages)
            {
                result = imagingInterface.ApplyImage(package, 1, SxSFolder, PreserveACL: false, progressCallback: callback2);
                if (!result)
                {
                    goto exit;
                }

                if (File.Exists(Path.Combine(SxSFolder, "update.mum")))
                {
                    var    assembly = AssemblyManifestHandler.Deserialize(File.ReadAllText(Path.Combine(SxSFolder, "update.mum")));
                    string cbsKey   = assembly.AssemblyIdentity.Name + "~" + assembly.AssemblyIdentity.PublicKeyToken + "~" + assembly.AssemblyIdentity.ProcessorArchitecture + "~" + (assembly.AssemblyIdentity.Language.ToLower() == "neutral" ? "" : assembly.AssemblyIdentity.Language) + "~" + assembly.AssemblyIdentity.Version;
                    if (!File.Exists(Path.Combine(SxSFolder, cbsKey + ".mum")))
                    {
                        File.Move(Path.Combine(SxSFolder, "update.mum"), Path.Combine(SxSFolder, cbsKey + ".mum"));
                    }
                    else
                    {
                        File.Delete(Path.Combine(SxSFolder, "update.mum"));
                    }

                    if (File.Exists(Path.Combine(SxSFolder, "update.cat")))
                    {
                        if (!File.Exists(Path.Combine(SxSFolder, cbsKey + ".cat")))
                        {
                            File.Move(Path.Combine(SxSFolder, "update.cat"), Path.Combine(SxSFolder, cbsKey + ".cat"));
                        }
                        else
                        {
                            File.Delete(Path.Combine(SxSFolder, "update.cat"));
                        }
                    }
                }
                File.Delete(Path.Combine(SxSFolder, "$filehashes$.dat"));
            }

            //
            // Generate unattend
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Generating unattend");
            string arch = manifestFileName.Split('~')[2];
            string ver  = manifestFileName.Split('~')[4].Replace(".mum", "");

            bool removeogedition = true;

            // TODO: get these from matrix
            //
            if (SourceEdition.Equals("core", StringComparison.InvariantCultureIgnoreCase))
            {
                if (EditionID.Equals("corecountryspecific", StringComparison.InvariantCultureIgnoreCase))
                {
                    removeogedition = false;
                }
            }
            if (SourceEdition.Equals("professional", StringComparison.InvariantCultureIgnoreCase))
            {
                if (EditionID.Equals("core", StringComparison.InvariantCultureIgnoreCase))
                {
                    removeogedition = false;
                }
            }
            if (SourceEdition.Equals("professionaln", StringComparison.InvariantCultureIgnoreCase))
            {
                if (EditionID.Equals("coren", StringComparison.InvariantCultureIgnoreCase))
                {
                    removeogedition = false;
                }
            }
            if (SourceEdition.Equals("core", StringComparison.InvariantCultureIgnoreCase))
            {
                if (EditionID.Equals("starter", StringComparison.InvariantCultureIgnoreCase))
                {
                    removeogedition = false;
                }
            }
            if (SourceEdition.Equals("coren", StringComparison.InvariantCultureIgnoreCase))
            {
                if (EditionID.Equals("startern", StringComparison.InvariantCultureIgnoreCase))
                {
                    removeogedition = false;
                }
            }

            string unattend = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                              "<unattend xmlns=\"urn:schemas-microsoft-com:unattend\">\n" +
                              "    <servicing>\n";

            if (!removeogedition)
            {
                unattend +=
                    "        <package action=\"stage\">\n" +
                    $"            <assemblyIdentity name=\"Microsoft-Windows-{SourceEdition}Edition\" version=\"{ver}\" processorArchitecture=\"{arch}\" publicKeyToken=\"31bf3856ad364e35\" language=\"neutral\" />\n" +
                    "        </package>\n";
            }

            unattend +=
                "        <package action=\"stage\">\n" +
                $"            <assemblyIdentity name=\"Microsoft-Windows-{EditionID}Edition\" version=\"{ver}\" processorArchitecture=\"{arch}\" publicKeyToken=\"31bf3856ad364e35\" language=\"neutral\" />\n" +
                $"            <source location=\"{newManifestPath}\" />\n" +
                "        </package>\n";

            if (removeogedition)
            {
                unattend +=
                    "        <package action=\"remove\">\n" +
                    $"            <assemblyIdentity name=\"Microsoft-Windows-{SourceEdition}Edition\" version=\"{ver}\" processorArchitecture=\"{arch}\" publicKeyToken=\"31bf3856ad364e35\" language=\"neutral\" />\n" +
                    "        </package>\n";
            }

            unattend +=
                "        <package action=\"install\">\n" +
                $"            <assemblyIdentity name=\"Microsoft-Windows-{EditionID}Edition\" version=\"{ver}\" processorArchitecture=\"{arch}\" publicKeyToken=\"31bf3856ad364e35\" language=\"neutral\" />\n" +
                "        </package>\n" +
                "        <package action=\"install\">\n" +
                $"            <assemblyIdentity name=\"Microsoft-Windows-Client-LanguagePack-Package\" version=\"{ver}\" processorArchitecture=\"{arch}\" publicKeyToken=\"31bf3856ad364e35\" language=\"{languagecode}\" />\n" +
                $"            <source location=\"{LPFolder}\\update.mum\" />\n" +
                "        </package>\n" +
                "    </servicing>\n" +
                "</unattend>";

            string unattendPath = Path.Combine(TemporaryFolder, "unattend.xml");

            File.WriteAllText(unattendPath, unattend);

            //
            // Backup OEMDefaultAssociations
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Backing up OEMDefaultAssociations");

            bool HandleOEMDefaultAssociationsXml = File.Exists(Path.Combine(MountedImagePath, "Windows", "System32", "OEMDefaultAssociations.xml"));
            bool HandleOEMDefaultAssociationsDll = File.Exists(Path.Combine(MountedImagePath, "Windows", "System32", "OEMDefaultAssociations.dll"));

            string OEMDefaultAssociationsXml = Path.GetTempFileName();
            string OEMDefaultAssociationsDll = Path.GetTempFileName();

            File.Delete(OEMDefaultAssociationsXml);
            File.Delete(OEMDefaultAssociationsDll);

            string OEMDefaultAssociationsXmlInImage = Path.Combine(MountedImagePath, "Windows", "System32", "OEMDefaultAssociations.xml");
            string OEMDefaultAssociationsDllInImage = Path.Combine(MountedImagePath, "Windows", "System32", "OEMDefaultAssociations.dll");

            if (HandleOEMDefaultAssociationsXml)
            {
                File.Copy(OEMDefaultAssociationsXmlInImage, OEMDefaultAssociationsXml);
            }

            if (HandleOEMDefaultAssociationsDll)
            {
                File.Copy(OEMDefaultAssociationsDllInImage, OEMDefaultAssociationsDll);
            }

            //
            // Apply unattend
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Applying unattend");
            DismOperations.ApplyUnattend(MountedImagePath, unattendPath);

            //
            // Restore OEMDefaultAssociations
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Restoring up OEMDefaultAssociations");

            if (HandleOEMDefaultAssociationsXml)
            {
                if (!File.Exists(OEMDefaultAssociationsXmlInImage))
                {
                    File.Move(OEMDefaultAssociationsXml, OEMDefaultAssociationsXmlInImage);
                }
            }

            if (HandleOEMDefaultAssociationsDll)
            {
                if (!File.Exists(OEMDefaultAssociationsDllInImage))
                {
                    File.Move(OEMDefaultAssociationsDll, OEMDefaultAssociationsDllInImage);
                }
            }

            //
            // Copy edition xml
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Handling Edition Unattend XML");
            string editionXml            = Path.Combine(MountedImagePath, "Windows", "servicing", "Editions", $"{EditionID}Edition.xml");
            string desintationEditionXml = Path.Combine(MountedImagePath, "Windows", $"{EditionID}.xml");

            File.Copy(editionXml, desintationEditionXml);

            //
            // Delete old edition xml
            //
            File.Delete(Path.Combine(MountedImagePath, "Windows", $"{SourceEdition}.xml"));

            //
            // Apply edition xml as unattend
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Applying Edition Unattend XML");
            DismOperations.ApplyUnattend(MountedImagePath, desintationEditionXml);

            //
            // Install correct product key
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Installing product key");

            DismOperations.SetProductKey(MountedImagePath, serial);

            //
            // Application handling
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Installing apps");

            //////////////////////// TODO ////////////////////////

            //
            // Cleanup
            //
            progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, true, 0, "Cleaning up");
            Directory.Delete(TemporaryFolder, true);
            CleanupLanguagePackFolderIfRequired();

            void callback2(string Operation, int ProgressPercentage, bool IsIndeterminate)
            {
                progressCallback?.Invoke(Common.ProcessPhase.CapturingImage, IsIndeterminate, ProgressPercentage, Operation);
            };

            string name = $"Windows 10 {EditionID}";

            if (Constants.FriendlyEditionNames.Any(x => x.Key.Equals(EditionID, StringComparison.InvariantCultureIgnoreCase)))
            {
                name = Constants.FriendlyEditionNames.First(x => x.Key.Equals(EditionID, StringComparison.InvariantCultureIgnoreCase)).Value;
            }

            result = imagingInterface.CaptureImage(
                OutputInstallImage,
                name,
                name,
                EditionID,
                MountedImagePath,
                name,
                name,
                compression,
                progressCallback: callback2,
                UpdateFrom: index);

            if (!result)
            {
                goto exit;
            }

            WIMInformationXML.IMAGE tmpImageInfo;
            result = imagingInterface.GetWIMImageInformation(OutputInstallImage, wiminfo.IMAGE.Count + 1, out tmpImageInfo);
            if (!result)
            {
                goto exit;
            }

            var sku = tmpImageInfo.WINDOWS.EDITIONID;

            tmpImageInfo.WINDOWS           = srcimage.WINDOWS;
            tmpImageInfo.WINDOWS.EDITIONID = sku;
            tmpImageInfo.FLAGS             = sku;
            tmpImageInfo.NAME               = name;
            tmpImageInfo.DESCRIPTION        = name;
            tmpImageInfo.DISPLAYNAME        = name;
            tmpImageInfo.DISPLAYDESCRIPTION = name;

            result = imagingInterface.SetWIMImageInformation(OutputInstallImage, wiminfo.IMAGE.Count + 1, tmpImageInfo);
            if (!result)
            {
                goto exit;
            }

exit:
            return(result);
        }
Exemple #6
0
        public static async Task <AvailableEdition[]> GetAvailableEditions(UpdateData UpdateData, string languagecode)
        {
            List <AvailableEdition> availableEditions = new List <AvailableEdition>();

            List <CExtendedUpdateInfoXml.File> metadataCabs = new List <CExtendedUpdateInfoXml.File>();

            foreach (var file in UpdateData.Xml.Files.File)
            {
                if (file.PatchingType.Equals("metadata", StringComparison.InvariantCultureIgnoreCase))
                {
                    metadataCabs.Add(file);
                }
            }

            if (metadataCabs.Count == 0)
            {
                goto exit;
            }

            if (metadataCabs.Count == 1 && metadataCabs[0].FileName.Contains("metadata", StringComparison.InvariantCultureIgnoreCase))
            {
                // This is the new metadata format where all metadata is in a single cab

                if (string.IsNullOrEmpty(UpdateData.CachedMetadata))
                {
                    var fileDownloadInfo = await FE3Handler.GetFileUrl(UpdateData, metadataCabs[0].Digest);

                    if (fileDownloadInfo == null)
                    {
                        goto exit;
                    }

                    string metadataCabTemp = Path.GetTempFileName();

                    // Download the file
                    WebClient client = new WebClient();
                    await client.DownloadFileTaskAsync(new Uri(fileDownloadInfo.DownloadUrl), metadataCabTemp);

                    if (fileDownloadInfo.IsEncrypted)
                    {
                        if (!await fileDownloadInfo.DecryptAsync(metadataCabTemp, metadataCabTemp + ".decrypted"))
                        {
                            goto exit;
                        }
                        metadataCabTemp += ".decrypted";
                    }

                    UpdateData.CachedMetadata = metadataCabTemp;
                }

                using (var cabinet = new CabinetHandler(File.OpenRead(UpdateData.CachedMetadata)))
                {
                    IEnumerable <string> potentialFiles = cabinet.Files.Where(x =>
                                                                              x.ToLower().Contains($"desktoptargetcompdb_") &&
                                                                              x.ToLower().Contains($"_{languagecode}") &&
                                                                              !x.ToLower().Contains("lxp") &&
                                                                              !x.ToLower().Contains($"desktoptargetcompdb_{languagecode}"));

                    foreach (var file in potentialFiles)
                    {
                        var edition = file.Split('_').Reverse().Skip(1).First();

                        if (availableEditions.Any(x => x.Edition == edition))
                        {
                            continue;
                        }

                        availableEditions.Add(new AvailableEdition()
                        {
                            Edition = edition
                        });
                    }
                }
            }
            else
            {
                IEnumerable <string> potentialFiles = metadataCabs.Select(x => x.FileName).Where(x =>
                                                                                                 x.ToLower().Contains($"desktoptargetcompdb_") &&
                                                                                                 x.ToLower().Contains($"_{languagecode}") &&
                                                                                                 !x.ToLower().Contains("lxp") &&
                                                                                                 !x.ToLower().Contains($"desktoptargetcompdb_{languagecode}"));

                // This is the old format, each cab is a file in WU
                foreach (var file in potentialFiles)
                {
                    var edition = file.Split('_').Reverse().Skip(1).First();

                    if (availableEditions.Any(x => x.Edition == edition))
                    {
                        continue;
                    }

                    availableEditions.Add(new AvailableEdition()
                    {
                        Edition = edition
                    });
                }
            }

            availableEditions.Sort((x, y) => x.Edition.CompareTo(y.Edition));

exit:
            return(availableEditions.ToArray());
        }