diff --git a/src/App.xaml b/App.xaml
similarity index 100%
rename from src/App.xaml
rename to App.xaml
diff --git a/src/App.xaml.cs b/App.xaml.cs
similarity index 100%
rename from src/App.xaml.cs
rename to App.xaml.cs
diff --git a/src/InstaSoftOfficeTool.csproj b/InstaSoftOfficeTool.csproj
similarity index 100%
rename from src/InstaSoftOfficeTool.csproj
rename to InstaSoftOfficeTool.csproj
diff --git a/src/MainWindow.xaml b/MainWindow.xaml
similarity index 100%
rename from src/MainWindow.xaml
rename to MainWindow.xaml
diff --git a/src/MainWindow.xaml.cs b/MainWindow.xaml.cs
similarity index 100%
rename from src/MainWindow.xaml.cs
rename to MainWindow.xaml.cs
diff --git a/src/Models/InstallConfig.cs b/Models/InstallConfig.cs
similarity index 100%
rename from src/Models/InstallConfig.cs
rename to Models/InstallConfig.cs
diff --git a/src/Models/InstalledOffice.cs b/Models/InstalledOffice.cs
similarity index 100%
rename from src/Models/InstalledOffice.cs
rename to Models/InstalledOffice.cs
diff --git a/src/Models/OfficeEdition.cs b/Models/OfficeEdition.cs
similarity index 100%
rename from src/Models/OfficeEdition.cs
rename to Models/OfficeEdition.cs
diff --git a/src/Models/OfficeVersion.cs b/Models/OfficeVersion.cs
similarity index 100%
rename from src/Models/OfficeVersion.cs
rename to Models/OfficeVersion.cs
diff --git a/src/Pages/ConfigPage.xaml b/Pages/ConfigPage.xaml
similarity index 100%
rename from src/Pages/ConfigPage.xaml
rename to Pages/ConfigPage.xaml
diff --git a/src/Pages/ConfigPage.xaml.cs b/Pages/ConfigPage.xaml.cs
similarity index 100%
rename from src/Pages/ConfigPage.xaml.cs
rename to Pages/ConfigPage.xaml.cs
diff --git a/src/Pages/ConfirmDialog.xaml b/Pages/ConfirmDialog.xaml
similarity index 100%
rename from src/Pages/ConfirmDialog.xaml
rename to Pages/ConfirmDialog.xaml
diff --git a/src/Pages/ConfirmDialog.xaml.cs b/Pages/ConfirmDialog.xaml.cs
similarity index 100%
rename from src/Pages/ConfirmDialog.xaml.cs
rename to Pages/ConfirmDialog.xaml.cs
diff --git a/src/Pages/EditionPage.xaml b/Pages/EditionPage.xaml
similarity index 100%
rename from src/Pages/EditionPage.xaml
rename to Pages/EditionPage.xaml
diff --git a/src/Pages/EditionPage.xaml.cs b/Pages/EditionPage.xaml.cs
similarity index 100%
rename from src/Pages/EditionPage.xaml.cs
rename to Pages/EditionPage.xaml.cs
diff --git a/src/Pages/PreInstallCheckPage.xaml b/Pages/PreInstallCheckPage.xaml
similarity index 100%
rename from src/Pages/PreInstallCheckPage.xaml
rename to Pages/PreInstallCheckPage.xaml
diff --git a/src/Pages/PreInstallCheckPage.xaml.cs b/Pages/PreInstallCheckPage.xaml.cs
similarity index 100%
rename from src/Pages/PreInstallCheckPage.xaml.cs
rename to Pages/PreInstallCheckPage.xaml.cs
diff --git a/src/Pages/ProductKeyDialog.xaml b/Pages/ProductKeyDialog.xaml
similarity index 100%
rename from src/Pages/ProductKeyDialog.xaml
rename to Pages/ProductKeyDialog.xaml
diff --git a/src/Pages/ProductKeyDialog.xaml.cs b/Pages/ProductKeyDialog.xaml.cs
similarity index 100%
rename from src/Pages/ProductKeyDialog.xaml.cs
rename to Pages/ProductKeyDialog.xaml.cs
diff --git a/src/Pages/ProductKeyPage.xaml b/Pages/ProductKeyPage.xaml
similarity index 100%
rename from src/Pages/ProductKeyPage.xaml
rename to Pages/ProductKeyPage.xaml
diff --git a/src/Pages/ProductKeyPage.xaml.cs b/Pages/ProductKeyPage.xaml.cs
similarity index 100%
rename from src/Pages/ProductKeyPage.xaml.cs
rename to Pages/ProductKeyPage.xaml.cs
diff --git a/src/Pages/ProgressPage.xaml b/Pages/ProgressPage.xaml
similarity index 100%
rename from src/Pages/ProgressPage.xaml
rename to Pages/ProgressPage.xaml
diff --git a/src/Pages/ProgressPage.xaml.cs b/Pages/ProgressPage.xaml.cs
similarity index 100%
rename from src/Pages/ProgressPage.xaml.cs
rename to Pages/ProgressPage.xaml.cs
diff --git a/src/Pages/RemovePage.xaml b/Pages/RemovePage.xaml
similarity index 100%
rename from src/Pages/RemovePage.xaml
rename to Pages/RemovePage.xaml
diff --git a/src/Pages/RemovePage.xaml.cs b/Pages/RemovePage.xaml.cs
similarity index 100%
rename from src/Pages/RemovePage.xaml.cs
rename to Pages/RemovePage.xaml.cs
diff --git a/src/Pages/SummaryPage.xaml b/Pages/SummaryPage.xaml
similarity index 100%
rename from src/Pages/SummaryPage.xaml
rename to Pages/SummaryPage.xaml
diff --git a/src/Pages/SummaryPage.xaml.cs b/Pages/SummaryPage.xaml.cs
similarity index 100%
rename from src/Pages/SummaryPage.xaml.cs
rename to Pages/SummaryPage.xaml.cs
diff --git a/src/Pages/TroubleshootPage.xaml b/Pages/TroubleshootPage.xaml
similarity index 100%
rename from src/Pages/TroubleshootPage.xaml
rename to Pages/TroubleshootPage.xaml
diff --git a/src/Pages/TroubleshootPage.xaml.cs b/Pages/TroubleshootPage.xaml.cs
similarity index 100%
rename from src/Pages/TroubleshootPage.xaml.cs
rename to Pages/TroubleshootPage.xaml.cs
diff --git a/src/Pages/VersionPage.xaml b/Pages/VersionPage.xaml
similarity index 100%
rename from src/Pages/VersionPage.xaml
rename to Pages/VersionPage.xaml
diff --git a/src/Pages/VersionPage.xaml.cs b/Pages/VersionPage.xaml.cs
similarity index 100%
rename from src/Pages/VersionPage.xaml.cs
rename to Pages/VersionPage.xaml.cs
diff --git a/src/Pages/WelcomePage.xaml b/Pages/WelcomePage.xaml
similarity index 100%
rename from src/Pages/WelcomePage.xaml
rename to Pages/WelcomePage.xaml
diff --git a/src/Pages/WelcomePage.xaml.cs b/Pages/WelcomePage.xaml.cs
similarity index 100%
rename from src/Pages/WelcomePage.xaml.cs
rename to Pages/WelcomePage.xaml.cs
diff --git a/src/Resources/app.ico b/Resources/app.ico
similarity index 100%
rename from src/Resources/app.ico
rename to Resources/app.ico
diff --git a/src/Services/LicenseManager.cs b/Services/LicenseManager.cs
similarity index 100%
rename from src/Services/LicenseManager.cs
rename to Services/LicenseManager.cs
diff --git a/src/Services/OdtDownloader.cs b/Services/OdtDownloader.cs
similarity index 100%
rename from src/Services/OdtDownloader.cs
rename to Services/OdtDownloader.cs
diff --git a/src/Services/OdtXmlGenerator.cs b/Services/OdtXmlGenerator.cs
similarity index 100%
rename from src/Services/OdtXmlGenerator.cs
rename to Services/OdtXmlGenerator.cs
diff --git a/src/Services/OfficeDetector.cs b/Services/OfficeDetector.cs
similarity index 100%
rename from src/Services/OfficeDetector.cs
rename to Services/OfficeDetector.cs
diff --git a/src/Services/ProcessRunner.cs b/Services/ProcessRunner.cs
similarity index 100%
rename from src/Services/ProcessRunner.cs
rename to Services/ProcessRunner.cs
diff --git a/src/Styles/ButtonStyles.xaml b/Styles/ButtonStyles.xaml
similarity index 100%
rename from src/Styles/ButtonStyles.xaml
rename to Styles/ButtonStyles.xaml
diff --git a/src/Styles/ControlStyles.xaml b/Styles/ControlStyles.xaml
similarity index 100%
rename from src/Styles/ControlStyles.xaml
rename to Styles/ControlStyles.xaml
diff --git a/src/Styles/FluentTheme.xaml b/Styles/FluentTheme.xaml
similarity index 100%
rename from src/Styles/FluentTheme.xaml
rename to Styles/FluentTheme.xaml
diff --git a/src/app.manifest b/app.manifest
similarity index 100%
rename from src/app.manifest
rename to app.manifest
diff --git a/powershell/InstaSoftOfficeTool.ps1 b/powershell/InstaSoftOfficeTool.ps1
deleted file mode 100644
index a40dc42..0000000
--- a/powershell/InstaSoftOfficeTool.ps1
+++ /dev/null
@@ -1,1155 +0,0 @@
-#Requires -Version 5.1
-# InstaSoft Office Tool v1.14 — PowerShell Edition
-# Copyright (c) InstaSoft Informatikai Zrt. 2026
-# Office deployment wizard: install, remove, license management
-
-# --- Request admin elevation ---
-if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
- Start-Process powershell.exe -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
- exit
-}
-
-Add-Type -AssemblyName PresentationFramework
-Add-Type -AssemblyName PresentationCore
-Add-Type -AssemblyName WindowsBase
-Add-Type -AssemblyName System.Net.Http
-
-# ============================================================
-# DATA
-# ============================================================
-$script:Config = @{
- Version = 'Office2024'
- Edition = $null
- Architecture = '64'
- Language = 'hu-hu'
- ProductKey = ''
- ExcludedApps = @()
-}
-
-$script:Editions = @{
- Office2024 = @(
- @{ DisplayName='Standard'; Description='Alapveto irodai alkalmazasok: Word, Excel, PowerPoint, Outlook, OneNote'; ProductId='Standard2024Volume'; Channel='PerpetualVL2024'; IsVolume=$true },
- @{ DisplayName='Professional Plus'; Description='Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote'; ProductId='ProPlus2024Volume'; Channel='PerpetualVL2024'; IsVolume=$true },
- @{ DisplayName="Otthoni `u{00e9}s kisv`u{00e1}llalati verzi`u{00f3}"; Description="Word, Excel, PowerPoint, Outlook, OneNote `u{2014} v`u{00e1}llalkoz`u{00e1}sokban is haszn`u{00e1}lhat`u{00f3}"; ProductId='HomeBusiness2024Retail'; Channel='Current'; IsVolume=$false }
- )
- Office2021 = @(
- @{ DisplayName='Standard'; Description='Alapveto irodai alkalmazasok: Word, Excel, PowerPoint, Outlook, OneNote'; ProductId='Standard2021Volume'; Channel='PerpetualVL2021'; IsVolume=$true },
- @{ DisplayName='Professional Plus'; Description='Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote'; ProductId='ProPlus2021Volume'; Channel='PerpetualVL2021'; IsVolume=$true },
- @{ DisplayName="Otthoni `u{00e9}s kisv`u{00e1}llalati verzi`u{00f3}"; Description="Word, Excel, PowerPoint, Outlook, OneNote `u{2014} v`u{00e1}llalkoz`u{00e1}sokban is haszn`u{00e1}lhat`u{00f3}"; ProductId='HomeBusiness2021Retail'; Channel='Current'; IsVolume=$false }
- )
- Office2019 = @(
- @{ DisplayName='Standard'; Description='Alapveto irodai alkalmazasok: Word, Excel, PowerPoint, Outlook, OneNote'; ProductId='Standard2019Volume'; Channel='PerpetualVL2019'; IsVolume=$true },
- @{ DisplayName='Professional Plus'; Description='Teljes csomag: Word, Excel, PowerPoint, Outlook, Access, Publisher, OneNote, Skype for Business'; ProductId='ProPlus2019Volume'; Channel='PerpetualVL2019'; IsVolume=$true },
- @{ DisplayName="Otthoni `u{00e9}s kisv`u{00e1}llalati verzi`u{00f3}"; Description="Word, Excel, PowerPoint, Outlook, OneNote `u{2014} v`u{00e1}llalkoz`u{00e1}sokban is haszn`u{00e1}lhat`u{00f3}"; ProductId='HomeBusiness2019Retail'; Channel='Current'; IsVolume=$false }
- )
-}
-
-$script:Languages = @(
- @('hu-hu','Magyar'), @('en-us','English (US)'), @('de-de','Deutsch'),
- @('fr-fr','Fran\u00e7ais'), @('it-it','Italiano'), @('es-es','Espa\u00f1ol'),
- @('pt-pt','Portugu\u00eas'), @('nl-nl','Nederlands'), @('pl-pl','Polski'),
- @('cs-cz','\u010ce\u0161tina'), @('sk-sk','Sloven\u010dina'), @('ro-ro','Rom\u00e2n\u0103'),
- @('hr-hr','Hrvatski'), @('sl-si','Sloven\u0161\u010dina'), @('sr-latn-rs','Srpski'),
- @('bg-bg','Bulgarian'), @('uk-ua','Ukrainian'), @('ru-ru','Russian'),
- @('tr-tr','T\u00fcrk\u00e7e'), @('ja-jp','Japanese'), @('zh-cn','Chinese'), @('ko-kr','Korean')
-)
-
-$script:ExcludableApps = @(
- @{Id='Word'; Name='Word'; Default=$true; Min='all'},
- @{Id='Excel'; Name='Excel'; Default=$true; Min='all'},
- @{Id='PowerPoint'; Name='PowerPoint'; Default=$true; Min='all'},
- @{Id='Outlook'; Name='Outlook'; Default=$true; Min='all'},
- @{Id='OneNote'; Name='OneNote'; Default=$true; Min='all'},
- @{Id='Access'; Name='Access'; Default=$true; Min='proplus'},
- @{Id='Publisher'; Name='Publisher'; Default=$true; Min='standard+'},
- @{Id='Teams'; Name='Teams'; Default=$false; Min='all'},
- @{Id='Lync'; Name='Skype for Business'; Default=$false; Min='all'}
-)
-
-# ============================================================
-# XAML — Full UI in one window with panels
-# ============================================================
-[xml]$xaml = @'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'@
-
-# ============================================================
-# CREATE WINDOW
-# ============================================================
-$reader = New-Object System.Xml.XmlNodeReader $xaml
-$window = [Windows.Markup.XamlReader]::Load($reader)
-
-# Find all named elements
-$names = @('PanelWelcome','PanelVersion','PanelEdition','PanelConfig','PanelKey','PanelSummary',
- 'PanelProgress','PanelRemove','PanelLicense',
- 'BtnInstall','BtnRemoveWelcome','BtnLicenseWelcome','BtnBack','BtnNext','StepDots',
- 'Rb2024','Rb2021','Rb2019','Rb64','Rb32','CbLanguage','AppChecks',
- 'EditionSubtitle','EditionCards',
- 'K1','K2','K3','K4','K5','CbSkipKey',
- 'SummaryText','XmlPreview',
- 'ProgressTitle','ProgressStatus','ProgressBar','ProgressLog','DonePanel','DoneText',
- 'ActivateCard','BtnActivatePost','LaunchCard','LaunchBtns',
- 'RemoveList','BtnDoRemove',
- 'LicenseCards','BtnLicRefresh',
- 'OverlayConfirm','DlgTitle','DlgMsg','DlgOk','DlgCancel')
-
-$el = @{}
-foreach ($n in $names) {
- $el[$n] = $window.FindName($n)
-}
-
-# ============================================================
-# SERVICES (PowerShell functions)
-# ============================================================
-function Show-Panel($name) {
- $panels = @('PanelWelcome','PanelVersion','PanelEdition','PanelConfig','PanelKey','PanelSummary','PanelProgress','PanelRemove','PanelLicense')
- foreach ($p in $panels) {
- $el[$p].Visibility = if ($p -eq $name) { 'Visible' } else { 'Collapsed' }
- }
-}
-
-$script:CurrentPanel = 'PanelWelcome'
-$script:InstallPanels = @('PanelVersion','PanelEdition','PanelConfig','PanelKey','PanelSummary','PanelProgress')
-$script:InstallIndex = 0
-
-function Update-StepDots {
- $el['StepDots'].Children.Clear()
- $total = $script:InstallPanels.Count - 1 # exclude progress
- for ($i = 0; $i -lt $total; $i++) {
- $dot = New-Object Windows.Shapes.Ellipse
- $dot.Margin = [Windows.Thickness]::new(4,0,4,0)
- if ($i -le $script:InstallIndex) {
- $dot.Width = 10; $dot.Height = 10
- $dot.Fill = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(0,120,212))
- } else {
- $dot.Width = 8; $dot.Height = 8
- $dot.Fill = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(224,224,224))
- }
- $el['StepDots'].Children.Add($dot) | Out-Null
- }
-}
-
-function Navigate-Install($index) {
- $script:InstallIndex = $index
- $panel = $script:InstallPanels[$index]
- Show-Panel $panel
- $script:CurrentPanel = $panel
-
- if ($panel -eq 'PanelProgress') {
- $el['BtnBack'].Visibility = 'Collapsed'
- $el['BtnNext'].Visibility = 'Collapsed'
- $el['StepDots'].Children.Clear()
- } else {
- $el['BtnBack'].Visibility = 'Visible'
- $el['BtnNext'].Visibility = 'Visible'
- $el['BtnNext'].Content = "Tov`u{00e1}bb `u{2192}"
- Update-StepDots
- }
-}
-
-function Get-SelectedVersion {
- if ($el['Rb2024'].IsChecked) { return 'Office2024' }
- if ($el['Rb2021'].IsChecked) { return 'Office2021' }
- if ($el['Rb2019'].IsChecked) { return 'Office2019' }
- return 'Office2024'
-}
-
-function Get-VersionDisplayName($v) {
- switch ($v) {
- 'Office2024' { 'Office 2024' }
- 'Office2021' { 'Office 2021' }
- 'Office2019' { 'Office 2019' }
- }
-}
-
-function Build-EditionCards {
- $el['EditionCards'].Children.Clear()
- $ver = Get-SelectedVersion
- $script:Config.Version = $ver
- $el['EditionSubtitle'].Text = "$(Get-VersionDisplayName $ver) `u{2014} melyik kiad`u{00e1}st szeretn`u{00e9}?"
- $eds = $script:Editions[$ver]
- for ($i = 0; $i -lt $eds.Count; $i++) {
- $ed = $eds[$i]
- $rb = New-Object Windows.Controls.RadioButton
- $rb.GroupName = 'Edition'
- $rb.Style = $window.FindResource('CardRadio')
- $rb.Margin = [Windows.Thickness]::new(0,0,0,10)
- $rb.IsChecked = ($i -eq 0)
- $rb.Tag = $i
- $sp = New-Object Windows.Controls.StackPanel
- $sp.Margin = [Windows.Thickness]::new(8,2,8,2)
- $t1 = New-Object Windows.Controls.TextBlock
- $t1.Text = $ed.DisplayName; $t1.FontSize = 18; $t1.FontWeight = 'SemiBold'
- $t2 = New-Object Windows.Controls.TextBlock
- $t2.Text = $ed.Description; $t2.FontSize = 12
- $t2.Foreground = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(102,102,102))
- $sp.Children.Add($t1) | Out-Null
- $sp.Children.Add($t2) | Out-Null
- $rb.Content = $sp
- $el['EditionCards'].Children.Add($rb) | Out-Null
- }
-}
-
-function Get-SelectedEdition {
- $ver = $script:Config.Version
- $eds = $script:Editions[$ver]
- foreach ($child in $el['EditionCards'].Children) {
- if ($child -is [Windows.Controls.RadioButton] -and $child.IsChecked) {
- return $eds[$child.Tag]
- }
- }
- return $eds[0]
-}
-
-function Build-AppChecks {
- $el['AppChecks'].Children.Clear()
- $ed = $script:Config.Edition
- $isProPlus = $ed -and $ed.ProductId -match 'ProPlus'
- $isStandard = $ed -and $ed.ProductId -match 'Standard'
- foreach ($app in $script:ExcludableApps) {
- $unavailable = $false
- if ($app.Min -eq 'proplus' -and -not $isProPlus) { $unavailable = $true }
- elseif ($app.Min -eq 'standard+' -and -not $isProPlus -and -not $isStandard) { $unavailable = $true }
- $cb = New-Object Windows.Controls.CheckBox
- $cb.Content = $app.Name
- $cb.IsChecked = if ($unavailable) { $false } else { $app.Default }
- $cb.IsEnabled = -not $unavailable
- $cb.Style = $window.FindResource('FluentCB')
- $cb.Margin = [Windows.Thickness]::new(0,4,24,4)
- $cb.MinWidth = 160
- $cb.Tag = $app.Id
- $el['AppChecks'].Children.Add($cb) | Out-Null
- }
-}
-
-function Build-LanguageCombo {
- $el['CbLanguage'].Items.Clear()
- foreach ($lang in $script:Languages) {
- $item = New-Object Windows.Controls.ComboBoxItem
- $item.Content = "$($lang[1]) ($($lang[0]))"
- $item.Tag = $lang[0]
- $el['CbLanguage'].Items.Add($item) | Out-Null
- }
- $el['CbLanguage'].SelectedIndex = 0
-}
-
-function Get-ProductKey {
- $parts = @($el['K1'].Text, $el['K2'].Text, $el['K3'].Text, $el['K4'].Text, $el['K5'].Text)
- $all = ($parts | Where-Object { $_.Length -eq 5 })
- if ($all.Count -eq 5) { return ($parts -join '-').ToUpper() }
- return ''
-}
-
-function Generate-OdtXml {
- $c = $script:Config
- $xml = "`n`n"
- $xml += " `n"
- $xml += " `n"
- $xml += " `n"
- foreach ($app in $c.ExcludedApps) { $xml += " `n" }
- $xml += " `n `n"
- $xml += " `n"
- $xml += " `n"
- $xml += ""
- return $xml
-}
-
-function Build-Summary {
- $c = $script:Config
- $keyText = if ($c.ProductKey) { $c.ProductKey } else { 'Nincs megadva' }
- $exText = if ($c.ExcludedApps.Count -gt 0) { $c.ExcludedApps -join ', ' } else { "Nincs (minden alkalmazas telepul)" }
- $langName = ($script:Languages | Where-Object { $_[0] -eq $c.Language } | Select-Object -First 1)[1]
- $el['SummaryText'].Text = "Verzio: $(Get-VersionDisplayName $c.Version)`nKiadas: $($c.Edition.DisplayName)`nArchitektura: $($c.Architecture)-bit`nNyelv: $langName ($($c.Language))`nTermekkulcs: $keyText`nKizart alkalmazasok: $exText"
- $el['XmlPreview'].Text = Generate-OdtXml
-}
-
-function Append-Log($text) {
- $ts = Get-Date -Format 'HH:mm:ss'
- $el['ProgressLog'].Text += "$ts $text`n"
- $el['ProgressLog'].ScrollToEnd()
- [Windows.Threading.Dispatcher]::CurrentDispatcher.Invoke([Action]{}, 'Background')
-}
-
-function Download-ODT {
- $odtFolder = Join-Path $env:TEMP 'InstaSoftODT'
- $setupPath = Join-Path $odtFolder 'setup.exe'
- if (Test-Path $setupPath) {
- $size = [math]::Round((Get-Item $setupPath).Length / 1MB, 1)
- if ((Get-Item $setupPath).Length -gt 1000000) {
- Append-Log "Az ODT setup.exe mar elerheto ($size MB)."
- return $setupPath
- }
- }
- New-Item -ItemType Directory -Path $odtFolder -Force | Out-Null
- Append-Log "Office Deployment Tool letoltese..."
- try {
- $url = 'https://officecdn.microsoft.com/pr/wsus/setup.exe'
- $client = New-Object System.Net.Http.HttpClient
- $client.Timeout = [TimeSpan]::FromMinutes(5)
- $response = $client.GetAsync($url).Result
- if (-not $response.IsSuccessStatusCode) {
- Append-Log "Hiba: HTTP $($response.StatusCode)"
- return $null
- }
- $bytes = $response.Content.ReadAsByteArrayAsync().Result
- [System.IO.File]::WriteAllBytes($setupPath, $bytes)
- $client.Dispose()
- Append-Log "Letoltve: $([math]::Round($bytes.Length / 1024)) KB"
- return $setupPath
- } catch {
- Append-Log "Hiba: $($_.Exception.Message)"
- return $null
- }
-}
-
-function Run-Setup($setupPath, $xmlPath) {
- Append-Log "setup.exe /configure `"$xmlPath`""
- Append-Log "Ez akár 30-40 percet is igénybe vehet..."
- $psi = New-Object System.Diagnostics.ProcessStartInfo
- $psi.FileName = $setupPath
- $psi.Arguments = "/configure `"$xmlPath`""
- $psi.UseShellExecute = $false
- $psi.CreateNoWindow = $true
- $p = [System.Diagnostics.Process]::Start($psi)
- $p.WaitForExit()
- return $p.ExitCode
-}
-
-function Start-Installation {
- Show-Panel 'PanelProgress'
- $el['BtnBack'].Visibility = 'Collapsed'
- $el['BtnNext'].Visibility = 'Collapsed'
- $el['StepDots'].Children.Clear()
- $el['ProgressLog'].Text = ''
- $el['DonePanel'].Visibility = 'Collapsed'
- $el['ProgressTitle'].Text = "Telep`u{00ed}t`u{00e9}s folyamatban..."
-
- Append-Log "ODT letoltes indul..."
- $setupPath = Download-ODT
- if (-not $setupPath) {
- $el['ProgressTitle'].Text = "Telep`u{00ed}t`u{00e9}s sikertelen"
- $el['DoneText'].Text = "Az ODT letoltese sikertelen."
- $el['DoneText'].Foreground = $window.FindResource('ErrorBrush')
- $el['DonePanel'].Visibility = 'Visible'
- $el['BtnBack'].Visibility = 'Visible'
- return
- }
-
- Append-Log "Konfiguracios XML generalasa..."
- $xml = Generate-OdtXml
- $odtFolder = Join-Path $env:TEMP 'InstaSoftODT'
- $xmlPath = Join-Path $odtFolder 'configuration.xml'
- [System.IO.File]::WriteAllText($xmlPath, $xml)
- Append-Log "XML mentve: $xmlPath"
-
- Append-Log "Office telepites inditasa..."
- $exitCode = Run-Setup $setupPath $xmlPath
-
- $el['ProgressBar'].IsIndeterminate = $false
- $el['ProgressBar'].Value = 100
-
- if ($exitCode -eq 0) {
- $el['ProgressTitle'].Text = "Telep`u{00ed}t`u{00e9}s befejezve"
- $el['DoneText'].Text = "Az Office sikeresen telepult!"
- $el['DoneText'].Foreground = $window.FindResource('SuccessBrush')
- if (-not $script:Config.ProductKey) {
- $el['ActivateCard'].Visibility = 'Visible'
- }
- # Launch buttons
- $el['LaunchBtns'].Children.Clear()
- $apps = @(@('Word','WINWORD.EXE'),@('Excel','EXCEL.EXE'),@('PowerPoint','POWERPNT.EXE'),@('Outlook','OUTLOOK.EXE'))
- foreach ($a in $apps) {
- if ($script:Config.ExcludedApps -notcontains $a[0]) {
- $btn = New-Object Windows.Controls.Button
- $btn.Content = $a[0]
- $btn.Style = $window.FindResource('SecBtn')
- $btn.Padding = [Windows.Thickness]::new(18,8,18,8)
- $btn.FontSize = 13
- $btn.Margin = [Windows.Thickness]::new(0,0,8,0)
- $btn.Tag = $a[1]
- $btn.Add_Click({ param($s,$e)
- try { Start-Process $s.Tag } catch { }
- })
- $el['LaunchBtns'].Children.Add($btn) | Out-Null
- }
- }
- $el['LaunchCard'].Visibility = 'Visible'
- } else {
- $el['ProgressTitle'].Text = "Telep`u{00ed}t`u{00e9}s sikertelen"
- $el['DoneText'].Text = "A telepites hibakoddal fejezoedoett be: $exitCode"
- $el['DoneText'].Foreground = $window.FindResource('ErrorBrush')
- }
- Append-Log "setup.exe exit code: $exitCode"
- $el['DonePanel'].Visibility = 'Visible'
- $el['BtnNext'].Content = "Bez`u{00e1}r`u{00e1}s"
- $el['BtnNext'].Visibility = 'Visible'
- $script:CurrentPanel = 'done'
-}
-
-function Detect-Office {
- $results = @()
- # Click-to-Run
- try {
- $c2rKey = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' -ErrorAction Stop
- $ids = $c2rKey.ProductReleaseIds -split ','
- foreach ($id in $ids) {
- $id = $id.Trim()
- if ($id) {
- $results += @{
- DisplayName = "Microsoft Office Click-to-Run ($id)"
- Version = $c2rKey.VersionToReport
- ProductCode = $id
- IsC2R = $true
- }
- }
- }
- } catch {}
- # MSI
- foreach ($path in @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall','HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall')) {
- try {
- Get-ChildItem $path -ErrorAction Stop | ForEach-Object {
- $props = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
- if ($props.DisplayName -and $props.Publisher -match 'Microsoft' -and ($props.DisplayName -match 'Microsoft Office|Microsoft 365')) {
- $isGuid = $_.PSChildName -match '^\{[0-9A-Fa-f\-]+\}$'
- $results += @{
- DisplayName = $props.DisplayName
- Version = $props.DisplayVersion
- ProductCode = if ($isGuid) { $_.PSChildName } else { $null }
- IsC2R = $false
- }
- }
- }
- } catch {}
- }
- return $results
-}
-
-function Find-Ospp {
- $paths = @(
- "$env:ProgramFiles\Microsoft Office\root\Office16\OSPP.VBS",
- "${env:ProgramFiles(x86)}\Microsoft Office\root\Office16\OSPP.VBS",
- "$env:ProgramFiles\Microsoft Office\Office16\ospp.vbs",
- "${env:ProgramFiles(x86)}\Microsoft Office\Office16\ospp.vbs"
- )
- # C2R registry path
- try {
- $c2r = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' -ErrorAction Stop).InstallationPath
- if ($c2r) {
- $paths = @(Join-Path $c2r 'root\Office16\OSPP.VBS') + @(Join-Path $c2r 'Office16\OSPP.VBS') + $paths
- }
- } catch {}
- foreach ($p in $paths) {
- if (Test-Path $p) { return $p }
- }
- return $null
-}
-
-function Build-LicenseCards {
- $el['LicenseCards'].Children.Clear()
- $osppPath = Find-Ospp
- if (-not $osppPath) {
- $tb = New-Object Windows.Controls.TextBlock
- $tb.Text = "Az ospp.vbs nem talalhato. Nincs telepitett Office?"
- $tb.FontSize = 14; $tb.Foreground = $window.FindResource('ErrorBrush')
- $el['LicenseCards'].Children.Add($tb) | Out-Null
- return
- }
- $output = & cscript //Nologo $osppPath /dstatus 2>&1 | Out-String
- # Parse entries
- $blocks = $output -split '-{10,}'
- foreach ($block in $blocks) {
- $block = $block.Trim()
- if (-not $block -or $block -match '^---') { continue }
- $nameMatch = [regex]::Match($block, 'LICENSE NAME:\s*(.+)')
- $statusMatch = [regex]::Match($block, 'LICENSE STATUS:\s*(.+)')
- $errorMatch = [regex]::Match($block, 'ERROR DESCRIPTION:\s*(.+)')
- $keyMatch = [regex]::Match($block, 'Last 5 characters of installed product key:\s*(\S+)')
- if ($keyMatch.Success) {
- $last5 = $keyMatch.Groups[1].Value
- $name = if ($nameMatch.Success) { $nameMatch.Groups[1].Value.Trim() } else { 'Ismeretlen licenc' }
- $status = if ($errorMatch.Success) { $errorMatch.Groups[1].Value.Trim() } elseif ($statusMatch.Success) { $statusMatch.Groups[1].Value.Trim() } else { '' }
-
- # Card
- $border = New-Object Windows.Controls.Border
- $border.Background = [Windows.Media.Brushes]::White
- $border.BorderBrush = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(224,224,224))
- $border.BorderThickness = [Windows.Thickness]::new(1)
- $border.CornerRadius = [Windows.CornerRadius]::new(8)
- $border.Padding = [Windows.Thickness]::new(16,10,16,10)
- $border.Margin = [Windows.Thickness]::new(0,0,0,6)
-
- $grid = New-Object Windows.Controls.Grid
- $grid.ColumnDefinitions.Add((New-Object Windows.Controls.ColumnDefinition -Property @{Width='*'}))
- $grid.ColumnDefinitions.Add((New-Object Windows.Controls.ColumnDefinition -Property @{Width='Auto'}))
-
- $info = New-Object Windows.Controls.StackPanel
- $t1 = New-Object Windows.Controls.TextBlock; $t1.Text = $name; $t1.FontSize = 13; $t1.FontWeight = 'SemiBold'
- $t2 = New-Object Windows.Controls.TextBlock; $t2.Text = $status; $t2.FontSize = 11; $t2.Foreground = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(102,102,102))
- $t3 = New-Object Windows.Controls.TextBlock; $t3.Text = "Kulcs: *****-$last5"; $t3.FontSize = 11; $t3.FontFamily = 'Consolas'
- $t3.Foreground = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(102,102,102))
- $info.Children.Add($t1) | Out-Null; $info.Children.Add($t2) | Out-Null; $info.Children.Add($t3) | Out-Null
- [Windows.Controls.Grid]::SetColumn($info, 0)
- $grid.Children.Add($info) | Out-Null
-
- $btnPanel = New-Object Windows.Controls.StackPanel
- $btnPanel.Orientation = 'Horizontal'
- $btnPanel.VerticalAlignment = 'Center'
-
- $rmBtn = New-Object Windows.Controls.Button
- $rmBtn.Content = "Eltavolitas"
- $rmBtn.Style = $window.FindResource('SecBtn')
- $rmBtn.Padding = [Windows.Thickness]::new(14,6,14,6)
- $rmBtn.FontSize = 12
- $rmBtn.Tag = @{ Last5 = $last5; OsppPath = $osppPath }
- $rmBtn.Add_Click({
- param($s,$e)
- $info = $s.Tag
- & cscript //Nologo $info.OsppPath "/unpkey:$($info.Last5)" 2>&1 | Out-Null
- Build-LicenseCards
- })
- $btnPanel.Children.Add($rmBtn) | Out-Null
-
- [Windows.Controls.Grid]::SetColumn($btnPanel, 1)
- $grid.Children.Add($btnPanel) | Out-Null
-
- $border.Child = $grid
- $el['LicenseCards'].Children.Add($border) | Out-Null
- }
- }
- if ($el['LicenseCards'].Children.Count -eq 0) {
- $tb = New-Object Windows.Controls.TextBlock
- $tb.Text = "Nincs telepitett termekkulcs."
- $tb.FontSize = 13; $tb.Foreground = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(102,102,102))
- $el['LicenseCards'].Children.Add($tb) | Out-Null
- }
-}
-
-# ============================================================
-# EVENT HANDLERS
-# ============================================================
-
-# Welcome buttons
-$el['BtnInstall'].Add_Click({
- $script:InstallIndex = 0
- Build-LanguageCombo
- Navigate-Install 0
-})
-
-$el['BtnRemoveWelcome'].Add_Click({
- Show-Panel 'PanelRemove'
- $el['BtnBack'].Visibility = 'Visible'
- $el['BtnNext'].Visibility = 'Collapsed'
- $el['StepDots'].Children.Clear()
- $script:CurrentPanel = 'PanelRemove'
- # Detect office
- $el['RemoveList'].Children.Clear()
- $detected = Detect-Office
- if ($detected.Count -eq 0) {
- $tb = New-Object Windows.Controls.TextBlock
- $tb.Text = "Nem talalhato telepitett Office."
- $tb.FontSize = 14; $tb.Foreground = [Windows.Media.SolidColorBrush]::new([Windows.Media.Color]::FromRgb(102,102,102))
- $el['RemoveList'].Children.Add($tb) | Out-Null
- $el['BtnDoRemove'].IsEnabled = $false
- } else {
- foreach ($o in $detected) {
- $cb = New-Object Windows.Controls.CheckBox
- $cb.Content = "$($o.DisplayName) ($($o.Version))"
- $cb.IsChecked = $true
- $cb.Style = $window.FindResource('FluentCB')
- $cb.Tag = $o
- $cb.Margin = [Windows.Thickness]::new(0,4,0,4)
- $el['RemoveList'].Children.Add($cb) | Out-Null
- }
- }
-})
-
-$el['BtnLicenseWelcome'].Add_Click({
- Show-Panel 'PanelLicense'
- $el['BtnBack'].Visibility = 'Visible'
- $el['BtnNext'].Visibility = 'Collapsed'
- $el['StepDots'].Children.Clear()
- $script:CurrentPanel = 'PanelLicense'
- Build-LicenseCards
-})
-
-# Back button
-$el['BtnBack'].Add_Click({
- $window.Height = 550
- if ($script:CurrentPanel -eq 'done') {
- $window.Close()
- return
- }
- if ($script:InstallPanels -contains $script:CurrentPanel -and $script:InstallIndex -gt 0) {
- Navigate-Install ($script:InstallIndex - 1)
- } else {
- Show-Panel 'PanelWelcome'
- $script:CurrentPanel = 'PanelWelcome'
- $el['BtnBack'].Visibility = 'Collapsed'
- $el['BtnNext'].Visibility = 'Collapsed'
- $el['StepDots'].Children.Clear()
- }
-})
-
-# Next button
-$el['BtnNext'].Add_Click({
- if ($script:CurrentPanel -eq 'done') {
- $window.Close()
- return
- }
- # Validate + advance
- switch ($script:CurrentPanel) {
- 'PanelVersion' {
- $script:Config.Version = Get-SelectedVersion
- Build-EditionCards
- Navigate-Install 1
- }
- 'PanelEdition' {
- $script:Config.Edition = Get-SelectedEdition
- Build-AppChecks
- Navigate-Install 2
- }
- 'PanelConfig' {
- $script:Config.Architecture = if ($el['Rb64'].IsChecked) { '64' } else { '32' }
- $sel = $el['CbLanguage'].SelectedItem
- if ($sel) { $script:Config.Language = $sel.Tag }
- $script:Config.ExcludedApps = @()
- foreach ($child in $el['AppChecks'].Children) {
- if ($child -is [Windows.Controls.CheckBox] -and (-not $child.IsChecked -or -not $child.IsEnabled)) {
- $script:Config.ExcludedApps += $child.Tag
- }
- }
- Navigate-Install 3
- }
- 'PanelKey' {
- if ($el['CbSkipKey'].IsChecked) {
- $script:Config.ProductKey = ''
- } else {
- $script:Config.ProductKey = Get-ProductKey
- }
- Build-Summary
- Navigate-Install 4
- }
- 'PanelSummary' {
- Start-Installation
- }
- }
-})
-
-# License refresh
-$el['BtnLicRefresh'].Add_Click({ Build-LicenseCards })
-
-# Key auto-tab
-$keyBoxes = @($el['K1'],$el['K2'],$el['K3'],$el['K4'],$el['K5'])
-for ($i = 0; $i -lt $keyBoxes.Count; $i++) {
- $box = $keyBoxes[$i]
- $idx = $i
- $box.Add_TextChanged({
- param($s,$e)
- if ($s.Text.Length -eq 5 -and $idx -lt 4) {
- $keyBoxes[$idx + 1].Focus()
- }
- }.GetNewClosure())
- # Paste handler
- [Windows.DataObject]::AddPastingHandler($box, [Windows.DataObjectPastingEventHandler]{
- param($s,$e)
- if ($e.DataObject.GetDataPresent([string])) {
- $pasted = $e.DataObject.GetData([string])
- $clean = $pasted -replace '[^A-Za-z0-9]',''
- if ($clean.Length -gt 5) {
- $e.CancelCommand()
- for ($j = 0; $j -lt 5; $j++) {
- $start = $j * 5
- if ($start -lt $clean.Length) {
- $len = [Math]::Min(5, $clean.Length - $start)
- $keyBoxes[$j].Text = $clean.Substring($start, $len).ToUpper()
- }
- }
- $keyBoxes[4].Focus()
- }
- }
- })
-}
-
-# Skip key checkbox
-$el['CbSkipKey'].Add_Checked({ foreach ($b in $keyBoxes) { $b.IsEnabled = $false; $b.Text = '' } })
-$el['CbSkipKey'].Add_Unchecked({ foreach ($b in $keyBoxes) { $b.IsEnabled = $true } })
-
-# ============================================================
-# RUN
-# ============================================================
-$window.ShowDialog() | Out-Null