diff --git a/InstaSoftOfficeTool.csproj b/InstaSoftOfficeTool.csproj index b6e3152..118726f 100644 --- a/InstaSoftOfficeTool.csproj +++ b/InstaSoftOfficeTool.csproj @@ -9,15 +9,16 @@ InstaSoft Zrt. InstaSoft Office Tool Copyright (c) InstaSoft Zrt. 2026 - 1.0.8 - 1.0.8.0 - 1.0.8.0 + 1.0.9 + 1.0.9.0 + 1.0.9.0 app.manifest latest + diff --git a/MainWindow.xaml b/MainWindow.xaml index eefdfca..c5c6701 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -45,7 +45,7 @@ Foreground="{StaticResource TextSecondaryBrush}" Margin="0,-2,0,0"/> - diff --git a/Pages/PreInstallCheckPage.xaml.cs b/Pages/PreInstallCheckPage.xaml.cs index 8f0d0bd..d0a1356 100644 --- a/Pages/PreInstallCheckPage.xaml.cs +++ b/Pages/PreInstallCheckPage.xaml.cs @@ -73,67 +73,85 @@ namespace InstaSoftOfficeTool.Pages BtnSkip.IsEnabled = false; LogPanel.Visibility = Visibility.Visible; - bool hasC2R = false; - foreach (UIElement child in OfficeListPanel.Children) + try { - if (child is CheckBox cb && cb.IsChecked == true) + var c2rProducts = new System.Collections.Generic.List(); + + foreach (UIElement child in OfficeListPanel.Children) { - var office = (InstalledOffice)cb.Tag; - if (office.IsClickToRun) + if (child is CheckBox cb && cb.IsChecked == true) { - hasC2R = true; - } - else if (!string.IsNullOrEmpty(office.ProductCode)) - { - AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName); - var runner = new ProcessRunner(); - runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg)); - await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb"); + var office = (InstalledOffice)cb.Tag; + if (office.IsClickToRun) + { + c2rProducts.Add(office.ProductCode); + } + else if (!string.IsNullOrEmpty(office.ProductCode)) + { + AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName); + var runner = new ProcessRunner(); + runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg)); + int code = await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb"); + AppendLog("MSI exit code: " + code); + } } } - } - if (hasC2R) - { - AppendLog("Click-to-Run Office elt\u00e1vol\u00edt\u00e1sa..."); - var downloader = new OdtDownloader(); - downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg)); - - bool ok = await downloader.DownloadAndExtractAsync(); - if (ok) + if (c2rProducts.Count > 0) { - string removeXml = OdtXmlGenerator.GenerateRemoveAll(); + AppendLog("Click-to-Run term\u00e9kek elt\u00e1vol\u00edt\u00e1sa: " + string.Join(", ", c2rProducts)); + + var downloader = new OdtDownloader(); + downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg)); + + bool ok = await downloader.DownloadAndExtractAsync(); + if (!ok) + { + AppendLog("HIBA: Az ODT let\u00f6lt\u00e9se sikertelen."); + BtnRemove.IsEnabled = true; + BtnSkip.IsEnabled = true; + return; + } + + string removeXml = OdtXmlGenerator.GenerateRemoveProducts(c2rProducts.ToArray()); string xmlPath = Path.Combine(downloader.OdtFolder, "remove.xml"); File.WriteAllText(xmlPath, removeXml); + AppendLog("Futtat\u00e1s: setup.exe /configure remove.xml"); + AppendLog("Ez eltarthat n\u00e9h\u00e1ny percig..."); + int exitCode = await downloader.RunRemoveAsync(xmlPath, msg => Dispatcher.Invoke(() => AppendLog(msg))); + AppendLog("setup.exe exit code: " + exitCode); AppendLog(exitCode == 0 ? "Office sikeresen elt\u00e1vol\u00edtva." - : "Elt\u00e1vol\u00edt\u00e1s befejez\u0151d\u00f6tt (k\u00f3d: " + exitCode + ")"); + : "FIGYELEM: Az elt\u00e1vol\u00edt\u00e1s nem siker\u00fclt (k\u00f3d: " + exitCode + ")"); } - } - if (CbCleanLicense.IsChecked == true) + if (CbCleanLicense.IsChecked == true) + { + AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa..."); + var lm = new LicenseManager(); + if (lm.FindOspp()) + { + var cleanResult = await lm.RemoveAllKeysAsync(); + AppendLog(cleanResult); + } + else + { + AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva."); + } + } + + AppendLog("K\u00e9sz. Tov\u00e1bbl\u00e9p\u00e9s az \u00faj Office telep\u00edt\u00e9s\u00e9hez..."); + } + catch (Exception ex) { - AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa..."); - var lm = new LicenseManager(); - if (lm.FindOspp()) - { - var cleanResult = await lm.RemoveAllKeysAsync(); - AppendLog(cleanResult); - } - else - { - AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva."); - } + AppendLog("V\u00e1ratlan hiba: " + ex.Message); } - AppendLog("K\u00e9sz. Tov\u00e1bbl\u00e9p\u00e9s az \u00faj Office telep\u00edt\u00e9s\u00e9hez..."); - - // Auto-proceed to install after short delay - await System.Threading.Tasks.Task.Delay(1500); + await System.Threading.Tasks.Task.Delay(2000); _main.ProceedToInstall(); } diff --git a/Pages/RemovePage.xaml.cs b/Pages/RemovePage.xaml.cs index b3334f0..83e7364 100644 --- a/Pages/RemovePage.xaml.cs +++ b/Pages/RemovePage.xaml.cs @@ -61,65 +61,96 @@ namespace InstaSoftOfficeTool.Pages BtnRemove.IsEnabled = false; LogPanel.Visibility = Visibility.Visible; - bool hasC2R = false; - foreach (UIElement child in OfficeListPanel.Children) + try { - if (child is CheckBox cb && cb.IsChecked == true) + var c2rProducts = new System.Collections.Generic.List(); + + foreach (UIElement child in OfficeListPanel.Children) { - var office = (InstalledOffice)cb.Tag; - if (office.IsClickToRun) + if (child is CheckBox cb && cb.IsChecked == true) { - hasC2R = true; - } - else if (!string.IsNullOrEmpty(office.ProductCode)) - { - AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName); - var runner = new ProcessRunner(); - runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg)); - await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb"); + var office = (InstalledOffice)cb.Tag; + if (office.IsClickToRun) + { + c2rProducts.Add(office.ProductCode); + } + else if (!string.IsNullOrEmpty(office.ProductCode)) + { + AppendLog("MSI elt\u00e1vol\u00edt\u00e1s: " + office.DisplayName); + var runner = new ProcessRunner(); + runner.OutputReceived += msg => Dispatcher.Invoke(() => AppendLog(msg)); + int code = await runner.RunAsync("msiexec", "/x " + office.ProductCode + " /qb"); + AppendLog("MSI exit code: " + code); + } } } - } - if (hasC2R) - { - AppendLog("Click-to-Run Office elt\u00e1vol\u00edt\u00e1sa ODT-vel..."); - - var downloader = new OdtDownloader(); - downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg)); - - bool ok = await downloader.DownloadAndExtractAsync(); - if (ok) + if (c2rProducts.Count > 0) { - string removeXml = OdtXmlGenerator.GenerateRemoveAll(); + AppendLog("Click-to-Run term\u00e9kek elt\u00e1vol\u00edt\u00e1sa: " + string.Join(", ", c2rProducts)); + + var downloader = new OdtDownloader(); + downloader.StatusChanged += msg => Dispatcher.Invoke(() => AppendLog(msg)); + + bool ok = await downloader.DownloadAndExtractAsync(); + if (!ok) + { + AppendLog("HIBA: Az ODT let\u00f6lt\u00e9se sikertelen."); + BtnRemove.IsEnabled = true; + return; + } + + string removeXml = OdtXmlGenerator.GenerateRemoveProducts(c2rProducts.ToArray()); string xmlPath = Path.Combine(downloader.OdtFolder, "remove.xml"); File.WriteAllText(xmlPath, removeXml); + AppendLog("Remove XML:"); + AppendLog(removeXml); + AppendLog(""); + AppendLog("Futtat\u00e1s: setup.exe /configure remove.xml"); + AppendLog("Ez eltarthat n\u00e9h\u00e1ny percig..."); + int exitCode = await downloader.RunRemoveAsync(xmlPath, msg => Dispatcher.Invoke(() => AppendLog(msg))); - AppendLog(exitCode == 0 - ? "Office sikeresen elt\u00e1vol\u00edtva." - : "Elt\u00e1vol\u00edt\u00e1s befejez\u0151d\u00f6tt (k\u00f3d: " + exitCode + ")"); - } - } + AppendLog("setup.exe exit code: " + exitCode); - if (CbCleanLicense.IsChecked == true) + if (exitCode == 0) + { + AppendLog("Office sikeresen elt\u00e1vol\u00edtva."); + } + else + { + AppendLog("FIGYELEM: Az elt\u00e1vol\u00edt\u00e1s nem siker\u00fclt (k\u00f3d: " + exitCode + ")"); + AppendLog("Pr\u00f3b\u00e1lja meg manu\u00e1lisan: Vez\u00e9rl\u0151pult > Programok elt\u00e1vol\u00edt\u00e1sa"); + } + } + + if (CbCleanLicense.IsChecked == true) + { + AppendLog(""); + AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa..."); + var lm = new LicenseManager(); + if (lm.FindOspp()) + { + var cleanResult = await lm.RemoveAllKeysAsync(); + AppendLog(cleanResult); + } + else + { + AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva."); + } + } + + AppendLog(""); + AppendLog("K\u00e9sz."); + } + catch (Exception ex) { - AppendLog("Licenc-adatb\u00e1zis tiszt\u00edt\u00e1sa..."); - var lm = new LicenseManager(); - if (lm.FindOspp()) - { - var cleanResult = await lm.RemoveAllKeysAsync(); - AppendLog(cleanResult); - } - else - { - AppendLog("Az ospp.vbs nem tal\u00e1lhat\u00f3 \u2014 licenc-tiszt\u00edt\u00e1s kihagyva."); - } + AppendLog("V\u00e1ratlan hiba: " + ex.Message); + AppendLog(ex.StackTrace); } - AppendLog("K\u00e9sz."); _main.ShowCloseButton(); } diff --git a/Services/OdtDownloader.cs b/Services/OdtDownloader.cs index 816337f..9ce78d7 100644 --- a/Services/OdtDownloader.cs +++ b/Services/OdtDownloader.cs @@ -1,16 +1,16 @@ using System; using System.IO; -using System.Net; +using System.Net.Http; using System.Threading.Tasks; namespace InstaSoftOfficeTool.Services { public class OdtDownloader { - private const string OdtDownloadUrl = "https://go.microsoft.com/fwlink/p/?LinkID=626065"; + // Direct CDN link to ODT setup.exe (no self-extractor needed) + private const string OdtDownloadUrl = "https://officecdn.microsoft.com/pr/wsus/setup.exe"; public event Action StatusChanged; - public event Action ProgressChanged; public string OdtFolder { get; private set; } public string SetupExePath { get; private set; } @@ -24,53 +24,70 @@ namespace InstaSoftOfficeTool.Services { try { - Directory.CreateDirectory(OdtFolder); - - var odtExePath = Path.Combine(OdtFolder, "officedeploymenttool.exe"); SetupExePath = Path.Combine(OdtFolder, "setup.exe"); + // Check if valid setup.exe already exists if (File.Exists(SetupExePath)) { - StatusChanged?.Invoke("Az ODT setup.exe m\u00e1r el\u00e9rhet\u0151, let\u00f6lt\u00e9s kihagyva."); - return true; - } - - StatusChanged?.Invoke("Office Deployment Tool let\u00f6lt\u00e9se..."); - - using (var client = new WebClient()) - { - client.DownloadProgressChanged += (s, e) => + var existingSize = new FileInfo(SetupExePath).Length; + if (existingSize > 1000000) // valid setup.exe is ~7MB { - ProgressChanged?.Invoke(e.ProgressPercentage); - }; + StatusChanged?.Invoke("Az ODT setup.exe m\u00e1r el\u00e9rhet\u0151 (" + + (existingSize / 1024 / 1024) + " MB)."); + return true; + } - await client.DownloadFileTaskAsync(new Uri(OdtDownloadUrl), odtExePath); + // Delete corrupted file + StatusChanged?.Invoke("S\u00e9r\u00fclt setup.exe t\u00f6rl\u00e9se..."); + File.Delete(SetupExePath); } - StatusChanged?.Invoke("ODT kicsomagol\u00e1sa..."); + Directory.CreateDirectory(OdtFolder); - var runner = new ProcessRunner(); - var exitCode = await runner.RunAsync(odtExePath, - "/extract:\"" + OdtFolder + "\" /quiet"); + // Download setup.exe directly from CDN + StatusChanged?.Invoke("Office Deployment Tool let\u00f6lt\u00e9se..."); + StatusChanged?.Invoke("URL: " + OdtDownloadUrl); - if (exitCode != 0) + using (var handler = new HttpClientHandler { AllowAutoRedirect = true }) + using (var client = new HttpClient(handler)) { - StatusChanged?.Invoke("Hiba: Az ODT kicsomagol\u00e1sa sikertelen (k\u00f3d: " + exitCode + ")"); + client.DefaultRequestHeaders.Add("User-Agent", "InstaSoftOfficeTool/1.0"); + client.Timeout = TimeSpan.FromMinutes(5); + + var response = await client.GetAsync(OdtDownloadUrl); + + if (!response.IsSuccessStatusCode) + { + StatusChanged?.Invoke("Hiba: HTTP " + (int)response.StatusCode + " " + response.StatusCode); + return false; + } + + var contentType = response.Content.Headers.ContentType?.MediaType ?? ""; + if (contentType.Contains("text/html")) + { + StatusChanged?.Invoke("Hiba: HTML oldal \u00e9rkezett exe helyett."); + StatusChanged?.Invoke("T\u00f6ltse le manu\u00e1lisan: https://www.microsoft.com/en-us/download/details.aspx?id=49117"); + return false; + } + + var bytes = await response.Content.ReadAsByteArrayAsync(); + File.WriteAllBytes(SetupExePath, bytes); + + StatusChanged?.Invoke("Let\u00f6ltve: " + (bytes.Length / 1024) + " KB"); + } + + if (!File.Exists(SetupExePath) || new FileInfo(SetupExePath).Length < 1000000) + { + StatusChanged?.Invoke("Hiba: A let\u00f6lt\u00f6tt f\u00e1jl s\u00e9r\u00fclt vagy t\u00fal kicsi."); return false; } - if (!File.Exists(SetupExePath)) - { - StatusChanged?.Invoke("Hiba: A setup.exe nem tal\u00e1lhat\u00f3 a kicsomagol\u00e1s ut\u00e1n."); - return false; - } - - StatusChanged?.Invoke("ODT sikeresen let\u00f6ltve \u00e9s kicsomagolva."); + StatusChanged?.Invoke("ODT setup.exe k\u00e9sz."); return true; } catch (Exception ex) { - StatusChanged?.Invoke("Hiba a let\u00f6lt\u00e9s sor\u00e1n: " + ex.Message); + StatusChanged?.Invoke("Hiba: " + ex.GetType().Name + ": " + ex.Message); return false; } } diff --git a/Services/OdtXmlGenerator.cs b/Services/OdtXmlGenerator.cs index 5ea332c..52c8f82 100644 --- a/Services/OdtXmlGenerator.cs +++ b/Services/OdtXmlGenerator.cs @@ -46,7 +46,31 @@ namespace InstaSoftOfficeTool.Services new XElement("Remove", new XAttribute("All", "TRUE")), new XElement("Display", new XAttribute("Level", "Full"), - new XAttribute("AcceptEULA", "TRUE"))); + new XAttribute("AcceptEULA", "TRUE")), + new XElement("Property", + new XAttribute("Name", "FORCEAPPSHUTDOWN"), + new XAttribute("Value", "TRUE"))); + + var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration); + return doc.Declaration + "\n" + doc.Root; + } + + public static string GenerateRemoveProducts(string[] productIds) + { + var remove = new XElement("Remove"); + foreach (var id in productIds) + { + remove.Add(new XElement("Product", new XAttribute("ID", id))); + } + + var configuration = new XElement("Configuration", + remove, + new XElement("Display", + new XAttribute("Level", "Full"), + new XAttribute("AcceptEULA", "TRUE")), + new XElement("Property", + new XAttribute("Name", "FORCEAPPSHUTDOWN"), + new XAttribute("Value", "TRUE"))); var doc = new XDocument(new XDeclaration("1.0", "utf-8", null), configuration); return doc.Declaration + "\n" + doc.Root; diff --git a/Services/OfficeDetector.cs b/Services/OfficeDetector.cs index 8694fe0..115227e 100644 --- a/Services/OfficeDetector.cs +++ b/Services/OfficeDetector.cs @@ -31,12 +31,20 @@ namespace InstaSoftOfficeTool.Services var productIds = key.GetValue("ProductReleaseIds") as string; var versionToReport = key.GetValue("VersionToReport") as string; - if (!string.IsNullOrEmpty(productIds)) + if (string.IsNullOrEmpty(productIds)) return; + + // Split into individual products (e.g. "O365BusinessRetail,VisioProRetail") + var ids = productIds.Split(','); + foreach (var id in ids) { + var trimmedId = id.Trim(); + if (string.IsNullOrEmpty(trimmedId)) continue; + results.Add(new InstalledOffice { - DisplayName = "Microsoft Office Click-to-Run (" + productIds + ")", + DisplayName = "Microsoft Office Click-to-Run (" + trimmedId + ")", Version = versionToReport ?? "", + ProductCode = trimmedId, IsClickToRun = true, IsSelected = true });