From ec3c89ac1b5a9b4460ab6c8e0a88b59844da528d Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Tue, 14 Jan 2025 19:09:32 -0800 Subject: [PATCH] Added Windows settings tab --- FFUDevelopment/BuildFFUVM_UI.ps1 | 1057 ++++++++++++++--------------- FFUDevelopment/BuildFFUVM_UI.xaml | 590 +++++++++++----- 2 files changed, 952 insertions(+), 695 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM_UI.ps1 b/FFUDevelopment/BuildFFUVM_UI.ps1 index a07b580..3a6e09f 100644 --- a/FFUDevelopment/BuildFFUVM_UI.ps1 +++ b/FFUDevelopment/BuildFFUVM_UI.ps1 @@ -1,78 +1,33 @@ [CmdletBinding()] -[System.STAThread()] +[System.STAThread()] param() -# Define FFUDevelopmentPath using $PSScriptRoot +# -------------------------------------------------------------------------- +# SECTION 1: Variables & Constants +# -------------------------------------------------------------------------- $FFUDevelopmentPath = $PSScriptRoot +$infoImagePath = Join-Path $PSScriptRoot "info.png" +$AppsPath = Join-Path $FFUDevelopmentPath "Apps" +$OfficePath = Join-Path $AppsPath "Office" -Add-Type -AssemblyName WindowsBase -Add-Type -AssemblyName PresentationCore,PresentationFramework -Add-Type -AssemblyName System.Windows.Forms # Added to load Windows Forms for OpenFileDialog +# Some default values +$defaultISOPath = "" +$defaultWindowsRelease = 11 # numeric +$defaultWindowsArch = "x64" +$defaultWindowsLang = "en-us" +$defaultWindowsSKU = "Pro" +$defaultMediaType = "consumer" +$defaultOptionalFeatures = "" +$defaultProductKey = "" -# Define the path to the info.png image -$infoImagePath = Join-Path -Path $PSScriptRoot -ChildPath "info.png" - -# Load the XAML from the external file -$xamlPath = Join-Path -Path $PSScriptRoot -ChildPath "BuildFFUVM_UI.xaml" -if (-Not (Test-Path $xamlPath)) { - Write-Error "XAML file not found at path: $xamlPath" - exit -} - -$xamlString = Get-Content -Path $xamlPath -Raw - -# Create the XmlReader -$reader = New-Object System.IO.StringReader($xamlString) -$xmlReader = [System.Xml.XmlReader]::Create($reader) - -# Load the window -$window = [Windows.Markup.XamlReader]::Load($xmlReader) - -# Set the Text property programmatically -$window.FindName('txtFFUName').Text = "{WindowsRelease}_{WindowsVersion}_{SKU}_{yyyy}-{MM}-{dd}_{HH}{mm}" - -# Replace the dynamic SKU extraction with a static list $skuList = @( - 'Home', 'Home N', 'Home Single Language', 'Education', 'Education N', 'Pro', - 'Pro N', 'Pro Education', 'Pro Education N', 'Pro for Workstations', - 'Pro N for Workstations', 'Enterprise', 'Enterprise N', 'Standard', - 'Standard (Desktop Experience)', 'Datacenter', 'Datacenter (Desktop Experience)' + 'Home','Home N','Home Single Language','Education','Education N','Pro', + 'Pro N','Pro Education','Pro Education N','Pro for Workstations', + 'Pro N for Workstations','Enterprise','Enterprise N','Standard', + 'Standard (Desktop Experience)','Datacenter','Datacenter (Desktop Experience)' ) -# Get the ComboBox control -$cmbWindowsSKU = $window.FindName('cmbWindowsSKU') - -# Clear existing items to avoid duplication when re-running the script -$cmbWindowsSKU.Items.Clear() - -# Populate the ComboBox with SKUs -foreach ($sku in $skuList) { - $cmbWindowsSKU.Items.Add($sku) | Out-Null -} - -# Set default selection -if ($cmbWindowsSKU.Items.Count -gt 0) { - $cmbWindowsSKU.SelectedIndex = 0 -} else { - Write-Host "No SKUs available to populate the ComboBox." -} - -# Function to set image sources -function Set-ImageSource { - param ( - [System.Windows.Window]$window, - [string]$imageName, - [string]$sourcePath - ) - $image = $window.FindName($imageName) - if ($image) { - $uri = New-Object System.Uri($sourcePath, [System.UriKind]::Absolute) - $bitmap = New-Object System.Windows.Media.Imaging.BitmapImage($uri) - $image.Source = $bitmap - } -} - -# List of Image control names +# Info icons $imageNames = @( "imgFFUNameInfo", "imgISOPathInfo", @@ -83,350 +38,371 @@ $imageNames = @( "imgInstallAppsInfo", "imgInstallDriversInfo", "imgCopyDriversInfo", - "imgFFUDevPathInfo" + "imgFFUDevPathInfo", + "imgOfficePathInfo", + "imgCopyOfficeConfigXMLInfo", + "imgOfficeConfigXMLFileInfo", + "imgMakeInfo", + "imgModelInfo", + "imgDownloadDriversInfo", + "imgDriversFolderInfo", + "imgPEDriversFolderInfo", + "imgCopyPEDriversInfo" ) -# Set the Source for each Image control +# Full list of Windows releases (for when ISO path is non-blank) +$allWindowsReleases = @( + [PSCustomObject]@{ Display = "Windows 10"; Value = 10 }, + [PSCustomObject]@{ Display = "Windows 11"; Value = 11 }, + [PSCustomObject]@{ Display = "Windows Server 2016"; Value = 2016 }, + [PSCustomObject]@{ Display = "Windows Server 2019"; Value = 2019 }, + [PSCustomObject]@{ Display = "Windows Server 2022"; Value = 2022 }, + [PSCustomObject]@{ Display = "Windows Server 2025"; Value = 2025 } +) +# Subset for MCT (Media Creation Tool) only +$mctWindowsReleases = @( + [PSCustomObject]@{ Display = "Windows 10"; Value = 10 }, + [PSCustomObject]@{ Display = "Windows 11"; Value = 11 } +) + +# Windows version sets for each release (for "Version" combobox) +$windowsVersionMap = @{ + 10 = @("22H2") + 11 = @("22H2","23H2","24H2") + 2016 = @("1607") + 2019 = @("1809") + 2022 = @("21H2") + 2025 = @("24H2") +} + +# -------------------------------------------------------------------------- +function Set-ImageSource { + param( + [System.Windows.Window]$window, + [string]$imageName, + [string]$sourcePath + ) + $imgControl = $window.FindName($imageName) + if ($imgControl) { + $uri = New-Object System.Uri($sourcePath, [System.UriKind]::Absolute) + $bitmap = New-Object System.Windows.Media.Imaging.BitmapImage($uri) + $imgControl.Source = $bitmap + } +} + +function Get-UIConfig { + # Basic tab + $ffuDevPath = $window.FindName('txtFFUDevPath').Text + $ffuName = $window.FindName('txtFFUName').Text + $vmSwitchSelected = $window.FindName('cmbVMSwitchName').SelectedItem + $customVMSwitch = $window.FindName('txtCustomVMSwitchName').Text + $vmHostIPAddress = $window.FindName('txtVMHostIPAddress').Text + + # Windows tab + $wrItem = $window.FindName('cmbWindowsRelease').SelectedItem + $windowsRelease = if ($wrItem -and $wrItem.Value) { + [int]$wrItem.Value + } else { + 10 + } + $windowsVersion = $window.FindName('cmbWindowsVersion').SelectedItem + $windowsArch = $window.FindName('cmbWindowsArch').SelectedItem + $windowsLang = $window.FindName('cmbWindowsLang').SelectedItem + $windowsSKU = $window.FindName('cmbWindowsSKU').SelectedItem + $mediaType = $window.FindName('cmbMediaType').SelectedItem + $optionalFeatures= $window.FindName('txtOptionalFeatures').Text + $productKey = $window.FindName('txtProductKey').Text + $isoPath = $window.FindName('txtISOPath').Text + + # Apps tab + $installApps = $window.FindName('chkInstallApps').IsChecked + + # Office tab + $installOffice = $window.FindName('chkInstallOffice').IsChecked + $officePath = $window.FindName('txtOfficePath').Text + $copyOfficeConfig = $window.FindName('chkCopyOfficeConfigXML').IsChecked + $officeConfigXMLFile = $window.FindName('txtOfficeConfigXMLFilePath').Text + + # Drivers tab + $installDrivers = $window.FindName('chkInstallDrivers').IsChecked + $copyDrivers = $window.FindName('chkCopyDrivers').IsChecked + $downloadDrivers = $window.FindName('chkDownloadDrivers').IsChecked + $make = $window.FindName('cmbMake').SelectedItem + $model = $window.FindName('cmbModel').Text + $driversFolder = $window.FindName('txtDriversFolder').Text + $peDriversFolder = $window.FindName('txtPEDriversFolder').Text + $copyPEDrivers = $window.FindName('chkCopyPEDrivers').IsChecked + + # Basic validations + if (-not $ffuDevPath) { + throw "FFU Development Path is required." + } + if ($installDrivers -and (-not $driversFolder)) { + throw "Drivers Folder is required when Install Drivers is checked." + } + if ($copyDrivers -and (-not $driversFolder)) { + throw "Drivers Folder is required when Copy Drivers is checked." + } + if ($copyPEDrivers -and (-not $peDriversFolder)) { + throw "PE Drivers Folder is required when Copy PE Drivers is checked." + } + if ($downloadDrivers -and (-not $make)) { + throw "Make is required when Download Drivers is checked." + } + if ($downloadDrivers -and (-not $model)) { + throw "Model is required when Download Drivers is checked." + } + + # If user picks 'Other' for VM Switch, use custom + $vmSwitchName = if ($vmSwitchSelected -eq 'Other') { $customVMSwitch } else { $vmSwitchSelected } + + # Build config + $config = [ordered]@{ + AppsPath = $AppsPath + CopyDrivers = $copyDrivers + CopyPEDrivers = $copyPEDrivers + CopyOfficeConfigXML = $copyOfficeConfig + DriversFolder = $driversFolder + DownloadDrivers = $downloadDrivers + FFUDevelopmentPath = $ffuDevPath + FFUName = $ffuName + InstallApps = $installApps + InstallDrivers = $installDrivers + InstallOffice = $installOffice + ISOPath = $isoPath + Make = if ($downloadDrivers) { $make } else { $null } + MediaType = $mediaType + Model = if ($downloadDrivers) { $model } else { $null } + OfficeConfigXMLFile = if ($installOffice -and $copyOfficeConfig) { $officeConfigXMLFile } else { $null } + OfficePath = $officePath + OptionalFeatures = $optionalFeatures + PEDriversFolder = $peDriversFolder + ProductKey = $productKey + VMHostIPAddress = $vmHostIPAddress + VMSwitchName = $vmSwitchName + WindowsArch = $windowsArch + WindowsLang = $windowsLang + WindowsRelease = $windowsRelease + WindowsSKU = $windowsSKU + WindowsVersion = $windowsVersion + } + return $config +} + +# This function updates the Windows Release list: +# - If ISO path is blank => only show Windows 10, Windows 11 +# - If ISO path is not blank => show all releases +function UpdateWindowsReleaseList { + param([string]$isoPath) + + if (-not $script:cmbWindowsRelease) { return } + + # Remember old item + $oldItem = $script:cmbWindowsRelease.SelectedItem + + # Clear + $script:cmbWindowsRelease.Items.Clear() + + # IMPORTANT: Set these paths so the ComboBox shows 'Display' text + $script:cmbWindowsRelease.DisplayMemberPath = 'Display' + $script:cmbWindowsRelease.SelectedValuePath = 'Value' + + # If blank => only MCT + if ([string]::IsNullOrEmpty($isoPath)) { + foreach ($rel in $mctWindowsReleases) { + $script:cmbWindowsRelease.Items.Add($rel) | Out-Null + } + } + else { + foreach ($rel in $allWindowsReleases) { + $script:cmbWindowsRelease.Items.Add($rel) | Out-Null + } + } + + # Attempt to re-select old item (based on Value) + if ($oldItem) { + $reSelect = $script:cmbWindowsRelease.Items | Where-Object { $_.Value -eq $oldItem.Value } + if ($reSelect) { + $script:cmbWindowsRelease.SelectedItem = $reSelect + } + else { + $script:cmbWindowsRelease.SelectedIndex = 0 + } + } + else { + $script:cmbWindowsRelease.SelectedIndex = 0 + } +} + +function UpdateWindowsVersionCombo { + param( + [int]$selectedRelease, + [string]$isoPath + ) + $combo = $window.FindName('cmbWindowsVersion') + if (-not $combo) { return } + + $combo.Items.Clear() + + if (-not $windowsVersionMap.ContainsKey($selectedRelease)) { + $combo.IsEnabled = $false + return + } + + $validVersions = $windowsVersionMap[$selectedRelease] + + if ([string]::IsNullOrEmpty($isoPath)) { + switch ($selectedRelease) { + 10 { $default = "22H2" } + 11 { $default = "24H2" } + 2016 { $default = "1607" } + 2019 { $default = "1809" } + 2022 { $default = "21H2" } + 2025 { $default = "24H2" } + default { $default = $validVersions[0] } + } + $combo.Items.Add($default) | Out-Null + $combo.SelectedIndex = 0 + $combo.IsEnabled = $false + } + else { + foreach ($v in $validVersions) { + [void]$combo.Items.Add($v) + } + $combo.SelectedIndex = 0 + $combo.IsEnabled = $true + } +} + +$script:RefreshWindowsUI = { + param([string]$isoPath) + + # Refresh releases + UpdateWindowsReleaseList -isoPath $isoPath + + # Then refresh version + $selItem = $script:cmbWindowsRelease.SelectedItem + if ($selItem -and $selItem.Value -is [int]) { + $selectedRelease = [int]$selItem.Value + } + else { + $selectedRelease = 10 + } + UpdateWindowsVersionCombo -selectedRelease $selectedRelease -isoPath $isoPath +} + +Add-Type -AssemblyName WindowsBase +Add-Type -AssemblyName PresentationCore,PresentationFramework +Add-Type -AssemblyName System.Windows.Forms + +# Load XAML +$xamlPath = Join-Path $PSScriptRoot "BuildFFUVM_UI.xaml" +if (-not (Test-Path $xamlPath)) { + Write-Error "XAML file not found: $xamlPath" + return +} +$xamlString = Get-Content $xamlPath -Raw +$reader = New-Object System.IO.StringReader($xamlString) +$xmlReader = [System.Xml.XmlReader]::Create($reader) +$window = [Windows.Markup.XamlReader]::Load($xmlReader) + +# Assign images foreach ($imgName in $imageNames) { Set-ImageSource -window $window -imageName $imgName -sourcePath $infoImagePath } -# Optional: Add logging for debugging purposes -# Uncomment the following lines to enable debug output -# Write-Host "Extracted SKU List: $skuList" -# Write-Host "ComboBox Items Count: $($cmbWindowsSKU.Items.Count)" -# Define event handler with feedback mechanisms and error handling -$runScriptHandler = { - try { - # Show progress bar and update status - $progressBar = $window.FindName('progressBar') - $txtStatus = $window.FindName('txtStatus') - $progressBar.Visibility = 'Visible' - $txtStatus.Text = "Starting FFU build..." - - # Gather user inputs from controls - $ffuDevPath = $window.FindName('txtFFUDevPath').Text - $customFFUNameTemplate = $window.FindName('txtFFUName').Text - $isoPath = $window.FindName('txtISOPath').Text - $windowsSKU = $cmbWindowsSKU.SelectedItem - $vmSwitchName = $cmbVMSwitchName.SelectedItem - if ($vmSwitchName -eq 'Other') { - $vmSwitchName = $window.FindName('txtCustomVMSwitchName').Text - } - $vmHostIPAddress = $window.FindName('txtVMHostIPAddress').Text - $installOffice = $window.FindName('chkInstallOffice').IsChecked - $installApps = $window.FindName('chkInstallApps').IsChecked - $installDrivers = $window.FindName('chkInstallDrivers').IsChecked - $copyDrivers = $window.FindName('chkCopyDrivers').IsChecked # Retrieved Copy Drivers value - $downloadDrivers = $window.FindName('chkDownloadDrivers').IsChecked - $make = $window.FindName('cmbMake').SelectedItem - $model = $window.FindName('cmbModel').Text # Changed from SelectedItem - $driversFolder = $window.FindName('txtDriversFolder').Text - $peDriversFolder = $window.FindName('txtPEDriversFolder').Text - - # Validate required fields - if ($installDrivers -and (-not $driversFolder)) { - throw "Drivers Folder is required when Install Drivers is checked." - } - if ($copyDrivers -and (-not $driversFolder)) { - throw "Drivers Folder is required when Copy Drivers is checked." - } - if ($copyPEDrivers -and (-not $peDriversFolder)) { - throw "PE Drivers Folder is required when Copy PE Drivers is checked." - } - if ($downloadDrivers -and (-not $make)) { - throw "Make is required when Download Drivers is checked." - } - if ($downloadDrivers -and (-not $model)) { - throw "Model is required when Download Drivers is checked." - } - if (-not $ffuDevPath) { - throw "FFU Development Path is required." - } - - # Create config object - $config = @{ - FFUDevelopmentPath = $ffuDevPath - CustomFFUNameTemplate = $customFFUNameTemplate - ISOPath = $isoPath - WindowsSKU = $windowsSKU - VMSwitchName = if ($cmbVMSwitchName.SelectedItem -eq 'Other') { - $window.FindName('txtCustomVMSwitchName').Text - } else { - $cmbVMSwitchName.SelectedItem.ToString() # Convert SelectedItem to string - } - VMHostIPAddress = $vmHostIPAddress - InstallOffice = $installOffice - InstallApps = $installApps - InstallDrivers = $installDrivers - CopyDrivers = $copyDrivers # Added CopyDrivers to config - DownloadDrivers = $downloadDrivers - Make = if ($downloadDrivers) { $make.ToString() } else { $null } - Model = if ($downloadDrivers) { $model } else { $null } # Changed from ToString() - DriversFolder = $driversFolder - PEDriversFolder = $peDriversFolder - # ...include other parameters as needed - } - - # Serialize config to JSON - $configJson = $config | ConvertTo-Json -Depth 10 - - # Save config file - $configFilePath = "$FFUDevelopmentPath\FFUConfig.json" - $configJson | Set-Content -Path $configFilePath -Encoding UTF8 - - # Update status - $txtStatus.Text = "Executing BuildFFUVM script with config file..." - - # Call BuildFFUVM.ps1 with -ConfigFile - & "$PSScriptRoot\BuildFFUVM.ps1" -ConfigFile $configFilePath -Verbose - - # Update status after successful execution - $txtStatus.Text = "FFU build completed successfully." - } - catch { - # Show error message and update status - [System.Windows.MessageBox]::Show("An error occurred: $_", "Error", "OK", "Error") - $txtStatus.Text = "FFU build failed." - } - finally { - # Hide progress bar - $window.FindName('progressBar').Visibility = 'Collapsed' +function UpdateOptionalFeaturesString { + if ($script:chkTelnetClient -and $script:chkNetFx3 -and $script:chkDirectPlay -and $script:chkSMB1Protocol -and $script:txtOptionalFeatures) { + $f = @() + if ($script:chkTelnetClient.IsChecked) { $f += "TelnetClient" } + if ($script:chkNetFx3.IsChecked) { $f += "NetFx3" } + if ($script:chkDirectPlay.IsChecked) { $f += "DirectPlay" } + if ($script:chkSMB1Protocol.IsChecked) { $f += "SMB1Protocol" } + $script:txtOptionalFeatures.Text = $f -join ";" } } -# Bind the event handler once -$btnRun = $window.FindName('btnRun') -$btnRun.Add_Click($runScriptHandler) - -# Bind the Browse button event handler -$btnBrowseISO = $window.FindName('btnBrowseISO') -$btnBrowseISO.Add_Click({ - $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog - $openFileDialog.Filter = "ISO files (*.iso)|*.iso" - $openFileDialog.Title = "Select Windows ISO File" - - if ($openFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { - $window.FindName('txtISOPath').Text = $openFileDialog.FileName - } -}) - -$btnBrowseFFUDevPath = $window.FindName('btnBrowseFFUDevPath') -$btnBrowseFFUDevPath.Add_Click({ - $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog - $folderBrowser.Description = "Select FFU Development Folder" - $folderBrowser.SelectedPath = $window.FindName('txtFFUDevPath').Text # Set initial path - if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { - $window.FindName('txtFFUDevPath').Text = $folderBrowser.SelectedPath - } -}) - -# Assign FFUDevelopmentPath to the TextBox -$window.FindName('txtFFUDevPath').Text = $FFUDevelopmentPath - -# Bind the Browse buttons for Drivers folders -$btnBrowseDriversFolder = $window.FindName('btnBrowseDriversFolder') -$btnBrowseDriversFolder.Add_Click({ - $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog - $folderBrowser.Description = "Select Drivers Folder" - if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { - $window.FindName('txtDriversFolder').Text = $folderBrowser.SelectedPath - } -}) - -$btnBrowsePEDrivers = $window.FindName('btnBrowsePEDrivers') -$btnBrowsePEDrivers.Add_Click({ - $folderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog - $folderBrowser.Description = "Select PE Drivers Folder" - if ($folderBrowser.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { - $window.FindName('txtPEDriversFolder').Text = $folderBrowser.SelectedPath - } -}) - -# Bind the Build Config File button event handler -$btnBuildConfig = $window.FindName('btnBuildConfig') -$btnBuildConfig.Add_Click({ - try { - # Define default save path - $defaultConfigPath = Join-Path -Path $FFUDevelopmentPath -ChildPath "config" - - # Ensure the config directory exists - if (-not (Test-Path -Path $defaultConfigPath)) { - New-Item -Path $defaultConfigPath -ItemType Directory -Force | Out-Null - } - - # Initialize SaveFileDialog - $saveFileDialog = New-Object System.Windows.Forms.SaveFileDialog - $saveFileDialog.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*" - $saveFileDialog.Title = "Save Configuration File" - $saveFileDialog.InitialDirectory = $defaultConfigPath - $saveFileDialog.FileName = "FFUConfig.json" - - # Show SaveFileDialog - if ($saveFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { - $savePath = $saveFileDialog.FileName - - # Gather current configuration from UI controls using $window.FindName - $ffuDevPath = ($window.FindName('txtFFUDevPath')).Text - $windowsSKU = ($window.FindName('cmbWindowsSKU')).SelectedItem - if (-not $windowsSKU) { - throw "Windows SKU is not selected." - } - - $selectedVMSwitch = ($window.FindName('cmbVMSwitchName')).SelectedItem - if (-not $selectedVMSwitch) { - throw "VM Switch Name is not selected." - } - - if ($selectedVMSwitch -eq 'Other') { - $vmSwitchName = ($window.FindName('txtCustomVMSwitchName')).Text - if (-not $vmSwitchName) { - throw "Custom VM Switch Name is empty." - } - } - else { - $vmSwitchName = $selectedVMSwitch.ToString() - } - - $installDrivers = ($window.FindName('chkInstallDrivers')).IsChecked - $copyDrivers = ($window.FindName('chkCopyDrivers')).IsChecked - $downloadDrivers = ($window.FindName('chkDownloadDrivers')).IsChecked - $make = ($window.FindName('cmbMake')).SelectedItem - $model = ($window.FindName('txtModel')).Text # Changed from SelectedItem - $driversFolder = ($window.FindName('txtDriversFolder')).Text - $peDriversFolder = ($window.FindName('txtPEDriversFolder')).Text - - # Validate required fields - if ($installDrivers -and (-not $driversFolder)) { - throw "Drivers Folder is required when Install Drivers is checked." - } - if ($copyDrivers -and (-not $driversFolder)) { - throw "Drivers Folder is required when Copy Drivers is checked." - } - if ($copyPEDrivers -and (-not $peDriversFolder)) { - throw "PE Drivers Folder is required when Copy PE Drivers is checked." - } - if ($downloadDrivers -and (-not $make)) { - throw "Make is required when Download Drivers is checked." - } - if ($downloadDrivers -and (-not $model)) { - throw "Model is required when Download Drivers is checked." - } - if (-not $ffuDevPath) { - throw "FFU Development Path is required." - } - - $config = @{ - FFUDevelopmentPath = $ffuDevPath - CustomFFUNameTemplate = ($window.FindName('txtFFUName')).Text - ISOPath = ($window.FindName('txtISOPath')).Text - WindowsSKU = $windowsSKU - VMSwitchName = $vmSwitchName - VMHostIPAddress = ($window.FindName('txtVMHostIPAddress')).Text - InstallOffice = ($window.FindName('chkInstallOffice')).IsChecked - InstallApps = ($window.FindName('chkInstallApps')).IsChecked - InstallDrivers = $installDrivers - CopyDrivers = $copyDrivers - DownloadDrivers = $downloadDrivers - Make = if ($downloadDrivers) { $make.ToString() } else { $null } - Model = if ($downloadDrivers) { $model } else { $null } # Changed from ToString() - DriversFolder = $driversFolder - PEDriversFolder = $peDriversFolder - # ...include other parameters as needed - } - - # Serialize config to JSON - $configJson = $config | ConvertTo-Json -Depth 10 - - # Save the config file - $configJson | Set-Content -Path $savePath -Encoding UTF8 - - # Inform the user of success - [System.Windows.MessageBox]::Show("Configuration file saved successfully to:`n$savePath", "Success", "OK", "Information") - } - } - catch { - # Show error message - [System.Windows.MessageBox]::Show("An error occurred while saving the configuration file:`n$_", "Error", "OK", "Error") - } -}) - -# After loading the window: -# Initialize script-scoped variable -$script:installAppsCheckedByOffice = $false - +# Window Loaded $window.Add_Loaded({ - $script:vmSwitchMap = @{} - $script:cmbVMSwitchName = $window.FindName('cmbVMSwitchName') + # Windows Release + $script:cmbWindowsRelease = $window.FindName('cmbWindowsRelease') + $script:cmbWindowsVersion = $window.FindName('cmbWindowsVersion') + $script:txtISOPath = $window.FindName('txtISOPath') - $allSwitches = Get-VMSwitch -ErrorAction SilentlyContinue - foreach ($sw in $allSwitches) { - $cmbVMSwitchName.Items.Add($sw.Name) - - # Use partial match in the NetAdapter Name - $netAdapter = Get-NetAdapter -ErrorAction SilentlyContinue | - Where-Object { $_.Name -like "*($($sw.Name))*" } - if ($netAdapter) { - # Use InterfaceIndex for accurate matching - $netIPs = Get-NetIPAddress -InterfaceIndex $netAdapter.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue + & $script:RefreshWindowsUI($defaultISOPath) + + # Event: ISO path changed + $script:txtISOPath.Add_TextChanged({ + & $script:RefreshWindowsUI($script:txtISOPath.Text) + }) + + # Event: Windows release changed + $script:cmbWindowsRelease.Add_SelectionChanged({ + $selItem = $script:cmbWindowsRelease.SelectedItem + if ($selItem -and $selItem.Value) { + UpdateWindowsVersionCombo -selectedRelease $selItem.Value -isoPath $script:txtISOPath.Text + } + }) + + # Browse ISO + $script:btnBrowseISO = $window.FindName('btnBrowseISO') + $script:btnBrowseISO.Add_Click({ + $ofd = New-Object System.Windows.Forms.OpenFileDialog + $ofd.Filter = "ISO files (*.iso)|*.iso" + $ofd.Title = "Select Windows ISO File" + if ($ofd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + $script:txtISOPath.Text = $ofd.FileName + } + }) + + # Basic defaults + $window.FindName('txtFFUDevPath').Text = $FFUDevelopmentPath + $window.FindName('txtFFUName').Text = "{WindowsRelease}_{WindowsVersion}_{SKU}_{yyyy}-{MM}-{dd}_{HH}{mm}" + + # VM Switch detection + $script:vmSwitchMap = @{} + $script:allSwitches = Get-VMSwitch -ErrorAction SilentlyContinue + $script:cmbVMSwitchName = $window.FindName('cmbVMSwitchName') + + foreach ($sw in $script:allSwitches) { + $script:cmbVMSwitchName.Items.Add($sw.Name) | Out-Null + $na = Get-NetAdapter -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*($($sw.Name))*" } + if ($na) { + $netIPs = Get-NetIPAddress -InterfaceIndex $na.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue $validIPs = $netIPs | Where-Object { $_.IPAddress -notlike '169.254.*' -and $_.IPAddress } - if ($validIPs) { $script:vmSwitchMap[$sw.Name] = ($validIPs | Select-Object -First 1).IPAddress } } } + $script:cmbVMSwitchName.Items.Add('Other') | Out-Null - # Add "Other" option to cmbVMSwitchName - $cmbVMSwitchName.Items.Add('Other') | Out-Null - - # Force a default selection if any items exist - if ($cmbVMSwitchName.Items.Count -gt 0) { - # Select the first VM Switch if available, else select 'Other' - if ($allSwitches.Count -gt 0) { - $cmbVMSwitchName.SelectedIndex = 0 - if ($cmbVMSwitchName.SelectedItem) { - $preSelected = $cmbVMSwitchName.SelectedItem.ToString() # Converted to string - if ($script:vmSwitchMap.ContainsKey($preSelected)) { - $window.FindName('txtVMHostIPAddress').Text = $script:vmSwitchMap[$preSelected] - } - else { - $window.FindName('txtVMHostIPAddress').Text = '' - } + if ($script:cmbVMSwitchName.Items.Count -gt 0) { + if ($script:allSwitches.Count -gt 0) { + $script:cmbVMSwitchName.SelectedIndex = 0 + $first = $script:cmbVMSwitchName.SelectedItem + if ($script:vmSwitchMap.ContainsKey($first)) { + $window.FindName('txtVMHostIPAddress').Text = $script:vmSwitchMap[$first] + } + else { + $window.FindName('txtVMHostIPAddress').Text = '' } } else { - # If no VM Switches exist, select 'Other' by default - $cmbVMSwitchName.SelectedItem = 'Other' + $script:cmbVMSwitchName.SelectedItem = 'Other' $window.FindName('txtCustomVMSwitchName').Visibility = 'Visible' } } - - # Update IP on selection change using the prebuilt mapping - $cmbVMSwitchName.Add_SelectionChanged({ - param($sender, $eventArgs) # Define parameters for the event handler - - if ($sender.SelectedItem -eq 'Other') { - # Show the custom VM Switch Name TextBox - $window.FindName('txtCustomVMSwitchName').Visibility = [System.Windows.Visibility]::Visible - - # Optionally, clear the VM Host IP Address field + $script:cmbVMSwitchName.Add_SelectionChanged({ + if ($_.AddedItems -contains 'Other') { + $window.FindName('txtCustomVMSwitchName').Visibility = 'Visible' $window.FindName('txtVMHostIPAddress').Text = '' } else { - # Hide the custom VM Switch Name TextBox - $window.FindName('txtCustomVMSwitchName').Visibility = [System.Windows.Visibility]::Collapsed - - # Update VM Host IP Address based on selection - if ($sender.SelectedItem) { - $selectedSwitch = $sender.SelectedItem.ToString() - if ($script:vmSwitchMap.ContainsKey($selectedSwitch)) { - $ipAddress = $script:vmSwitchMap[$selectedSwitch] - $window.FindName('txtVMHostIPAddress').Text = $ipAddress - } - else { - $window.FindName('txtVMHostIPAddress').Text = '' - } + $window.FindName('txtCustomVMSwitchName').Visibility = 'Collapsed' + $sel = $_.AddedItems[0] + if ($script:vmSwitchMap.ContainsKey($sel)) { + $window.FindName('txtVMHostIPAddress').Text = $script:vmSwitchMap[$sel] } else { $window.FindName('txtVMHostIPAddress').Text = '' @@ -434,197 +410,194 @@ $window.Add_Loaded({ } }) - # Cast to WPF CheckBox and ComboBoxes - $script:chkDownloadDrivers = [System.Windows.Controls.CheckBox]$window.FindName('chkDownloadDrivers') - $script:cmbMake = [System.Windows.Controls.ComboBox]$window.FindName('cmbMake') - $script:cmbModel = [System.Windows.Controls.TextBox]$window.FindName('cmbModel') # Cast cmbModel as TextBox instead of ComboBox + # Windows Arch, Lang, SKU, etc. + $script:cmbWindowsArch = $window.FindName('cmbWindowsArch') + foreach ($a in 'x86','x64','arm64') { [void]$script:cmbWindowsArch.Items.Add($a) } + $script:cmbWindowsArch.SelectedItem = $defaultWindowsArch - # Cast to WPF TextBlocks for label visibility - $script:txtMakeLabel = [System.Windows.Controls.TextBlock]$window.FindName('txtMakeLabel') - $script:txtModelLabel = [System.Windows.Controls.TextBlock]$window.FindName('txtModelLabel') - - # Set initial visibility based on the checkbox state - if ($chkDownloadDrivers.IsChecked) { - $script:cmbMake.Visibility = [System.Windows.Visibility]::Visible - $script:cmbModel.Visibility = [System.Windows.Visibility]::Visible - $script:txtMakeLabel.Visibility = [System.Windows.Visibility]::Visible - $script:txtModelLabel.Visibility = [System.Windows.Visibility]::Visible + $script:cmbWindowsLang = $window.FindName('cmbWindowsLang') + $allowedLangs = @('ar-sa','bg-bg','cs-cz','da-dk','de-de','el-gr','en-gb','en-us','es-es','es-mx','et-ee','fi-fi','fr-ca','fr-fr','he-il','hr-hr','hu-hu','it-it','ja-jp','ko-kr','lt-lt','lv-lv','nb-no','nl-nl','pl-pl','pt-br','pt-pt','ro-ro','ru-ru','sk-sk','sl-si','sr-latn-rs','sv-se','th-th','tr-tr','uk-ua','zh-cn','zh-tw') + foreach ($lang in $allowedLangs) { + [void]$script:cmbWindowsLang.Items.Add($lang) } - else { - $script:cmbMake.Visibility = [System.Windows.Visibility]::Collapsed - $script:cmbModel.Visibility = [System.Windows.Visibility]::Collapsed - $script:txtMakeLabel.Visibility = [System.Windows.Visibility]::Collapsed - $script:txtModelLabel.Visibility = [System.Windows.Visibility]::Collapsed + $script:cmbWindowsLang.SelectedItem = $defaultWindowsLang + + $script:cmbWindowsSKU = $window.FindName('cmbWindowsSKU') + $script:cmbWindowsSKU.Items.Clear() + foreach ($sku in $skuList) { + [void]$script:cmbWindowsSKU.Items.Add($sku) } + $script:cmbWindowsSKU.SelectedItem = $defaultWindowsSKU - $chkDownloadDrivers.Add_Checked({ - $script:cmbMake.Visibility = [System.Windows.Visibility]::Visible - $script:cmbModel.Visibility = [System.Windows.Visibility]::Visible - $script:txtMakeLabel.Visibility = [System.Windows.Visibility]::Visible - $script:txtModelLabel.Visibility = [System.Windows.Visibility]::Visible - }) - - $chkDownloadDrivers.Add_Unchecked({ - $script:cmbMake.Visibility = [System.Windows.Visibility]::Collapsed - $script:cmbModel.Visibility = [System.Windows.Visibility]::Collapsed - $script:txtMakeLabel.Visibility = [System.Windows.Visibility]::Collapsed - $script:txtModelLabel.Visibility = [System.Windows.Visibility]::Collapsed - }) - - # Remove or comment out the ComboBox population logic for cmbModel - # $script:cmbMake.Add_SelectionChanged({ - # param($sender, $eventArgs) - # - # $selectedMake = $sender.SelectedItem # Changed from $sender.SelectedItem.Content - # - # $script:cmbModel.Items.Clear() - # - # switch ($selectedMake) { - # 'Microsoft' { - # $script:cmbModel.Items.Add('Surface Pro') - # $script:cmbModel.Items.Add('Surface Laptop') - # # Add more Microsoft models - # } - # 'Dell' { - # $script:cmbModel.Items.Add('XPS 13') - # $script:cmbModel.Items.Add('Inspiron 15') - # # Add more Dell models - # } - # 'HP' { - # $script:cmbModel.Items.Add('Spectre x360') - # $script:cmbModel.Items.Add('Envy 13') - # # Add more HP models - # } - # 'Lenovo' { - # $script:cmbModel.Items.Add('ThinkPad X1') - # $script:cmbModel.Items.Add('Yoga 7i') - # # Add more Lenovo models - # } - # default { - # # Handle unexpected Make selections - # } - # } - # }) - - # Populate cmbMake ComboBox with Make options - $makeList = @('Microsoft', 'Dell', 'HP', 'Lenovo') # Add more manufacturers as needed - foreach ($make in $makeList) { - $cmbMake.Items.Add($make) | Out-Null + $script:cmbMediaType = $window.FindName('cmbMediaType') + foreach ($mt in 'consumer','business') { + [void]$script:cmbMediaType.Items.Add($mt) } + $script:cmbMediaType.SelectedItem = $defaultMediaType - if ($cmbMake.Items.Count -gt 0) { - $cmbMake.SelectedIndex = 0 - } + $window.FindName('txtOptionalFeatures').Text = $defaultOptionalFeatures + $window.FindName('txtProductKey').Text = $defaultProductKey - $chkDownloadDrivers = $window.FindName('chkDownloadDrivers') - $spMakeModelSection = $window.FindName('spMakeModelSection') + # Drivers tab + $script:chkDownloadDrivers = $window.FindName('chkDownloadDrivers') + $script:cmbMake = $window.FindName('cmbMake') + $script:cmbModel = $window.FindName('cmbModel') + $script:spMakeModelSection = $window.FindName('spMakeModelSection') - # Control visibility when checkbox is checked/unchecked - $chkDownloadDrivers.Add_Checked({ - $spMakeModelSection.Visibility = [System.Windows.Visibility]::Visible - }) - $chkDownloadDrivers.Add_Unchecked({ - $spMakeModelSection.Visibility = [System.Windows.Visibility]::Collapsed - }) - - $script:chkDownloadDrivers = [System.Windows.Controls.CheckBox]$window.FindName('chkDownloadDrivers') - $script:spMakeModelSection = [System.Windows.Controls.StackPanel]$window.FindName('spMakeModelSection') + $makeList = @('Microsoft','Dell','HP','Lenovo') + foreach ($m in $makeList) { [void]$script:cmbMake.Items.Add($m) } + if ($script:cmbMake.Items.Count -gt 0) { $script:cmbMake.SelectedIndex = 0 } $script:chkDownloadDrivers.Add_Checked({ - $script:spMakeModelSection.Visibility = [System.Windows.Visibility]::Visible + $script:cmbMake.Visibility = 'Visible' + $script:cmbModel.Visibility = 'Visible' + $script:spMakeModelSection.Visibility = 'Visible' }) $script:chkDownloadDrivers.Add_Unchecked({ - $script:spMakeModelSection.Visibility = [System.Windows.Visibility]::Collapsed + $script:cmbMake.Visibility = 'Collapsed' + $script:cmbModel.Visibility = 'Collapsed' + $script:spMakeModelSection.Visibility = 'Collapsed' }) - $script:chkInstallDrivers = [System.Windows.Controls.CheckBox]$window.FindName('chkInstallDrivers') - $script:chkCopyDrivers = [System.Windows.Controls.CheckBox]$window.FindName('chkCopyDrivers') - - $script:chkInstallDrivers.Add_Checked({ - $script:chkCopyDrivers.IsEnabled = $false - }) - $script:chkInstallDrivers.Add_Unchecked({ - $script:chkCopyDrivers.IsEnabled = $true - }) - - $script:chkCopyDrivers.Add_Checked({ - $script:chkInstallDrivers.IsEnabled = $false - }) - $script:chkCopyDrivers.Add_Unchecked({ - $script:chkInstallDrivers.IsEnabled = $true - }) - - # Assign FFUDevelopmentPath to the TextBox - $window.FindName('txtFFUDevPath').Text = $FFUDevelopmentPath - - # Set default values for Drivers Folder and PE Drivers Folder - $window.FindName('txtDriversFolder').Text = Join-Path -Path $FFUDevelopmentPath -ChildPath "Drivers" - $window.FindName('txtPEDriversFolder').Text = Join-Path -Path $FFUDevelopmentPath -ChildPath "PEDrivers" - - # Find the Install Office and Install Apps checkboxes + # Office interplay $script:chkInstallOffice = $window.FindName('chkInstallOffice') - $script:chkInstallApps = $window.FindName('chkInstallApps') + $script:chkInstallApps = $window.FindName('chkInstallApps') + $script:installAppsCheckedByOffice = $false + + $script:OfficePathStackPanel = $window.FindName('OfficePathStackPanel') + $script:OfficePathGrid = $window.FindName('OfficePathGrid') + $script:CopyOfficeConfigXMLStackPanel = $window.FindName('CopyOfficeConfigXMLStackPanel') + $script:OfficeConfigurationXMLFileStackPanel = $window.FindName('OfficeConfigurationXMLFileStackPanel') + $script:OfficeConfigurationXMLFileGrid = $window.FindName('OfficeConfigurationXMLFileGrid') + $script:chkCopyOfficeConfigXML = $window.FindName('chkCopyOfficeConfigXML') + + if ($script:chkInstallOffice.IsChecked) { + $script:OfficePathStackPanel.Visibility = 'Visible' + $script:OfficePathGrid.Visibility = 'Visible' + $script:CopyOfficeConfigXMLStackPanel.Visibility = 'Visible' + } + else { + $script:OfficePathStackPanel.Visibility = 'Collapsed' + $script:OfficePathGrid.Visibility = 'Collapsed' + $script:CopyOfficeConfigXMLStackPanel.Visibility = 'Collapsed' + $script:OfficeConfigurationXMLFileStackPanel.Visibility = 'Collapsed' + $script:OfficeConfigurationXMLFileGrid.Visibility = 'Collapsed' + } - # Add event handler for Install Office Checked $script:chkInstallOffice.Add_Checked({ if (-not $script:chkInstallApps.IsChecked) { $script:chkInstallApps.IsChecked = $true $script:installAppsCheckedByOffice = $true } $script:chkInstallApps.IsEnabled = $false + $script:OfficePathStackPanel.Visibility = 'Visible' + $script:OfficePathGrid.Visibility = 'Visible' + $script:CopyOfficeConfigXMLStackPanel.Visibility = 'Visible' }) - - # Add event handler for Install Office Unchecked $script:chkInstallOffice.Add_Unchecked({ if ($script:installAppsCheckedByOffice) { $script:chkInstallApps.IsChecked = $false $script:installAppsCheckedByOffice = $false } $script:chkInstallApps.IsEnabled = $true + $script:OfficePathStackPanel.Visibility = 'Collapsed' + $script:OfficePathGrid.Visibility = 'Collapsed' + $script:CopyOfficeConfigXMLStackPanel.Visibility = 'Collapsed' + $script:OfficeConfigurationXMLFileStackPanel.Visibility = 'Collapsed' + $script:OfficeConfigurationXMLFileGrid.Visibility = 'Collapsed' }) - # Initialize additional script-scoped variables - $script:installAppsCheckedManually = $false + $script:chkCopyOfficeConfigXML.Add_Checked({ + $script:OfficeConfigurationXMLFileStackPanel.Visibility = 'Visible' + $script:OfficeConfigurationXMLFileGrid.Visibility = 'Visible' + }) + $script:chkCopyOfficeConfigXML.Add_Unchecked({ + $script:OfficeConfigurationXMLFileStackPanel.Visibility = 'Collapsed' + $script:OfficeConfigurationXMLFileGrid.Visibility = 'Collapsed' + }) - # Assign script-scoped variables - $script:chkInstallOffice = $window.FindName('chkInstallOffice') - $script:chkInstallApps = $window.FindName('chkInstallApps') - # ...assign other script-scoped variables... - - # Add event handler for Install Apps Checked manually - $script:chkInstallApps.Add_Checked({ - if (-not $script:installAppsCheckedByOffice) { - # User checked Install Apps manually - $script:installAppsCheckedManually = $true - } - }) - - # Add event handler for Install Apps Unchecked manually - $script:chkInstallApps.Add_Unchecked({ - if (-not $script:installAppsCheckedByOffice) { - # User unchecked Install Apps manually - $script:installAppsCheckedManually = $false - } - }) - - # Add event handler for Install Office Checked - $script:chkInstallOffice.Add_Checked({ - if (-not $script:chkInstallApps.IsChecked) { - $script:chkInstallApps.IsChecked = $true - $script:installAppsCheckedByOffice = $true - } - $script:chkInstallApps.IsEnabled = $false - }) - - # Add event handler for Install Office Unchecked - $script:chkInstallOffice.Add_Unchecked({ - if ($script:installAppsCheckedByOffice) { - $script:chkInstallApps.IsChecked = $false - $script:installAppsCheckedByOffice = $false - } - $script:chkInstallApps.IsEnabled = $true - }) + # Optional Features + $script:chkTelnetClient = $window.FindName('chkTelnetClient') + $script:chkNetFx3 = $window.FindName('chkNetFx3') + $script:chkDirectPlay = $window.FindName('chkDirectPlay') + $script:chkSMB1Protocol = $window.FindName('chkSMB1Protocol') + $script:txtOptionalFeatures = $window.FindName('txtOptionalFeatures') + + $script:chkTelnetClient.Add_Checked({ UpdateOptionalFeaturesString }) + $script:chkTelnetClient.Add_Unchecked({ UpdateOptionalFeaturesString }) + $script:chkNetFx3.Add_Checked({ UpdateOptionalFeaturesString }) + $script:chkNetFx3.Add_Unchecked({ UpdateOptionalFeaturesString }) + $script:chkDirectPlay.Add_Checked({ UpdateOptionalFeaturesString }) + $script:chkDirectPlay.Add_Unchecked({ UpdateOptionalFeaturesString }) + $script:chkSMB1Protocol.Add_Checked({ UpdateOptionalFeaturesString }) + $script:chkSMB1Protocol.Add_Unchecked({ UpdateOptionalFeaturesString }) +}) + +# Button: Build FFU +$btnRun = $window.FindName('btnRun') +$btnRun.Add_Click({ + try { + $progressBar = $window.FindName('progressBar') + $txtStatus = $window.FindName('txtStatus') + $progressBar.Visibility = 'Visible' + $txtStatus.Text = "Starting FFU build..." + + $config = Get-UIConfig + $configFilePath = Join-Path $config.FFUDevelopmentPath "FFUConfig.json" + $config | ConvertTo-Json -Depth 10 | Set-Content $configFilePath -Encoding UTF8 + + $txtStatus.Text = "Executing BuildFFUVM script with config file..." + & "$PSScriptRoot\BuildFFUVM.ps1" -ConfigFile $configFilePath -Verbose + + # If Office config XML needed + if ($config.InstallOffice -and $config.OfficeConfigXMLFile) { + Copy-Item -Path $config.OfficeConfigXMLFile -Destination $config.OfficePath -Force + $txtStatus.Text = "Office Configuration XML file copied successfully." + } + + $txtStatus.Text = "FFU build completed successfully." + } + catch { + [System.Windows.MessageBox]::Show("An error occurred: $_", "Error", "OK", "Error") + $window.FindName('txtStatus').Text = "FFU build failed." + } + finally { + $window.FindName('progressBar').Visibility = 'Collapsed' + } +}) + +# Button: Build Config +$btnBuildConfig = $window.FindName('btnBuildConfig') +$btnBuildConfig.Add_Click({ + try { + $config = Get-UIConfig + + $defaultConfigPath = Join-Path $config.FFUDevelopmentPath "config" + if (-not (Test-Path $defaultConfigPath)) { + New-Item -Path $defaultConfigPath -ItemType Directory -Force | Out-Null + } + + $sfd = New-Object System.Windows.Forms.SaveFileDialog + $sfd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*" + $sfd.Title = "Save Configuration File" + $sfd.InitialDirectory= $defaultConfigPath + $sfd.FileName = "FFUConfig.json" + + if ($sfd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { + $savePath = $sfd.FileName + $config | ConvertTo-Json -Depth 10 | Set-Content $savePath -Encoding UTF8 + + [System.Windows.MessageBox]::Show( + "Configuration file saved to:`n$savePath", + "Success", + "OK", + "Information" + ) + } + } + catch { + [System.Windows.MessageBox]::Show("Error saving config file:`n$_","Error","OK","Error") + } }) -# Show the window [void]$window.ShowDialog() diff --git a/FFUDevelopment/BuildFFUVM_UI.xaml b/FFUDevelopment/BuildFFUVM_UI.xaml index 88b20df..2d547c2 100644 --- a/FFUDevelopment/BuildFFUVM_UI.xaml +++ b/FFUDevelopment/BuildFFUVM_UI.xaml @@ -2,123 +2,274 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="FFU Builder UI" Height="600" Width="900"> - + - + - - + + + + - - - - - - - + + + + + - + - + - - - + + + - + - - - + + - -