public static extern IntPtr WIMCreateFile( string pszWimPath, WimOpenMode dwDesiredAccess, WimCreationMode dwCreationDisposition, WimCreationOptions dwFlagsAndAttributes, WimCompressionType dwCompressionType, out uint pdwCreationResult );
public static bool CreateSetupMedia( string UUPPath, string LanguageCode, string OutputMediaPath, string OutputWindowsREPath, Common.CompressionType CompressionType, ProgressCallback progressCallback = null) { bool result = true; string BaseESD = null; (result, BaseESD) = FileLocator.LocateFilesForSetupMediaCreation(UUPPath, LanguageCode, progressCallback); if (!result) { goto exit; } 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; } // // Build installer // result = WindowsInstallerBuilder.BuildSetupMedia(BaseESD, OutputWindowsREPath, OutputMediaPath, compression, RunsAsAdministrator, LanguageCode, progressCallback); if (!result) { goto exit; } exit: return(result); }
/*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); }
public static bool CreateUpgradedEditionFromMountedImage( string MountedImagePath, string EditionID, string OutputInstallImage, bool IsVirtual, Common.CompressionType CompressionType, ProgressCallback progressCallback = null) { bool result = true; string SourceEdition = DismOperations.GetCurrentEdition(MountedImagePath); WIMInformationXML.WIM wiminfo; result = imagingInterface.GetWIMInformation(OutputInstallImage, out wiminfo); if (!result) { goto exit; } var srcimage = wiminfo.IMAGE.First(x => x.WINDOWS.EDITIONID.Equals(SourceEdition, StringComparison.InvariantCultureIgnoreCase)); var index = int.Parse(srcimage.INDEX); 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; } void callback(bool IsIndeterminate, int ProgressInPercentage, string SubOperation) { progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, IsIndeterminate, ProgressInPercentage, SubOperation); }; DismOperations.SetTargetEdition(MountedImagePath, EditionID, callback); 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; } if (IsVirtual) { File.Delete(Path.Combine(MountedImagePath, "Windows", $"{EditionID}.xml")); } exit: return(result); }
private static bool PerformComponentCleanupOnPEImage( string MediaPath, WimCompressionType compressionType, WIMInformationXML.IMAGE image, ProgressCallback progressCallback = null ) { using (VirtualDiskSession vhdsession = new VirtualDiskSession()) { string ospath = vhdsession.GetMountedPath(); // // Apply the RE image to our ospath, in this case our VHD // void callback(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, IsIndeterminate, ProgressPercentage, Operation); } bool result = imagingInterface.ApplyImage(Path.Combine(MediaPath, "sources", "boot.wim"), 1, ospath, progressCallback: callback); if (!result) { goto exit; } File.Delete(Path.Combine(MediaPath, "sources", "boot.wim")); result = RunDismComponentRemovalOperation(ospath, progressCallback); if (!result) { goto exit; } // // Cleanup leftovers for WLAN // progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Cleaning up leftovers"); string winsxsfolder = Path.Combine(ospath, "Windows", "WinSxS"); string winsxsManFolder = Path.Combine(winsxsfolder, "Manifests"); IEnumerable <string> directoriesToCleanOut = Directory.EnumerateDirectories(winsxsfolder, "*_dual_netnwifi.inf_31bf3856ad364e35_*", SearchOption.TopDirectoryOnly); IEnumerable <string> manifestsToCleanOut = Directory.EnumerateFiles(winsxsManFolder, "*_dual_netnwifi.inf_31bf3856ad364e35_*", SearchOption.TopDirectoryOnly); foreach (string dir in directoriesToCleanOut) { try { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Deleting " + dir); TakeOwn.TakeOwnDirectory(dir); Directory.Delete(dir, true); } catch { } } foreach (string file in manifestsToCleanOut) { try { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Deleting " + file); TakeOwn.TakeOwnFile(file); File.Delete(file); } catch { } } // // Add missing files from the setup media root // progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Adding missing files"); if (!File.Exists(Path.Combine(ospath, "Windows", "System32", "ReAgent.dll"))) { File.Copy(Path.Combine(MediaPath, "sources", "ReAgent.dll"), Path.Combine(ospath, "Windows", "System32", "ReAgent.dll")); } if (!File.Exists(Path.Combine(ospath, "Windows", "System32", "unattend.dll"))) { File.Copy(Path.Combine(MediaPath, "sources", "unattend.dll"), Path.Combine(ospath, "Windows", "System32", "unattend.dll")); } if (!File.Exists(Path.Combine(ospath, "Windows", "System32", "wpx.dll"))) { File.Copy(Path.Combine(MediaPath, "sources", "wpx.dll"), Path.Combine(ospath, "Windows", "System32", "wpx.dll")); } result = imagingInterface.CaptureImage( Path.Combine(MediaPath, "sources", "boot.wim"), image.NAME, image.DESCRIPTION, image.FLAGS, ospath, progressCallback: callback, compressionType: compressionType); if (!result) { goto exit; } exit: return(result); } }
private static bool PreparePEImage( string BaseESD, string OutputWinREPath, string MediaPath, WimCompressionType compressionType, string LanguageCode, ProgressCallback progressCallback = null ) { // // Export the RE image to our re path, in this case a WIM // void callback(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, IsIndeterminate, ProgressPercentage, Operation); } bool result = imagingInterface.ExportImage(BaseESD, OutputWinREPath, 2, compressionType: compressionType, progressCallback: callback); if (!result) { goto exit; } WIMInformationXML.IMAGE image; result = imagingInterface.GetWIMImageInformation(OutputWinREPath, 1, out image); if (!result) { goto exit; } if (image.WINDOWS.LANGUAGES == null) { image.WINDOWS.LANGUAGES = new WIMInformationXML.LANGUAGES() { LANGUAGE = LanguageCode, FALLBACK = new WIMInformationXML.FALLBACK() { LANGUAGE = LanguageCode, Text = "en-US" }, DEFAULT = LanguageCode }; result = imagingInterface.SetWIMImageInformation(OutputWinREPath, 1, image); if (!result) { goto exit; } } progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Marking image as bootable"); result = imagingInterface.MarkImageAsBootable(OutputWinREPath, 1); if (!result) { goto exit; } string bootwim = Path.Combine(MediaPath, "sources", "boot.wim"); File.Copy(OutputWinREPath, bootwim); // // Cleanup WinPE Shell directive // string sys32 = Path.Combine("Windows", "System32"); string peshellini = Path.Combine(sys32, "winpeshl.ini"); // Ignore return result imagingInterface.DeleteFileFromImage(bootwim, 1, peshellini, progressCallback: callback); // // Cleanup log file from RE conversion phase mentions // try { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Cleaning log files"); string logfile = Path.GetTempFileName(); string pathinimage = Path.Combine("Windows", "INF", "setupapi.offline.log"); bool cresult = imagingInterface.ExtractFileFromImage(bootwim, 1, pathinimage, logfile); if (cresult) { string[] lines = File.ReadAllLines(logfile); int bootsessioncount = 0; List <string> finallines = new List <string>(); foreach (string line in lines) { if (line.StartsWith("[Boot Session: ", StringComparison.InvariantCultureIgnoreCase)) { bootsessioncount++; } if (bootsessioncount == 2) { finallines.RemoveAt(finallines.Count - 1); File.WriteAllLines(logfile, finallines); // Ignore return result imagingInterface.AddFileToImage(bootwim, 1, logfile, pathinimage, progressCallback: callback); break; } finallines.Add(line); } } } catch { } // // Disable UMCI // progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Disabling UMCI"); string tempSystemHiveBackup = Path.GetTempFileName(); result = imagingInterface.ExtractFileFromImage(bootwim, 1, Constants.SYSTEM_Hive_Location, tempSystemHiveBackup); if (!result) { goto cleanup; } result = RegistryOperations.ModifyBootGlobalRegistry(tempSystemHiveBackup); if (!result) { goto cleanup; } result = imagingInterface.AddFileToImage(bootwim, 1, tempSystemHiveBackup, Constants.SYSTEM_Hive_Location, progressCallback: callback); if (!result) { goto cleanup; } cleanup: File.Delete(tempSystemHiveBackup); exit: return(result); }
// 6 progress bars public static bool BuildSetupMedia( string BaseESD, string OutputWinREPath, string MediaPath, WimCompressionType compressionType, bool RunsAsAdministrator, string LanguageCode, ProgressCallback progressCallback = null ) { // // First create the setup media base, minus install.wim and boot.wim // bool result = CreateSetupMediaRoot(BaseESD, MediaPath, progressCallback); if (!result) { goto exit; } // // Gather information about the Windows Recovery Environment image so we can transplant it later // into our new images // WIMInformationXML.IMAGE image; result = imagingInterface.GetWIMImageInformation(BaseESD, 2, out image); if (!result) { goto exit; } // // Gather the architecture string under parenthesis for the new images we are creating // string ArchitectureInNameAndDescription = image.NAME.Split('(')[1].Replace(")", ""); string BootFirstImageName = $"Microsoft Windows PE ({ArchitectureInNameAndDescription})"; string BootSecondImageName = $"Microsoft Windows Setup ({ArchitectureInNameAndDescription})"; string BootFirstImageFlag = "9"; string BootSecondImageFlag = "2"; // // Bootable wim files must not be lzms // if (compressionType == WimCompressionType.Lzms) { compressionType = WimCompressionType.Lzx; } void callback(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, IsIndeterminate, ProgressPercentage, Operation); } // // Prepare our base PE image which will serve as a basis for all subsequent operations // This function also generates WinRE // result = PreparePEImage(BaseESD, OutputWinREPath, MediaPath, compressionType, LanguageCode, progressCallback); if (!result) { goto exit; } // // If we are running as administrator, perform additional component cleanup // if (RunsAsAdministrator) { result = PerformComponentCleanupOnPEImage(MediaPath, compressionType, image, progressCallback); if (!result) { goto exit; } } string bootwim = Path.Combine(MediaPath, "sources", "boot.wim"); string tmpwimcopy = Path.GetTempFileName(); File.Delete(tmpwimcopy); File.Copy(bootwim, tmpwimcopy); // // Duplicate the boot image so we have two of them // result = imagingInterface.ExportImage(tmpwimcopy, bootwim, 1, compressionType: compressionType, progressCallback: callback); if (!result) { goto exit; } File.Delete(tmpwimcopy); // // Set the correct metadata on both images // image.NAME = BootFirstImageName; image.DESCRIPTION = BootFirstImageName; image.FLAGS = BootFirstImageFlag; if (image.WINDOWS.LANGUAGES == null) { image.WINDOWS.LANGUAGES = new WIMInformationXML.LANGUAGES() { LANGUAGE = LanguageCode, FALLBACK = new WIMInformationXML.FALLBACK() { LANGUAGE = LanguageCode, Text = "en-US" }, DEFAULT = LanguageCode }; } result = imagingInterface.SetWIMImageInformation(bootwim, 1, image); if (!result) { goto exit; } image.NAME = BootSecondImageName; image.DESCRIPTION = BootSecondImageName; image.FLAGS = BootSecondImageFlag; if (image.WINDOWS.LANGUAGES == null) { image.WINDOWS.LANGUAGES = new WIMInformationXML.LANGUAGES() { LANGUAGE = LanguageCode, FALLBACK = new WIMInformationXML.FALLBACK() { LANGUAGE = LanguageCode, Text = "en-US" }, DEFAULT = LanguageCode }; } result = imagingInterface.SetWIMImageInformation(bootwim, 2, image); if (!result) { goto exit; } // // Mark image as bootable // result = imagingInterface.MarkImageAsBootable(bootwim, 2); if (!result) { goto exit; } // // Modifying registry for each index // string tempSoftwareHiveBackup = Path.GetTempFileName(); string tempSystemHiveBackup = Path.GetTempFileName(); result = imagingInterface.ExtractFileFromImage(bootwim, 1, Constants.SYSTEM_Hive_Location, tempSystemHiveBackup); if (!result) { goto exit; } result = imagingInterface.ExtractFileFromImage(bootwim, 1, Constants.SOFTWARE_Hive_Location, tempSoftwareHiveBackup); if (!result) { goto exit; } File.Copy(tempSoftwareHiveBackup, $"{tempSoftwareHiveBackup}.2"); result = RegistryOperations.ModifyBootIndex2Registry($"{tempSoftwareHiveBackup}.2"); if (!result) { goto exit; } result = imagingInterface.AddFileToImage(bootwim, 2, $"{tempSoftwareHiveBackup}.2", Constants.SOFTWARE_Hive_Location, progressCallback: callback); if (!result) { goto exit; } File.Delete($"{tempSoftwareHiveBackup}.2"); result = RegistryOperations.ModifyBootIndex1Registry(tempSystemHiveBackup, tempSoftwareHiveBackup); if (!result) { goto exit; } result = imagingInterface.AddFileToImage(bootwim, 1, tempSystemHiveBackup, Constants.SYSTEM_Hive_Location, progressCallback: callback); if (!result) { goto exit; } result = imagingInterface.AddFileToImage(bootwim, 1, tempSoftwareHiveBackup, Constants.SOFTWARE_Hive_Location, progressCallback: callback); if (!result) { goto exit; } File.Delete(tempSoftwareHiveBackup); File.Delete(tempSystemHiveBackup); // // Adding missing files in index 2 // progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Modifying assets for Setup PE (1)"); result = imagingInterface.RenameFileInImage(bootwim, 2, Path.Combine("Windows", "System32", "winpe.jpg"), Path.Combine("Windows", "System32", "setup.bmp"), progressCallback: callback); if (!result) { goto exit; } progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Modifying assets for Setup PE (2)"); var winpejpgtmp = Path.GetTempFileName(); File.WriteAllBytes(winpejpgtmp, Constants.winpejpg); result = imagingInterface.AddFileToImage(bootwim, 2, winpejpgtmp, Path.Combine("Windows", "System32", "winpe.jpg"), progressCallback: callback); File.Delete(winpejpgtmp); if (!result) { goto exit; } progressCallback?.Invoke(Common.ProcessPhase.CreatingWindowsInstaller, true, 0, "Backporting missing files"); var dirs = Directory.EnumerateDirectories(Path.Combine(MediaPath, "sources"), "??-??"); if (dirs.Count() == 0) { dirs = Directory.EnumerateDirectories(Path.Combine(MediaPath, "sources"), "*-*"); } string langcode = dirs.First().Replace(Path.Combine(MediaPath, "sources") + "\\", ""); foreach (string file in Constants.SetupFilesToBackport) { string matchingfile = Path.Combine(MediaPath, file).Replace("??-??", langcode); string normalizedPath = file.Replace("??-??", langcode); string normalizedPathWithoutFile = normalizedPath.Contains("\\") ? string.Join("\\", normalizedPath.Split('\\').Reverse().Skip(1).Reverse()) : ""; if (file == "sources\\background.bmp") { string matchingfile1 = Path.Combine(MediaPath, "sources", "background_cli.bmp"); string matchingfile2 = Path.Combine(MediaPath, "sources", "background_srv.bmp"); if (File.Exists(matchingfile1)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile1, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } else if (File.Exists(matchingfile2)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile2, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } } else if (File.Exists(matchingfile)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } } if (ulong.Parse(image.WINDOWS.VERSION.BUILD) >= 20231) { foreach (string file in Constants.SetupFilesToBackportStartingWith20231) { string matchingfile = Path.Combine(MediaPath, file).Replace("??-??", langcode); string normalizedPath = file.Replace("??-??", langcode); string normalizedPathWithoutFile = normalizedPath.Contains("\\") ? string.Join("\\", normalizedPath.Split('\\').Reverse().Skip(1).Reverse()) : ""; if (file == "sources\\background.bmp") { string matchingfile1 = Path.Combine(MediaPath, "sources", "background_cli.bmp"); string matchingfile2 = Path.Combine(MediaPath, "sources", "background_srv.bmp"); if (File.Exists(matchingfile1)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile1, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } else if (File.Exists(matchingfile2)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile2, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } } else if (File.Exists(matchingfile)) { result = imagingInterface.AddFileToImage(bootwim, 2, matchingfile, normalizedPath, progressCallback: callback); if (!result) { goto exit; } } } } // // We're done // exit: return(result); }
public void CreateFileTest(WimCompressionType compressionType) { using (WimHandle wimHandle = WimgApi.CreateFile(CreateWimPath, WimFileAccess.Write, WimCreationDisposition.CreateAlways, WimCreateFileOptions.None, compressionType)) { } }
public static bool CreateUpgradedEditionFromMountedImage( string MountedImagePath, string EditionID, string OutputInstallImage, bool IsVirtual, Common.CompressionType CompressionType, ProgressCallback progressCallback = null) { bool result = true; string SourceEdition = DismOperations.GetCurrentEdition(MountedImagePath); WIMInformationXML.WIM wiminfo; result = imagingInterface.GetWIMInformation(OutputInstallImage, out wiminfo); if (!result) { goto exit; } var srcimage = wiminfo.IMAGE.First(x => x.WINDOWS.EDITIONID.Equals(SourceEdition, StringComparison.InvariantCultureIgnoreCase)); var index = int.Parse(srcimage.INDEX); 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; } void callback(bool IsIndeterminate, int ProgressInPercentage, string SubOperation) { progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, IsIndeterminate, ProgressInPercentage, SubOperation); }; DismOperations.SetTargetEdition(MountedImagePath, EditionID, callback); void callback2(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.CapturingImage, IsIndeterminate, ProgressPercentage, Operation); }; string replaceStr = LongestCommonSubstring(new string[] { srcimage.DISPLAYNAME, SourceEdition }); string replaceStr2 = LongestCommonSubstring(new string[] { EditionID, SourceEdition }); if (!string.IsNullOrEmpty(replaceStr2)) { replaceStr2 = EditionID.Replace(replaceStr2, ""); } else { replaceStr2 = EditionID; } string name; string description; string displayname; string displaydescription; if (string.IsNullOrEmpty(replaceStr)) { name = $"Windows 10 {replaceStr2}"; description = name; displayname = name; displaydescription = name; } else { name = srcimage.NAME.Replace(replaceStr, replaceStr2, StringComparison.InvariantCultureIgnoreCase); description = srcimage.DESCRIPTION.Replace(replaceStr, replaceStr2, StringComparison.InvariantCultureIgnoreCase); displayname = srcimage.DISPLAYNAME.Replace(replaceStr, replaceStr2, StringComparison.InvariantCultureIgnoreCase); displaydescription = srcimage.DISPLAYDESCRIPTION.Replace(replaceStr, replaceStr2, StringComparison.InvariantCultureIgnoreCase); } if (Constants.FriendlyEditionNames.Any(x => x.Key.Equals(EditionID, StringComparison.InvariantCultureIgnoreCase))) { name = Constants.FriendlyEditionNames.First(x => x.Key.Equals(EditionID, StringComparison.InvariantCultureIgnoreCase)).Value; description = name; displayname = name; displaydescription = name; } result = imagingInterface.CaptureImage( OutputInstallImage, name, description, EditionID, MountedImagePath, displayname, displaydescription, 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; } // // Set the correct metadata on the image // var sku = tmpImageInfo.WINDOWS.EDITIONID; tmpImageInfo.WINDOWS = srcimage.WINDOWS; tmpImageInfo.WINDOWS.EDITIONID = sku; tmpImageInfo.FLAGS = sku; if (tmpImageInfo.WINDOWS.INSTALLATIONTYPE.EndsWith(" Core", StringComparison.InvariantCultureIgnoreCase) && !tmpImageInfo.FLAGS.EndsWith("Core", StringComparison.InvariantCultureIgnoreCase)) { tmpImageInfo.FLAGS += "Core"; } tmpImageInfo.NAME = name; tmpImageInfo.DESCRIPTION = description; tmpImageInfo.DISPLAYNAME = displayname; tmpImageInfo.DISPLAYDESCRIPTION = displaydescription; result = imagingInterface.SetWIMImageInformation(OutputInstallImage, wiminfo.IMAGE.Count + 1, tmpImageInfo); if (!result) { goto exit; } if (IsVirtual) { File.Delete(Path.Combine(MountedImagePath, "Windows", $"{EditionID}.xml")); } else { File.Delete(Path.Combine(MountedImagePath, "Windows", $"{SourceEdition}.xml")); } exit: return(result); }
/// <summary> /// Makes a new image file or opens an existing image file. /// </summary> /// <param name="path">The name of the file to create or to open.</param> /// <param name="desiredAccess">The type of <see cref="WimFileAccess"/> to the object. An application can obtain read access, write access, read/write access, or device query access.</param> /// <param name="creationDisposition">The <see cref="WimCreationDisposition"/> to take on files that exist, and which action to take when files do not exist.</param> /// <param name="options"><see cref="WimCreateFileOptions"/> to be used for the specified file.</param> /// <param name="compressionType">The <see cref="WimCompressionType"/> to be used for a newly created image file. If the file already exists, then this value is ignored.</param> /// <returns>A <see cref="WimHandle"/> object representing the file.</returns> /// <exception cref="ArgumentNullException">path is null.</exception> /// <exception cref="Win32Exception">The Windows® Imaging API reported a failure.</exception> public static WimHandle CreateFile(string path, WimFileAccess desiredAccess, WimCreationDisposition creationDisposition, WimCreateFileOptions options, WimCompressionType compressionType) { // See if destinationFile is null if (path == null) { throw new ArgumentNullException(nameof(path)); } // Call the native function WimHandle wimHandle = WimgApi.NativeMethods.WIMCreateFile(path, (DWORD)desiredAccess, (DWORD)creationDisposition, (DWORD)options, (DWORD)compressionType, out _); // See if the handle returned is valid if (wimHandle == null || wimHandle.IsInvalid) { // Throw a Win32Exception based on the last error code throw new Win32Exception(); } // Return the handle to the wim return(wimHandle); }
public bool CaptureImage( string wimFile, string imageName, string imageDescription, string imageFlag, string InputDirectory, string imageDisplayName = null, string imageDisplayDescription = null, WimCompressionType compressionType = WimCompressionType.Lzx, IImaging.ProgressCallback progressCallback = null, int UpdateFrom = -1, bool PreserveACL = true) { string title = $"Creating {imageName} ({wimFile.Split('\\').Last()})"; try { CallbackStatus ProgressCallback(ProgressMsg msg, object info, object progctx) { switch (msg) { case ProgressMsg.ScanBegin: { ScanProgress m = (ScanProgress)info; progressCallback?.Invoke($"Scanning files ({m.NumBytesScanned} bytes scanned, {m.NumDirsScanned} Directories, {m.NumNonDirsScanned} Files, Current directory: {m.CurPath})", 0, true); } break; case ProgressMsg.ScanDEntry: { ScanProgress m = (ScanProgress)info; progressCallback?.Invoke($"Scanning files ({m.NumBytesScanned} bytes scanned, {m.NumDirsScanned} Directories, {m.NumNonDirsScanned} Files, Current directory: {m.CurPath})", 0, true); } break; case ProgressMsg.ScanEnd: { ScanProgress m = (ScanProgress)info; progressCallback?.Invoke($"Scanning files ({m.NumBytesScanned} bytes scanned, {m.NumDirsScanned} Directories, {m.NumNonDirsScanned} Files, Current directory: {m.CurPath})", 0, true); } break; case ProgressMsg.WriteMetadataBegin: break; case ProgressMsg.WriteStreams: { WriteStreamsProgress m = (WriteStreamsProgress)info; progressCallback?.Invoke(title, (int)Math.Round((double)m.CompletedBytes / m.TotalBytes * 100), false); } break; case ProgressMsg.WriteMetadataEnd: break; } return(CallbackStatus.Continue); } if (File.Exists(wimFile)) { using (Wim wim = Wim.OpenWim(wimFile, OpenFlags.WriteAccess)) { wim.RegisterCallback(ProgressCallback); wim.AddImage(InputDirectory, imageName, null, PreserveACL ? AddFlags.StrictAcls : AddFlags.NoAcls); if (!string.IsNullOrEmpty(imageDescription)) { wim.SetImageDescription((int)wim.GetWimInfo().ImageCount, imageDescription); } if (!string.IsNullOrEmpty(imageDisplayName)) { wim.SetImageProperty((int)wim.GetWimInfo().ImageCount, "DISPLAYNAME", imageDisplayName); } if (!string.IsNullOrEmpty(imageDisplayDescription)) { wim.SetImageProperty((int)wim.GetWimInfo().ImageCount, "DISPLAYDESCRIPTION", imageDisplayDescription); } if (!string.IsNullOrEmpty(imageFlag)) { wim.SetImageFlags((int)wim.GetWimInfo().ImageCount, imageFlag); } if (UpdateFrom != -1) { wim.ReferenceTemplateImage((int)wim.GetWimInfo().ImageCount, UpdateFrom); } wim.Overwrite(WriteFlags.None, Wim.DefaultThreads); } } else { var compression = CompressionType.None; switch (compressionType) { case WimCompressionType.Lzms: { compression = CompressionType.LZMS; break; } case WimCompressionType.Lzx: { compression = CompressionType.LZX; break; } case WimCompressionType.None: { compression = CompressionType.None; break; } case WimCompressionType.Xpress: { compression = CompressionType.XPRESS; break; } } using (Wim wim = Wim.CreateNewWim(compression)) { wim.RegisterCallback(ProgressCallback); string config = @"[ExclusionList] \$ntfs.log \hiberfil.sys \pagefile.sys \swapfile.sys \System Volume Information"; var configpath = Path.GetTempFileName(); File.Delete(configpath); File.WriteAllText(configpath, config); wim.AddImage(InputDirectory, imageName, configpath, PreserveACL ? AddFlags.StrictAcls : AddFlags.NoAcls); if (!string.IsNullOrEmpty(imageDescription)) { wim.SetImageDescription((int)wim.GetWimInfo().ImageCount, imageDescription); } if (!string.IsNullOrEmpty(imageDisplayName)) { wim.SetImageProperty((int)wim.GetWimInfo().ImageCount, "DISPLAYNAME", imageDisplayName); } if (!string.IsNullOrEmpty(imageDisplayDescription)) { wim.SetImageProperty((int)wim.GetWimInfo().ImageCount, "DISPLAYDESCRIPTION", imageDisplayDescription); } if (!string.IsNullOrEmpty(imageFlag)) { wim.SetImageFlags((int)wim.GetWimInfo().ImageCount, imageFlag); } wim.Write(wimFile, Wim.AllImages, WriteFlags.None, Wim.DefaultThreads); File.Delete(configpath); } } } catch (Exception ex) { return(false); } return(ReseatWIMXml(wimFile)); }
public bool ExportImage(string wimFile, string destinationWimFile, int imageIndex, IEnumerable <string> referenceWIMs = null, WimCompressionType compressionType = WimCompressionType.Lzx, IImaging.ProgressCallback progressCallback = null) { string title = $"Exporting {wimFile.Split('\\').Last()} - Index {imageIndex}"; try { CallbackStatus ProgressCallback(ProgressMsg msg, object info, object progctx) { switch (msg) { case ProgressMsg.WriteStreams: { WriteStreamsProgress m = (WriteStreamsProgress)info; progressCallback?.Invoke(title, (int)Math.Round((double)m.CompletedBytes / m.TotalBytes * 100), false); } break; case ProgressMsg.WriteMetadataBegin: break; case ProgressMsg.WriteMetadataEnd: break; } return(CallbackStatus.Continue); } using (Wim srcWim = Wim.OpenWim(wimFile, OpenFlags.None)) { string imageName = srcWim.GetImageName(imageIndex); string imageDescription = srcWim.GetImageDescription(imageIndex); var compression = CompressionType.None; switch (compressionType) { case WimCompressionType.Lzms: { compression = CompressionType.LZMS; break; } case WimCompressionType.Lzx: { compression = CompressionType.LZX; break; } case WimCompressionType.None: { compression = CompressionType.None; break; } case WimCompressionType.Xpress: { compression = CompressionType.XPRESS; break; } } if (referenceWIMs != null && referenceWIMs.Count() > 0) { srcWim.ReferenceResourceFiles(referenceWIMs, RefFlags.None, OpenFlags.None); } if (File.Exists(destinationWimFile)) { using (Wim destWim = Wim.OpenWim(destinationWimFile, OpenFlags.WriteAccess)) { destWim.RegisterCallback(ProgressCallback); if (destWim.IsImageNameInUse(imageName)) { srcWim.ExportImage(imageIndex, destWim, imageName + " " + DateTime.UtcNow.ToString(), imageDescription, ExportFlags.None); } else { srcWim.ExportImage(imageIndex, destWim, imageName, imageDescription, ExportFlags.None); } destWim.Overwrite(WriteFlags.None, Wim.DefaultThreads); } } else { using (Wim destWim = Wim.CreateNewWim(compression)) { destWim.RegisterCallback(ProgressCallback); srcWim.ExportImage(imageIndex, destWim, imageName, imageDescription, ExportFlags.None); destWim.Write(destinationWimFile, Wim.AllImages, compression == CompressionType.LZMS ? WriteFlags.Solid : WriteFlags.None, Wim.DefaultThreads); } } } } catch (Exception ex) { return(false); } return(ReseatWIMXml(destinationWimFile)); }
public static bool CreateBaseEdition( string UUPPath, string LanguageCode, string EditionID, string InputWindowsREPath, string OutputInstallImage, Common.CompressionType CompressionType, ProgressCallback progressCallback = null) { bool result = true; 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; } HashSet <string> ReferencePackages, referencePackagesToConvert; string BaseESD = null; (result, BaseESD, ReferencePackages, referencePackagesToConvert) = FileLocator.LocateFilesForBaseEditionCreation(UUPPath, LanguageCode, EditionID, progressCallback); if (!result) { goto exit; } progressCallback?.Invoke(Common.ProcessPhase.PreparingFiles, true, 0, "Converting Reference Cabinets"); int counter = 0; int total = referencePackagesToConvert.Count; foreach (var file in referencePackagesToConvert) { int progressoffset = (int)Math.Round((double)counter / total * 100); int progressScale = (int)Math.Round((double)1 / total * 100); string refesd = ConvertCABToESD(Path.Combine(UUPPath, file), progressCallback, progressoffset, progressScale); if (string.IsNullOrEmpty(refesd)) { progressCallback?.Invoke(Common.ProcessPhase.ReadingMetadata, true, 0, "Reference ESD creation from Cabinet files failed"); goto exit; } ReferencePackages.Add(refesd); counter++; } // // Gather information to transplant later into DisplayName and DisplayDescription // WIMInformationXML.IMAGE image; imagingInterface.GetWIMImageInformation(BaseESD, 3, out image); // // Export the install image // void callback(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.ApplyingImage, IsIndeterminate, ProgressPercentage, Operation); }; result = imagingInterface.ExportImage( BaseESD, OutputInstallImage, 3, referenceWIMs: ReferencePackages, compressionType: compression, progressCallback: callback); if (!result) { goto exit; } WIMInformationXML.WIM wim; imagingInterface.GetWIMInformation(OutputInstallImage, out wim); // // Set the correct metadata on the image // image.DISPLAYNAME = image.NAME; image.DISPLAYDESCRIPTION = image.NAME; image.FLAGS = image.WINDOWS.EDITIONID; if (image.WINDOWS.LANGUAGES == null) { image.WINDOWS.LANGUAGES = new WIMInformationXML.LANGUAGES() { LANGUAGE = LanguageCode, FALLBACK = new WIMInformationXML.FALLBACK() { LANGUAGE = LanguageCode, Text = "en-US" }, DEFAULT = LanguageCode }; } result = imagingInterface.SetWIMImageInformation(OutputInstallImage, wim.IMAGE.Count, image); if (!result) { goto exit; } void callback2(string Operation, int ProgressPercentage, bool IsIndeterminate) { progressCallback?.Invoke(Common.ProcessPhase.IntegratingWinRE, IsIndeterminate, ProgressPercentage, Operation); }; // // Integrate the WinRE image into the installation image // progressCallback?.Invoke(Common.ProcessPhase.IntegratingWinRE, true, 0, ""); result = imagingInterface.AddFileToImage( OutputInstallImage, wim.IMAGE.Count, InputWindowsREPath, Path.Combine("Windows", "System32", "Recovery", "Winre.wim"), callback2); if (!result) { goto exit; } exit: return(result); }
public bool ExportImage( string wimFile, string destinationWimFile, int imageIndex, IEnumerable <string> referenceWIMs = null, WimCompressionType compressionType = WimCompressionType.Lzx, IImaging.ProgressCallback progressCallback = null) { return(WIMLibImaging.ExportImage(wimFile, destinationWimFile, imageIndex, referenceWIMs, compressionType, progressCallback)); string title = $"Exporting {wimFile.Split('\\').Last()} - Index {imageIndex}"; try { WimMessageResult callback2(WimMessageType messageType, object message, object userData) { switch (messageType) { case WimMessageType.Progress: { WimMessageProgress progressMessage = (WimMessageProgress)message; progressCallback?.Invoke($"{title} (Estimated time remaining: {progressMessage.EstimatedTimeRemaining})", progressMessage.PercentComplete, false); break; } } return(WimMessageResult.Success); } using (var wimHandle = WimgApi.CreateFile( wimFile, WimFileAccess.Read, WimCreationDisposition.OpenExisting, WimCreateFileOptions.Chunked, WimCompressionType.None)) { // Always set a temporary path // WimgApi.SetTemporaryPath(wimHandle, Environment.GetEnvironmentVariable("TEMP")); if (referenceWIMs != null) { foreach (var referenceFile in referenceWIMs) { WimgApi.SetReferenceFile(wimHandle, referenceFile, WimSetReferenceMode.Append, WimSetReferenceOptions.Chunked); } } // Register a method to be called while actions are performed by WIMGAPi for this .wim file // WimgApi.RegisterMessageCallback(wimHandle, callback2); using (var newWimHandle = WimgApi.CreateFile( destinationWimFile, WimFileAccess.Write, WimCreationDisposition.OpenAlways, compressionType == WimCompressionType.Lzms ? WimCreateFileOptions.Chunked : WimCreateFileOptions.None, compressionType)) { // Always set a temporary path // WimgApi.SetTemporaryPath(newWimHandle, Environment.GetEnvironmentVariable("TEMP")); // Register a method to be called while actions are performed by WIMGAPi for this .wim file // WimgApi.RegisterMessageCallback(newWimHandle, callback2); try { using (WimHandle imageHandle = WimgApi.LoadImage(wimHandle, imageIndex)) { var wiminfo = WimgApi.GetImageInformationAsString(imageHandle); var wiminfoclass = WIMInformationXML.DeserializeIMAGE(wiminfo); string imagename = wiminfoclass.DISPLAYNAME == null ? wiminfoclass.NAME : wiminfoclass.DISPLAYNAME; title = $"Exporting {imagename} ({wimFile.Split('\\').Last()} - Index {imageIndex})"; // Export the image contents // This call is blocking but WIMGAPI will be calling MyCallbackMethod() during the process // WimgApi.ExportImage(imageHandle, newWimHandle, WimExportImageOptions.AllowDuplicates); } } finally { // Be sure to unregister the callback method // WimgApi.UnregisterMessageCallback(wimHandle, callback2); // Be sure to unregister the callback method // WimgApi.UnregisterMessageCallback(newWimHandle, callback2); } } } } catch { return(false); } return(true); }
public bool CaptureImage( string wimFile, string imageName, string imageDescription, string imageFlag, string InputDirectory, string imageDisplayName = null, string imageDisplayDescription = null, WIMInformationXML.WINDOWS windows = null, WimCompressionType compressionType = WimCompressionType.Lzx, WimCaptureImageOptions addFlags = WimCaptureImageOptions.None, IImaging.ProgressCallback progressCallback = null) { string title = $"Creating {imageName} ({wimFile.Split('\\').Last()})"; try { int directoriesScanned = 0; int filesScanned = 0; WimMessageResult callback2(WimMessageType messageType, object message, object userData) { switch (messageType) { case WimMessageType.Process: { WimMessageProcess processMessage = (WimMessageProcess)message; if (processMessage.Path.StartsWith(Path.Combine(InputDirectory.EndsWith(":") ? InputDirectory + @"\" : InputDirectory, @"System Volume Information"), StringComparison.InvariantCultureIgnoreCase)) { processMessage.Process = false; } break; } case WimMessageType.Progress: { WimMessageProgress progressMessage = (WimMessageProgress)message; progressCallback?.Invoke($"{title} (Estimated time remaining: {progressMessage.EstimatedTimeRemaining})", progressMessage.PercentComplete, false); break; } case WimMessageType.Scanning: { WimMessageScanning scanningMessage = (WimMessageScanning)message; switch (scanningMessage.CountType) { case WimMessageScanningType.Directories: { directoriesScanned = scanningMessage.Count; break; } case WimMessageScanningType.Files: { filesScanned = scanningMessage.Count; break; } } progressCallback?.Invoke($"Scanning objects ({filesScanned} files, {directoriesScanned} directories scanned)", 0, true); break; } } return(WimMessageResult.Success); } using (var wimHandle = WimgApi.CreateFile( wimFile, WimFileAccess.Write, WimCreationDisposition.OpenAlways, compressionType == WimCompressionType.Lzms ? WimCreateFileOptions.Chunked : WimCreateFileOptions.None, compressionType)) { // Always set a temporary path // WimgApi.SetTemporaryPath(wimHandle, Environment.GetEnvironmentVariable("TEMP")); // Register a method to be called while actions are performed by WIMGAPi for this .wim file // WimgApi.RegisterMessageCallback(wimHandle, callback2); try { using (var imagehandle = WimgApi.CaptureImage(wimHandle, InputDirectory, addFlags)) { var wiminfo = WimgApi.GetImageInformationAsString(imagehandle); var wiminfoclass = WIMInformationXML.DeserializeIMAGE(wiminfo); if (!string.IsNullOrEmpty(imageFlag)) { wiminfoclass.FLAGS = imageFlag; } if (!string.IsNullOrEmpty(imageName)) { wiminfoclass.NAME = imageName; } if (!string.IsNullOrEmpty(imageDescription)) { wiminfoclass.DESCRIPTION = imageDescription; } if (!string.IsNullOrEmpty(imageDisplayName)) { wiminfoclass.DISPLAYNAME = imageDisplayName; } if (!string.IsNullOrEmpty(imageDisplayDescription)) { wiminfoclass.DISPLAYDESCRIPTION = imageDisplayDescription; } if (windows != null) { wiminfoclass.WINDOWS = windows; } wiminfo = WIMInformationXML.SerializeIMAGE(wiminfoclass); WimgApi.SetImageInformation(imagehandle, wiminfo); } } finally { // Be sure to unregister the callback method // WimgApi.UnregisterMessageCallback(wimHandle, callback2); } } } catch { return(false); } return(true); }