mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-13 18:07:20 -06:00
d6361dac4d
- Enables automatic horizontal and vertical scrollbars for ListViews in the UI to improve navigation. - Introduces functions to dynamically calculate and apply column widths based on the visible content and header text. - Triggers column auto-resizing across various modules whenever ListView data is updated or refreshed. - Renames a path normalization function and updates an event handler parameter name for clarity.
1286 lines
70 KiB
PowerShell
1286 lines
70 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Contains functions for loading and saving UI configuration.
|
|
.DESCRIPTION
|
|
This module provides the core logic for loading and saving the UI configuration. It includes functions to gather settings from the various UI controls, save them to a JSON file, and load settings from a JSON file to populate the UI. This allows users to persist their build configurations and easily switch between different setups.
|
|
#>
|
|
function Get-UIConfig {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
# Create hash to store configuration
|
|
$config = [ordered]@{
|
|
AllowExternalHardDiskMedia = $State.Controls.chkAllowExternalHardDiskMedia.IsChecked
|
|
AllowVHDXCaching = $State.Controls.chkAllowVHDXCaching.IsChecked
|
|
AppListPath = $State.Controls.txtAppListJsonPath.Text
|
|
AppsPath = $State.Controls.txtApplicationPath.Text
|
|
AppsScriptVariables = if ($State.Controls.chkDefineAppsScriptVariables.IsChecked) {
|
|
$vars = @{}
|
|
foreach ($item in $State.Data.appsScriptVariablesDataList) {
|
|
$vars[$item.Key] = $item.Value
|
|
}
|
|
if ($vars.Count -gt 0) { $vars } else { $null }
|
|
}
|
|
else { $null }
|
|
BuildUSBDrive = $State.Controls.chkBuildUSBDriveEnable.IsChecked
|
|
CleanupAppsISO = $State.Controls.chkCleanupAppsISO.IsChecked
|
|
CleanupCaptureISO = $State.Controls.chkCleanupCaptureISO.IsChecked
|
|
CleanupDeployISO = $State.Controls.chkCleanupDeployISO.IsChecked
|
|
CleanupDrivers = $State.Controls.chkCleanupDrivers.IsChecked
|
|
CompactOS = $State.Controls.chkCompactOS.IsChecked
|
|
CompressDownloadedDriversToWim = $State.Controls.chkCompressDriversToWIM.IsChecked
|
|
CopyAutopilot = $State.Controls.chkCopyAutopilot.IsChecked
|
|
CopyDrivers = $State.Controls.chkCopyDrivers.IsChecked
|
|
CopyOfficeConfigXML = $State.Controls.chkCopyOfficeConfigXML.IsChecked
|
|
CopyPEDrivers = $State.Controls.chkCopyPEDrivers.IsChecked
|
|
UseDriversAsPEDrivers = $State.Controls.chkUseDriversAsPEDrivers.IsChecked
|
|
CopyPPKG = $State.Controls.chkCopyPPKG.IsChecked
|
|
CopyUnattend = $State.Controls.chkCopyUnattend.IsChecked
|
|
CopyAdditionalFFUFiles = $State.Controls.chkCopyAdditionalFFUFiles.IsChecked
|
|
CreateCaptureMedia = $State.Controls.chkCreateCaptureMedia.IsChecked
|
|
CreateDeploymentMedia = $State.Controls.chkCreateDeploymentMedia.IsChecked
|
|
InjectUnattend = $State.Controls.chkInjectUnattend.IsChecked
|
|
CustomFFUNameTemplate = $State.Controls.txtCustomFFUNameTemplate.Text
|
|
Disksize = [int64]$State.Controls.txtDiskSize.Text * 1GB
|
|
DownloadDrivers = $State.Controls.chkDownloadDrivers.IsChecked
|
|
DriversFolder = $State.Controls.txtDriversFolder.Text
|
|
DriversJsonPath = $State.Controls.txtDriversJsonPath.Text
|
|
FFUCaptureLocation = $State.Controls.txtFFUCaptureLocation.Text
|
|
FFUDevelopmentPath = $State.Controls.txtFFUDevPath.Text
|
|
FFUPrefix = $State.Controls.txtVMNamePrefix.Text
|
|
InstallApps = $State.Controls.chkInstallApps.IsChecked
|
|
InstallDrivers = $State.Controls.chkInstallDrivers.IsChecked
|
|
InstallOffice = $State.Controls.chkInstallOffice.IsChecked
|
|
InstallWingetApps = $State.Controls.chkInstallWingetApps.IsChecked
|
|
ISOPath = $State.Controls.txtISOPath.Text
|
|
WindowsMediaSource = if ($null -ne $State.Controls.rbProvideISO -and $State.Controls.rbProvideISO.IsChecked) { "Provide Windows ISO" } else { "Download Windows ESD" }
|
|
LogicalSectorSizeBytes = [int]$State.Controls.cmbLogicalSectorSize.SelectedItem.Content
|
|
# Make = $null
|
|
MediaType = $State.Controls.cmbMediaType.SelectedItem
|
|
Memory = [int64]$State.Controls.txtMemory.Text * 1GB
|
|
# Model = if ($State.Controls.chkDownloadDrivers.IsChecked) {
|
|
# $selectedModels = $State.Controls.lstDriverModels.Items | Where-Object { $_.IsSelected }
|
|
# if ($selectedModels.Count -ge 1) {
|
|
# $selectedModels[0].Model
|
|
# }
|
|
# else {
|
|
# $null
|
|
# }
|
|
# }
|
|
# else {
|
|
# $null
|
|
# }
|
|
OfficeConfigXMLFile = $State.Controls.txtOfficeConfigXMLFilePath.Text
|
|
OfficePath = $State.Controls.txtOfficePath.Text
|
|
Optimize = $State.Controls.chkOptimize.IsChecked
|
|
OptionalFeatures = (($State.Controls.featureCheckBoxes.GetEnumerator() | Where-Object { $_.Value.IsChecked } | ForEach-Object { $_.Key } | Sort-Object) -join ';')
|
|
OrchestrationPath = "$($State.Controls.txtApplicationPath.Text)\Orchestration"
|
|
PEDriversFolder = $State.Controls.txtPEDriversFolder.Text
|
|
Processors = [int]$State.Controls.txtProcessors.Text
|
|
ProductKey = $State.Controls.txtProductKey.Text
|
|
PromptExternalHardDiskMedia = $State.Controls.chkPromptExternalHardDiskMedia.IsChecked
|
|
RemoveApps = $State.Controls.chkRemoveApps.IsChecked
|
|
RemoveFFU = $State.Controls.chkRemoveFFU.IsChecked
|
|
RemoveUpdates = $State.Controls.chkRemoveUpdates.IsChecked
|
|
RemoveDownloadedESD = $State.Controls.chkRemoveDownloadedESD.IsChecked
|
|
ShareName = $State.Controls.txtShareName.Text
|
|
UpdateADK = $State.Controls.chkUpdateADK.IsChecked
|
|
UpdateEdge = $State.Controls.chkUpdateEdge.IsChecked
|
|
UpdateLatestCU = $State.Controls.chkUpdateLatestCU.IsChecked
|
|
UpdateLatestDefender = $State.Controls.chkUpdateLatestDefender.IsChecked
|
|
UpdateLatestMicrocode = $State.Controls.chkUpdateLatestMicrocode.IsChecked
|
|
UpdateLatestMSRT = $State.Controls.chkUpdateLatestMSRT.IsChecked
|
|
UpdateLatestNet = $State.Controls.chkUpdateLatestNet.IsChecked
|
|
UpdateOneDrive = $State.Controls.chkUpdateOneDrive.IsChecked
|
|
UpdatePreviewCU = $State.Controls.chkUpdatePreviewCU.IsChecked
|
|
UserAppListPath = $State.Controls.txtUserAppListPath.Text
|
|
USBDriveList = @{}
|
|
Username = $State.Controls.txtUsername.Text
|
|
Threads = [int]$State.Controls.txtThreads.Text
|
|
BitsPriority = $State.Controls.cmbBitsPriority.SelectedItem
|
|
MaxUSBDrives = [int]$State.Controls.txtMaxUSBDrives.Text
|
|
ThemeMode = if ($null -ne $State.Controls.cmbThemeMode -and $null -ne $State.Controls.cmbThemeMode.SelectedItem) { $State.Controls.cmbThemeMode.SelectedItem } else { "System" }
|
|
Verbose = $State.Controls.chkVerbose.IsChecked
|
|
VMHostIPAddress = $State.Controls.txtVMHostIPAddress.Text
|
|
VMLocation = $State.Controls.txtVMLocation.Text
|
|
VMSwitchName = if ($State.Controls.cmbVMSwitchName.SelectedItem -eq 'Other') {
|
|
$State.Controls.txtCustomVMSwitchName.Text
|
|
}
|
|
else {
|
|
$State.Controls.cmbVMSwitchName.SelectedItem
|
|
}
|
|
WindowsArch = $State.Controls.cmbWindowsArch.SelectedItem
|
|
WindowsLang = $State.Controls.cmbWindowsLang.SelectedItem
|
|
WindowsRelease = [int]$State.Controls.cmbWindowsRelease.SelectedItem.Value
|
|
WindowsSKU = $State.Controls.cmbWindowsSKU.SelectedItem
|
|
WindowsVersion = $State.Controls.cmbWindowsVersion.SelectedItem
|
|
}
|
|
|
|
# Save selected USB drives using UniqueId for reliable identification
|
|
# Multiple physical drives can share the same Model, so store an array of UniqueIds per Model.
|
|
$State.Controls.lstUSBDrives.Items | Where-Object { $_.IsSelected } | ForEach-Object {
|
|
$modelName = $_.Model
|
|
$uniqueId = $_.UniqueId
|
|
|
|
if ([string]::IsNullOrWhiteSpace($modelName) -or [string]::IsNullOrWhiteSpace($uniqueId)) {
|
|
return
|
|
}
|
|
|
|
# Ensure the hashtable value is always an array so multiple same-model drives are preserved
|
|
$existingUniqueIds = $config.USBDriveList[$modelName]
|
|
if ($null -eq $existingUniqueIds) {
|
|
$config.USBDriveList[$modelName] = @($uniqueId)
|
|
return
|
|
}
|
|
|
|
$existingUniqueIds = @($existingUniqueIds)
|
|
if (-not ($existingUniqueIds -contains $uniqueId)) {
|
|
$existingUniqueIds += $uniqueId
|
|
}
|
|
$config.USBDriveList[$modelName] = $existingUniqueIds
|
|
}
|
|
|
|
# Additional FFU file selections
|
|
$config.AdditionalFFUFiles = @()
|
|
if ($State.Controls.chkCopyAdditionalFFUFiles.IsChecked) {
|
|
$config.AdditionalFFUFiles = @(
|
|
$State.Controls.lstAdditionalFFUs.Items |
|
|
Where-Object { $_.IsSelected } |
|
|
ForEach-Object { $_.FullName }
|
|
)
|
|
}
|
|
|
|
return $config
|
|
}
|
|
|
|
function Set-UIValue {
|
|
param(
|
|
[string]$ControlName,
|
|
[string]$PropertyName,
|
|
[object]$ConfigObject,
|
|
[string]$ConfigKey,
|
|
[scriptblock]$TransformValue = $null, # Optional scriptblock to transform the value from config
|
|
[psobject]$State # Pass the $State object
|
|
)
|
|
|
|
$control = $State.Controls[$ControlName]
|
|
if ($null -eq $control) {
|
|
WriteLog "LoadConfig Error: Control '$ControlName' not found in the state object."
|
|
return
|
|
}
|
|
|
|
# Robust check for property existence.
|
|
$keyExists = $false
|
|
if ($ConfigObject -is [System.Management.Automation.PSCustomObject] -and $null -ne $ConfigObject.PSObject.Properties) {
|
|
# Use the Match() method, which returns a collection of matching properties.
|
|
# If the count is greater than 0, the key exists.
|
|
try {
|
|
if (($ConfigObject.PSObject.Properties.Match($ConfigKey)).Count -gt 0) {
|
|
$keyExists = $true
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "ERROR: Exception while trying to Match key '$ConfigKey' on ConfigObject.PSObject.Properties. Error: $($_.Exception.Message)"
|
|
# $keyExists remains false
|
|
}
|
|
}
|
|
|
|
if (-not $keyExists) {
|
|
WriteLog "LoadConfig Info: Key '$ConfigKey' not found in configuration object. Skipping '$ControlName.$PropertyName'."
|
|
return
|
|
}
|
|
|
|
$valueFromConfig = $ConfigObject.$ConfigKey
|
|
WriteLog "LoadConfig: Preparing to set '$ControlName.$PropertyName'. Config key: '$ConfigKey', Raw value: '$valueFromConfig'."
|
|
|
|
$finalValue = $valueFromConfig
|
|
if ($null -ne $TransformValue) {
|
|
try {
|
|
$finalValue = Invoke-Command -ScriptBlock $TransformValue -ArgumentList $valueFromConfig
|
|
WriteLog "LoadConfig: Transformed value for '$ControlName.$PropertyName' (from key '$ConfigKey') is: '$finalValue'."
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig Error: Failed to transform value for '$ControlName.$PropertyName' from key '$ConfigKey'. Error: $($_.Exception.Message)"
|
|
return
|
|
}
|
|
}
|
|
|
|
try {
|
|
# Handle ComboBox SelectedItem specifically
|
|
if ($control -is [System.Windows.Controls.ComboBox] -and $PropertyName -eq 'SelectedItem') {
|
|
$itemToSelect = $null
|
|
# Iterate through the Items collection of the ComboBox
|
|
foreach ($item in $control.Items) {
|
|
$itemValue = $null
|
|
if ($item -is [System.Windows.Controls.ComboBoxItem]) {
|
|
$itemValue = $item.Content
|
|
}
|
|
elseif ($item -is [pscustomobject] -and $item.PSObject.Properties['Value']) {
|
|
$itemValue = $item.Value
|
|
}
|
|
elseif ($item -is [pscustomobject] -and $item.PSObject.Properties['Display']) {
|
|
# Assuming 'Display' might be used if 'Value' isn't
|
|
$itemValue = $item.Display
|
|
}
|
|
else {
|
|
$itemValue = $item # For simple string items or direct object comparison
|
|
}
|
|
|
|
# Compare, ensuring types are compatible or converting $finalValue if necessary
|
|
if (($null -ne $itemValue -and $itemValue.ToString() -eq $finalValue.ToString()) -or ($item -eq $finalValue)) {
|
|
$itemToSelect = $item
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($null -ne $itemToSelect) {
|
|
$control.SelectedItem = $itemToSelect
|
|
WriteLog "LoadConfig: Successfully set '$ControlName.SelectedItem' by finding matching item for value '$finalValue'."
|
|
}
|
|
elseif ($control.IsEditable -and ($finalValue -is [string] -or $finalValue -is [int] -or $finalValue -is [long])) {
|
|
$control.Text = $finalValue.ToString()
|
|
WriteLog "LoadConfig: Set '$ControlName.Text' to '$($finalValue.ToString())' as SelectedItem match failed (editable ComboBox)."
|
|
}
|
|
else {
|
|
$itemsString = ""
|
|
try {
|
|
# Safer way to get item strings
|
|
$itemStrings = @()
|
|
foreach ($cbItem in $control.Items) {
|
|
if ($null -ne $cbItem) { $itemStrings += $cbItem.ToString() } else { $itemStrings += "[NULL_ITEM]" }
|
|
}
|
|
$itemsString = $itemStrings -join "; "
|
|
}
|
|
catch { $itemsString = "Error retrieving item strings." }
|
|
WriteLog "LoadConfig Warning: Could not find or set item matching value '$finalValue' for '$ControlName.SelectedItem'. Current items: [$itemsString]"
|
|
}
|
|
}
|
|
else {
|
|
# For other properties or controls
|
|
$control.$PropertyName = $finalValue
|
|
WriteLog "LoadConfig: Successfully set '$ControlName.$PropertyName' to '$finalValue'."
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig Error: Failed to set '$ControlName.$PropertyName' to '$finalValue'. Error: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
function Get-ConfigDriverBaseName {
|
|
param(
|
|
[string]$RawName
|
|
)
|
|
|
|
if ([string]::IsNullOrWhiteSpace($RawName)) {
|
|
return $RawName
|
|
}
|
|
|
|
if ($RawName -match '^(.*?)\s*\((.+)\)\s*$') {
|
|
return $matches[1].Trim()
|
|
}
|
|
|
|
return $RawName.Trim()
|
|
}
|
|
|
|
function Get-ConfigDriverDisplayName {
|
|
param(
|
|
[string]$Make,
|
|
[string]$StoredName,
|
|
[string]$ProductName,
|
|
[string]$SystemId,
|
|
[string]$MachineType
|
|
)
|
|
|
|
$baseName = if (-not [string]::IsNullOrWhiteSpace($ProductName)) { $ProductName } else { Get-ConfigDriverBaseName -RawName $StoredName }
|
|
|
|
switch ($Make) {
|
|
'Dell' {
|
|
if ([string]::IsNullOrWhiteSpace($baseName)) { $baseName = $StoredName }
|
|
if ([string]::IsNullOrWhiteSpace($SystemId)) { return $baseName }
|
|
return "{0} ({1})" -f $baseName.Trim(), $SystemId.Trim()
|
|
}
|
|
'HP' {
|
|
if ([string]::IsNullOrWhiteSpace($baseName)) { $baseName = $StoredName }
|
|
if ([string]::IsNullOrWhiteSpace($SystemId)) { return $baseName }
|
|
return "{0} ({1})" -f $baseName.Trim(), $SystemId.Trim()
|
|
}
|
|
'Lenovo' {
|
|
if ([string]::IsNullOrWhiteSpace($baseName)) { $baseName = $StoredName }
|
|
if ([string]::IsNullOrWhiteSpace($MachineType)) { return $baseName }
|
|
return "{0} ({1})" -f $baseName.Trim(), $MachineType.Trim()
|
|
}
|
|
default {
|
|
return $StoredName
|
|
}
|
|
}
|
|
}
|
|
|
|
function Invoke-LoadConfiguration {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
try {
|
|
$filePath = Invoke-BrowseAction -Type 'OpenFile' -Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" -Title "Load Configuration File"
|
|
if (-not $filePath) {
|
|
WriteLog "Load configuration cancelled by user."
|
|
return
|
|
}
|
|
WriteLog "Loading configuration from: $filePath"
|
|
$raw = $null
|
|
try {
|
|
$raw = Get-Content -Path $filePath -Raw -ErrorAction Stop
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig Error: Failed reading file $filePath : $($_.Exception.Message)"
|
|
[System.Windows.MessageBox]::Show("Failed to read the configuration file.`n$($_.Exception.Message)", "Load Error", "OK", "Error")
|
|
return
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($raw)) {
|
|
WriteLog "LoadConfig Error: File $filePath is empty."
|
|
[System.Windows.MessageBox]::Show("The selected configuration file is empty.", "Load Error", "OK", "Error")
|
|
return
|
|
}
|
|
$configContent = $null
|
|
try {
|
|
$configContent = $raw | ConvertFrom-Json -ErrorAction Stop
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig Error: JSON parse failure for $filePath : $($_.Exception.Message)"
|
|
[System.Windows.MessageBox]::Show("Failed to parse the configuration file (invalid JSON).`n$($_.Exception.Message)", "Load Error", "OK", "Error")
|
|
return
|
|
}
|
|
if ($null -eq $configContent) {
|
|
WriteLog "LoadConfig Error: Parsed config object is null after $filePath."
|
|
[System.Windows.MessageBox]::Show("Parsed configuration object was null.", "Load Error", "OK", "Error")
|
|
return
|
|
}
|
|
WriteLog "LoadConfig: Successfully parsed config file. Top-level keys: $($configContent.PSObject.Properties.Name -join ', ')"
|
|
Update-UIFromConfig -ConfigContent $configContent -State $State
|
|
$State.Data.lastConfigFilePath = $filePath
|
|
Import-ConfigSupplementalAssets -ConfigContent $configContent -State $State -ShowWarnings:$true
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig FATAL Error: $($_.Exception.ToString())"
|
|
[System.Windows.MessageBox]::Show("Error loading config file:`n$($_.Exception.Message)", "Error", "OK", "Error")
|
|
}
|
|
}
|
|
|
|
function Select-VMSwitchFromConfig {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State,
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$ConfigContent
|
|
)
|
|
|
|
# Select VM switch based on configuration; fall back to 'Other' with custom name.
|
|
$combo = $State.Controls.cmbVMSwitchName
|
|
if ($null -eq $combo) {
|
|
WriteLog "LoadConfig Error: 'cmbVMSwitchName' control not found."
|
|
return
|
|
}
|
|
|
|
$configSwitch = $ConfigContent.VMSwitchName
|
|
if ($null -eq $configSwitch -or [string]::IsNullOrWhiteSpace($configSwitch)) {
|
|
WriteLog "LoadConfig Info: VMSwitchName in config was empty or null. Leaving selection unchanged."
|
|
return
|
|
}
|
|
|
|
$itemFound = $false
|
|
foreach ($item in $combo.Items) {
|
|
if ($null -ne $item -and $item.ToString().Equals($configSwitch, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
$itemFound = $true
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($itemFound) {
|
|
$combo.SelectedItem = ($combo.Items | Where-Object { $_.ToString().Equals($configSwitch, [System.StringComparison]::OrdinalIgnoreCase) } | Select-Object -First 1)
|
|
$State.Controls.txtCustomVMSwitchName.Visibility = 'Collapsed'
|
|
WriteLog "LoadConfig: Selected existing VM switch '$configSwitch'."
|
|
}
|
|
else {
|
|
# Ensure 'Other' exists
|
|
$otherExists = $false
|
|
foreach ($item in $combo.Items) {
|
|
if ($null -ne $item -and $item.ToString() -eq 'Other') { $otherExists = $true; break }
|
|
}
|
|
if (-not $otherExists) { $combo.Items.Add('Other') | Out-Null }
|
|
|
|
# Select 'Other' and populate custom name
|
|
$combo.SelectedItem = 'Other'
|
|
$State.Controls.txtCustomVMSwitchName.Visibility = 'Visible'
|
|
$State.Controls.txtCustomVMSwitchName.Text = $configSwitch
|
|
$State.Data.customVMSwitchName = $configSwitch
|
|
$State.Data.customVMHostIP = $ConfigContent.VMHostIPAddress
|
|
WriteLog "LoadConfig: VMSwitchName '$configSwitch' not found. Selected 'Other' and populated custom VM Switch Name textbox."
|
|
}
|
|
}
|
|
|
|
function Update-UIFromConfig {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$ConfigContent,
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
|
|
WriteLog "Applying loaded configuration to the UI."
|
|
|
|
# Apply theme mode from config (must be done before other controls load for proper styling)
|
|
if ($null -ne $ConfigContent.PSObject.Properties.Item('ThemeMode') -and $State.Flags.isFluentSupported) {
|
|
$configTheme = $ConfigContent.ThemeMode
|
|
if ($configTheme -in @("Light", "Dark", "System")) {
|
|
Initialize-FluentTheme -Window $State.Window -ThemeMode $configTheme -State $State
|
|
Set-UIValue -ControlName 'cmbThemeMode' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'ThemeMode' -State $State
|
|
}
|
|
}
|
|
|
|
# Update Build tab values
|
|
Set-UIValue -ControlName 'txtFFUDevPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'FFUDevelopmentPath' -State $State
|
|
Set-UIValue -ControlName 'txtCustomFFUNameTemplate' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'CustomFFUNameTemplate' -State $State
|
|
Set-UIValue -ControlName 'txtFFUCaptureLocation' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'FFUCaptureLocation' -State $State
|
|
Set-UIValue -ControlName 'txtShareName' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'ShareName' -State $State
|
|
Set-UIValue -ControlName 'txtUsername' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Username' -State $State
|
|
Set-UIValue -ControlName 'txtThreads' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Threads' -State $State
|
|
Set-UIValue -ControlName 'cmbBitsPriority' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'BitsPriority' -State $State
|
|
Set-UIValue -ControlName 'txtMaxUSBDrives' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'MaxUSBDrives' -State $State
|
|
Set-UIValue -ControlName 'chkBuildUSBDriveEnable' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'BuildUSBDrive' -State $State
|
|
Set-UIValue -ControlName 'chkCompactOS' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CompactOS' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateADK' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateADK' -State $State
|
|
Set-UIValue -ControlName 'chkOptimize' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'Optimize' -State $State
|
|
Set-UIValue -ControlName 'chkAllowVHDXCaching' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'AllowVHDXCaching' -State $State
|
|
Set-UIValue -ControlName 'chkAllowExternalHardDiskMedia' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'AllowExternalHardDiskMedia' -State $State
|
|
Set-UIValue -ControlName 'chkPromptExternalHardDiskMedia' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'PromptExternalHardDiskMedia' -State $State
|
|
Set-UIValue -ControlName 'chkCopyAdditionalFFUFiles' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyAdditionalFFUFiles' -State $State
|
|
Set-UIValue -ControlName 'chkCreateCaptureMedia' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CreateCaptureMedia' -State $State
|
|
Set-UIValue -ControlName 'chkCreateDeploymentMedia' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CreateDeploymentMedia' -State $State
|
|
Set-UIValue -ControlName 'chkInjectUnattend' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'InjectUnattend' -State $State
|
|
Set-UIValue -ControlName 'chkVerbose' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'Verbose' -State $State
|
|
|
|
# USB Drive Modification group (Build Tab)
|
|
Set-UIValue -ControlName 'chkCopyAutopilot' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyAutopilot' -State $State
|
|
Set-UIValue -ControlName 'chkCopyUnattend' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyUnattend' -State $State
|
|
Set-UIValue -ControlName 'chkCopyPPKG' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyPPKG' -State $State
|
|
|
|
# Post Build Cleanup group (Build Tab)
|
|
Set-UIValue -ControlName 'chkCleanupAppsISO' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CleanupAppsISO' -State $State
|
|
Set-UIValue -ControlName 'chkCleanupCaptureISO' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CleanupCaptureISO' -State $State
|
|
Set-UIValue -ControlName 'chkCleanupDeployISO' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CleanupDeployISO' -State $State
|
|
Set-UIValue -ControlName 'chkCleanupDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CleanupDrivers' -State $State
|
|
Set-UIValue -ControlName 'chkRemoveFFU' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'RemoveFFU' -State $State
|
|
Set-UIValue -ControlName 'chkRemoveApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'RemoveApps' -State $State
|
|
Set-UIValue -ControlName 'chkRemoveUpdates' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'RemoveUpdates' -State $State
|
|
Set-UIValue -ControlName 'chkRemoveDownloadedESD' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'RemoveDownloadedESD' -State $State
|
|
|
|
# Hyper-V Settings
|
|
Select-VMSwitchFromConfig -State $State -ConfigContent $ConfigContent
|
|
Set-UIValue -ControlName 'txtVMHostIPAddress' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'VMHostIPAddress' -State $State
|
|
Set-UIValue -ControlName 'txtDiskSize' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Disksize' -TransformValue { param($val) $val / 1GB } -State $State
|
|
Set-UIValue -ControlName 'txtMemory' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Memory' -TransformValue { param($val) $val / 1GB } -State $State
|
|
Set-UIValue -ControlName 'txtProcessors' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Processors' -State $State
|
|
Set-UIValue -ControlName 'txtVMLocation' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'VMLocation' -State $State
|
|
Set-UIValue -ControlName 'txtVMNamePrefix' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'FFUPrefix' -State $State
|
|
Set-UIValue -ControlName 'cmbLogicalSectorSize' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'LogicalSectorSizeBytes' -TransformValue { param($val) $val.ToString() } -State $State
|
|
|
|
# Windows Settings
|
|
Set-UIValue -ControlName 'txtISOPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'ISOPath' -State $State
|
|
# Load Windows Media Source setting
|
|
if ($null -ne $ConfigContent.PSObject.Properties.Item('WindowsMediaSource')) {
|
|
if ($ConfigContent.WindowsMediaSource -eq 'Provide Windows ISO') {
|
|
$State.Controls.rbProvideISO.IsChecked = $true
|
|
}
|
|
else {
|
|
$State.Controls.rbDownloadESD.IsChecked = $true
|
|
}
|
|
}
|
|
|
|
# Special handling for Windows Release and SKU due to value collision (e.g., 2019 for Server and LTSC)
|
|
if (($null -ne $ConfigContent.PSObject.Properties.Item('WindowsRelease')) -and ($null -ne $ConfigContent.PSObject.Properties.Item('WindowsSKU'))) {
|
|
$configReleaseValue = $ConfigContent.WindowsRelease
|
|
$configSkuValue = $ConfigContent.WindowsSKU
|
|
WriteLog "LoadConfig: Handling Windows Release/SKU selection. Release: '$configReleaseValue', SKU: '$configSkuValue'."
|
|
|
|
$releaseCombo = $State.Controls.cmbWindowsRelease
|
|
# The items in the combobox are PSCustomObjects with Display and Value properties
|
|
$possibleReleases = $releaseCombo.Items | Where-Object { $_.Value -eq $configReleaseValue }
|
|
|
|
$releaseToSelect = $null
|
|
if ($possibleReleases.Count -gt 1) {
|
|
WriteLog "LoadConfig: Ambiguous release value '$configReleaseValue' found. Using SKU to disambiguate."
|
|
if ($configSkuValue -like '*LTS*') {
|
|
$releaseToSelect = $possibleReleases | Where-Object { $_.Display -like '*LTS*' } | Select-Object -First 1
|
|
WriteLog "LoadConfig: SKU contains 'LTS'. Selecting LTSC-related release: '$($releaseToSelect.Display)'."
|
|
}
|
|
else {
|
|
$releaseToSelect = $possibleReleases | Where-Object { $_.Display -notlike '*LTS*' } | Select-Object -First 1
|
|
WriteLog "LoadConfig: SKU does not contain 'LTS'. Selecting non-LTSC (Server) release: '$($releaseToSelect.Display)'."
|
|
}
|
|
}
|
|
else {
|
|
$releaseToSelect = $possibleReleases | Select-Object -First 1
|
|
if ($null -ne $releaseToSelect) {
|
|
WriteLog "LoadConfig: Found unique release match: '$($releaseToSelect.Display)'."
|
|
}
|
|
}
|
|
|
|
if ($null -ne $releaseToSelect) {
|
|
$releaseCombo.SelectedItem = $releaseToSelect
|
|
}
|
|
else {
|
|
WriteLog "LoadConfig: Could not determine a specific Windows Release to select for value '$configReleaseValue'. Skipping."
|
|
}
|
|
}
|
|
else {
|
|
# Fallback to individual setting if only one key exists
|
|
WriteLog "LoadConfig: WindowsRelease or WindowsSKU key not found in config. Falling back to simple assignment for WindowsRelease."
|
|
Set-UIValue -ControlName 'cmbWindowsRelease' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'WindowsRelease' -State $State
|
|
}
|
|
|
|
Set-UIValue -ControlName 'cmbWindowsVersion' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'WindowsVersion' -State $State
|
|
Set-UIValue -ControlName 'cmbWindowsArch' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'WindowsArch' -State $State
|
|
Set-UIValue -ControlName 'cmbWindowsLang' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'WindowsLang' -State $State
|
|
Set-UIValue -ControlName 'cmbWindowsSKU' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'WindowsSKU' -State $State
|
|
Set-UIValue -ControlName 'cmbMediaType' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'MediaType' -State $State
|
|
Set-UIValue -ControlName 'txtProductKey' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'ProductKey' -State $State
|
|
|
|
# Update Optional Features checkboxes
|
|
$loadedFeaturesString = $ConfigContent.OptionalFeatures
|
|
if (-not [string]::IsNullOrWhiteSpace($loadedFeaturesString)) {
|
|
$loadedFeaturesArray = $loadedFeaturesString.Split(';')
|
|
WriteLog "LoadConfig: Updating Optional Features checkboxes. Loaded features: $($loadedFeaturesArray -join ', ')"
|
|
foreach ($featureEntry in $State.Controls.featureCheckBoxes.GetEnumerator()) {
|
|
$featureName = $featureEntry.Key
|
|
$featureCheckbox = $featureEntry.Value
|
|
if ($loadedFeaturesArray -contains $featureName) {
|
|
$featureCheckbox.IsChecked = $true
|
|
WriteLog "LoadConfig: Checked checkbox for feature '$featureName'."
|
|
}
|
|
else {
|
|
$featureCheckbox.IsChecked = $false
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
# If no optional features are loaded, uncheck all
|
|
WriteLog "LoadConfig: No optional features string loaded. Unchecking all feature checkboxes."
|
|
foreach ($featureEntry in $State.Controls.featureCheckBoxes.GetEnumerator()) {
|
|
$featureEntry.Value.IsChecked = $false
|
|
}
|
|
}
|
|
|
|
# M365 Apps/Office tab
|
|
Set-UIValue -ControlName 'chkInstallOffice' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'InstallOffice' -State $State
|
|
Set-UIValue -ControlName 'txtOfficePath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'OfficePath' -State $State
|
|
Set-UIValue -ControlName 'chkCopyOfficeConfigXML' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyOfficeConfigXML' -State $State
|
|
Set-UIValue -ControlName 'txtOfficeConfigXMLFilePath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'OfficeConfigXMLFile' -State $State
|
|
|
|
# Drivers tab
|
|
Set-UIValue -ControlName 'chkInstallDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'InstallDrivers' -State $State
|
|
Set-UIValue -ControlName 'chkDownloadDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'DownloadDrivers' -State $State
|
|
Set-UIValue -ControlName 'chkCopyDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyDrivers' -State $State
|
|
# Set-UIValue -ControlName 'cmbMake' -PropertyName 'SelectedItem' -ConfigObject $ConfigContent -ConfigKey 'Make' -State $State
|
|
Set-UIValue -ControlName 'txtDriversFolder' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DriversFolder' -State $State
|
|
Set-UIValue -ControlName 'txtPEDriversFolder' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'PEDriversFolder' -State $State
|
|
Set-UIValue -ControlName 'txtDriversJsonPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'DriversJsonPath' -State $State
|
|
Set-UIValue -ControlName 'chkCopyPEDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CopyPEDrivers' -State $State
|
|
Set-UIValue -ControlName 'chkUseDriversAsPEDrivers' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UseDriversAsPEDrivers' -State $State
|
|
Set-UIValue -ControlName 'chkCompressDriversToWIM' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CompressDownloadedDriversToWim' -State $State
|
|
|
|
# Updates tab
|
|
Set-UIValue -ControlName 'chkUpdateLatestCU' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateLatestCU' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateLatestNet' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateLatestNet' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateLatestDefender' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateLatestDefender' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateEdge' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateEdge' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateOneDrive' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateOneDrive' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateLatestMSRT' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateLatestMSRT' -State $State
|
|
Set-UIValue -ControlName 'chkUpdateLatestMicrocode' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateLatestMicrocode' -State $State
|
|
Set-UIValue -ControlName 'chkUpdatePreviewCU' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdatePreviewCU' -State $State
|
|
|
|
# Applications tab
|
|
Set-UIValue -ControlName 'chkInstallApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'InstallApps' -State $State
|
|
Set-UIValue -ControlName 'chkInstallWingetApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'InstallWingetApps' -State $State
|
|
Set-UIValue -ControlName 'chkBringYourOwnApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'BringYourOwnApps' -State $State
|
|
Set-UIValue -ControlName 'txtApplicationPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppsPath' -State $State
|
|
Set-UIValue -ControlName 'txtAppListJsonPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppListPath' -State $State
|
|
Set-UIValue -ControlName 'txtUserAppListPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'UserAppListPath' -State $State
|
|
|
|
# Handle AppsScriptVariables
|
|
$appsScriptVarsKeyExists = $false
|
|
if ($ConfigContent -is [System.Management.Automation.PSCustomObject] -and $null -ne $ConfigContent.PSObject.Properties) {
|
|
try {
|
|
if (($ConfigContent.PSObject.Properties.Match('AppsScriptVariables')).Count -gt 0) {
|
|
$appsScriptVarsKeyExists = $true
|
|
}
|
|
}
|
|
catch { WriteLog "ERROR: Exception while trying to Match key 'AppsScriptVariables'. Error: $($_.Exception.Message)" }
|
|
}
|
|
|
|
$lstAppsScriptVars = $State.Controls.lstAppsScriptVariables
|
|
$chkDefineAppsScriptVars = $State.Controls.chkDefineAppsScriptVariables
|
|
$appsScriptVarsPanel = $State.Controls.appsScriptVariablesPanel
|
|
$State.Data.appsScriptVariablesDataList.Clear()
|
|
|
|
if ($appsScriptVarsKeyExists -and $null -ne $ConfigContent.AppsScriptVariables -and $ConfigContent.AppsScriptVariables -is [System.Management.Automation.PSCustomObject]) {
|
|
WriteLog "LoadConfig: Processing AppsScriptVariables from config."
|
|
$loadedVars = $ConfigContent.AppsScriptVariables
|
|
$hasVars = $false
|
|
foreach ($prop in $loadedVars.PSObject.Properties) {
|
|
$State.Data.appsScriptVariablesDataList.Add([PSCustomObject]@{ IsSelected = $false; Key = $prop.Name; Value = $prop.Value })
|
|
$hasVars = $true
|
|
}
|
|
if ($hasVars) {
|
|
$chkDefineAppsScriptVars.IsChecked = $true
|
|
$appsScriptVarsPanel.Visibility = 'Visible'
|
|
WriteLog "LoadConfig: Loaded AppsScriptVariables and checked 'Define Apps Script Variables'."
|
|
}
|
|
else {
|
|
$chkDefineAppsScriptVars.IsChecked = $false
|
|
$appsScriptVarsPanel.Visibility = 'Collapsed'
|
|
WriteLog "LoadConfig: AppsScriptVariables key was present but empty. Unchecked 'Define Apps Script Variables'."
|
|
}
|
|
}
|
|
elseif ($appsScriptVarsKeyExists -and $null -ne $ConfigContent.AppsScriptVariables -and $ConfigContent.AppsScriptVariables -is [hashtable]) {
|
|
# Handle if it's already a hashtable (e.g., from older config or direct creation)
|
|
WriteLog "LoadConfig: Processing AppsScriptVariables (Hashtable) from config."
|
|
$loadedVars = $ConfigContent.AppsScriptVariables
|
|
$hasVars = $false
|
|
foreach ($keyName in $loadedVars.Keys) {
|
|
$State.Data.appsScriptVariablesDataList.Add([PSCustomObject]@{ IsSelected = $false; Key = $keyName; Value = $loadedVars[$keyName] })
|
|
$hasVars = $true
|
|
}
|
|
if ($hasVars) {
|
|
$chkDefineAppsScriptVars.IsChecked = $true
|
|
$appsScriptVarsPanel.Visibility = 'Visible'
|
|
WriteLog "LoadConfig: Loaded AppsScriptVariables (Hashtable) and checked 'Define Apps Script Variables'."
|
|
}
|
|
else {
|
|
$chkDefineAppsScriptVars.IsChecked = $false
|
|
$appsScriptVarsPanel.Visibility = 'Collapsed'
|
|
WriteLog "LoadConfig: AppsScriptVariables (Hashtable) key was present but empty. Unchecked 'Define Apps Script Variables'."
|
|
}
|
|
}
|
|
else {
|
|
$chkDefineAppsScriptVars.IsChecked = $false
|
|
$appsScriptVarsPanel.Visibility = 'Collapsed'
|
|
WriteLog "LoadConfig Info: Key 'AppsScriptVariables' not found, is null, or not a PSCustomObject/Hashtable. Unchecked 'Define Apps Script Variables'."
|
|
}
|
|
# Update the ListView's ItemsSource after populating the data list
|
|
$lstAppsScriptVars.ItemsSource = $State.Data.appsScriptVariablesDataList.ToArray()
|
|
Request-ListViewColumnAutoResize -ListView $lstAppsScriptVars
|
|
# Update the header checkbox state
|
|
if ($null -ne $State.Controls.chkSelectAllAppsScriptVariables) {
|
|
Update-SelectAllHeaderCheckBoxState -ListView $lstAppsScriptVars -HeaderCheckBox $State.Controls.chkSelectAllAppsScriptVariables
|
|
}
|
|
|
|
# Update USB Drive selection if present in config
|
|
$usbDriveListKeyExists = $false
|
|
if ($ConfigContent -is [System.Management.Automation.PSCustomObject] -and $null -ne $ConfigContent.PSObject.Properties) {
|
|
try {
|
|
if (($ConfigContent.PSObject.Properties.Match('USBDriveList')).Count -gt 0) {
|
|
$usbDriveListKeyExists = $true
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "ERROR: Exception while trying to Match key 'USBDriveList' on ConfigContent.PSObject.Properties. Error: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
if ($usbDriveListKeyExists -and $null -ne $ConfigContent.USBDriveList) {
|
|
WriteLog "LoadConfig: Processing USBDriveList from config."
|
|
# First click the Check USB Drives button to populate the list
|
|
$State.Controls.btnCheckUSBDrives.RaiseEvent(
|
|
[System.Windows.RoutedEventArgs]::new(
|
|
[System.Windows.Controls.Button]::ClickEvent
|
|
)
|
|
)
|
|
|
|
# Then select the drives that match the saved configuration
|
|
foreach ($item in $State.Controls.lstUSBDrives.Items) {
|
|
$propertyName = $item.Model
|
|
$propertyExists = $false
|
|
$propertyValue = $null
|
|
|
|
# Ensure USBDriveList is a PSCustomObject before trying to access its properties dynamically
|
|
if ($null -ne $ConfigContent.USBDriveList -and $ConfigContent.USBDriveList -is [System.Management.Automation.PSCustomObject]) {
|
|
# Check if the property exists on the USBDriveList object
|
|
if ($ConfigContent.USBDriveList.PSObject.Properties.Match($propertyName).Count -gt 0) {
|
|
$propertyExists = $true
|
|
# Access the value dynamically
|
|
$propertyValue = $ConfigContent.USBDriveList.$($propertyName)
|
|
}
|
|
}
|
|
|
|
# Match USB drives by UniqueId instead of SerialNumber
|
|
# USBDriveList values can be a single UniqueId (string) or an array of UniqueIds (multiple same-model drives)
|
|
$isMatch = $false
|
|
if ($propertyExists) {
|
|
if ($propertyValue -is [string]) {
|
|
$isMatch = ($propertyValue -eq $item.UniqueId)
|
|
}
|
|
else {
|
|
$propertyValueArray = @($propertyValue)
|
|
$isMatch = ($propertyValueArray -contains $item.UniqueId)
|
|
}
|
|
}
|
|
|
|
if ($isMatch) {
|
|
WriteLog "LoadConfig: Selecting USB Drive Model '$($item.Model)' with UniqueId '$($item.UniqueId)'."
|
|
$item.IsSelected = $true
|
|
}
|
|
else {
|
|
if (-not $propertyExists -and ($null -ne $ConfigContent.USBDriveList)) {
|
|
WriteLog "LoadConfig: Property '$($propertyName)' not found on USBDriveList for item Model '$($item.Model)'."
|
|
}
|
|
$item.IsSelected = $false # Ensure others are deselected if not in config or value mismatch
|
|
}
|
|
}
|
|
$State.Controls.lstUSBDrives.Items.Refresh()
|
|
Request-ListViewColumnAutoResize -ListView $State.Controls.lstUSBDrives
|
|
|
|
# Update the Select All header checkbox state
|
|
$headerChk = $State.Controls.chkSelectAllUSBDrivesHeader
|
|
if ($null -ne $headerChk) {
|
|
Update-SelectAllHeaderCheckBoxState -ListView $State.Controls.lstUSBDrives -HeaderCheckBox $headerChk
|
|
}
|
|
WriteLog "LoadConfig: USBDriveList processing complete."
|
|
}
|
|
else {
|
|
WriteLog "LoadConfig Info: Key 'USBDriveList' not found or is null in configuration file. Skipping USB drive selection."
|
|
}
|
|
|
|
# If BuildUSBDrive is enabled and USBDriveList was present and not empty in the config,
|
|
# ensure "Select Specific USB Drives" is checked to show the list.
|
|
$shouldAutoCheckSpecificDrives = $false
|
|
if ($State.Controls.chkBuildUSBDriveEnable.IsChecked -and $usbDriveListKeyExists -and ($null -ne $ConfigContent.USBDriveList)) {
|
|
if ($ConfigContent.USBDriveList -is [System.Management.Automation.PSCustomObject]) {
|
|
if ($ConfigContent.USBDriveList.PSObject.Properties.Count -gt 0) {
|
|
$shouldAutoCheckSpecificDrives = $true
|
|
}
|
|
}
|
|
elseif ($ConfigContent.USBDriveList -is [hashtable]) {
|
|
# Fallback for older configs
|
|
if ($ConfigContent.USBDriveList.Keys.Count -gt 0) {
|
|
$shouldAutoCheckSpecificDrives = $true
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($shouldAutoCheckSpecificDrives) {
|
|
WriteLog "LoadConfig: Auto-checking 'Select Specific USB Drives' due to pre-selected USB drives in config."
|
|
$State.Controls.chkSelectSpecificUSBDrives.IsChecked = $true
|
|
}
|
|
else {
|
|
WriteLog "LoadConfig: Condition to auto-check 'Select Specific USB Drives' was NOT met."
|
|
}
|
|
# Populate additional FFU list and apply selections
|
|
try {
|
|
if ($State.Controls.chkCopyAdditionalFFUFiles.IsChecked) {
|
|
$State.Controls.additionalFFUPanel.Visibility = 'Visible'
|
|
if ($State.Controls.btnRefreshAdditionalFFUs) {
|
|
$State.Controls.btnRefreshAdditionalFFUs.RaiseEvent([System.Windows.RoutedEventArgs]::new([System.Windows.Controls.Button]::ClickEvent))
|
|
}
|
|
$selectedFiles = @()
|
|
$addFFUKeyExists = $false
|
|
if ($ConfigContent -is [System.Management.Automation.PSCustomObject] -and $null -ne $ConfigContent.PSObject.Properties) {
|
|
if (($ConfigContent.PSObject.Properties.Match('AdditionalFFUFiles')).Count -gt 0) {
|
|
$addFFUKeyExists = $true
|
|
}
|
|
}
|
|
if ($addFFUKeyExists -and $null -ne $ConfigContent.AdditionalFFUFiles) {
|
|
$selectedFiles = @($ConfigContent.AdditionalFFUFiles)
|
|
}
|
|
if ($selectedFiles.Count -gt 0) {
|
|
foreach ($item in $State.Controls.lstAdditionalFFUs.Items) {
|
|
if ($selectedFiles -contains $item.FullName) {
|
|
$item.IsSelected = $true
|
|
}
|
|
}
|
|
$State.Controls.lstAdditionalFFUs.Items.Refresh()
|
|
Request-ListViewColumnAutoResize -ListView $State.Controls.lstAdditionalFFUs
|
|
$headerChk = $State.Controls.chkSelectAllAdditionalFFUs
|
|
if ($null -ne $headerChk) {
|
|
Update-SelectAllHeaderCheckBoxState -ListView $State.Controls.lstAdditionalFFUs -HeaderCheckBox $headerChk
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
$State.Controls.additionalFFUPanel.Visibility = 'Collapsed'
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "LoadConfig: Error applying Additional FFU selections: $($_.Exception.Message)"
|
|
}
|
|
|
|
Update-BitsPrioritySetting -State $State
|
|
WriteLog "LoadConfig: Configuration loading process finished."
|
|
}
|
|
|
|
function Invoke-SaveConfiguration {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
try {
|
|
$config = Get-UIConfig -State $State
|
|
$defaultConfigPath = Join-Path $config.FFUDevelopmentPath "config"
|
|
if (-not (Test-Path $defaultConfigPath)) {
|
|
New-Item -Path $defaultConfigPath -ItemType Directory -Force | Out-Null
|
|
}
|
|
|
|
$savePath = Invoke-BrowseAction -Type 'SaveFile' `
|
|
-Title "Save Configuration File" `
|
|
-Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" `
|
|
-InitialDirectory $defaultConfigPath `
|
|
-FileName "FFUConfig.json" `
|
|
-DefaultExt ".json"
|
|
|
|
if ($savePath) {
|
|
# Sort top-level keys alphabetically for consistent output
|
|
$sortedConfig = [ordered]@{}
|
|
foreach ($k in ($config.Keys | Sort-Object)) { $sortedConfig[$k] = $config[$k] }
|
|
$sortedConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $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$($_.Exception.Message)", "Error", "OK", "Error")
|
|
}
|
|
}
|
|
|
|
function Invoke-RestoreDefaults {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
try {
|
|
$rootPath = $State.FFUDevelopmentPath
|
|
|
|
# Normalize potential array values to single strings
|
|
function Get-PathScalar {
|
|
param([object]$value)
|
|
if ($null -eq $value) { return $null }
|
|
if ($value -is [System.Array]) {
|
|
foreach ($v in $value) {
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$v)) {
|
|
return [string]$v
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
return [string]$value
|
|
}
|
|
|
|
$appsPath = Join-Path $rootPath 'Apps'
|
|
$driversRaw = Get-PathScalar -value $State.Controls.txtDriversFolder.Text
|
|
if ([string]::IsNullOrWhiteSpace($driversRaw)) {
|
|
$driversPath = Join-Path $rootPath 'Drivers'
|
|
}
|
|
else {
|
|
$driversPath = $driversRaw
|
|
}
|
|
$ffuCaptureRaw = Get-PathScalar -value $State.Controls.txtFFUCaptureLocation.Text
|
|
$ffuCapturePath = if ([string]::IsNullOrWhiteSpace($ffuCaptureRaw)) { Join-Path $rootPath 'FFU' } else { $ffuCaptureRaw }
|
|
|
|
$captureISOPath = Join-Path $rootPath 'WinPECaptureFFUFiles\WinPE-Capture.iso'
|
|
$deployISOPath = Join-Path $rootPath 'WinPEDeployFFUFiles\WinPE-Deploy.iso'
|
|
$appsISOPath = Join-Path $rootPath 'Apps.iso'
|
|
|
|
$msg = "Restore Defaults will:`n`n- Delete generated config and app/driver list JSON files`n- Remove ISO files (Capture, Deploy, Apps) if present`n- Remove Apps/Update/downloaded artifacts`n- Remove driver folder contents (not the folder)`n- Remove FFU files in the capture folder`n`nSample/template files and VM/VHDX cache are NOT removed.`n`nProceed?"
|
|
$result = [System.Windows.MessageBox]::Show($msg, "Confirm Restore Defaults", "YesNo", "Warning")
|
|
if ($result -ne [System.Windows.MessageBoxResult]::Yes) {
|
|
WriteLog "RestoreDefaults: User cancelled."
|
|
return
|
|
}
|
|
|
|
WriteLog "RestoreDefaults: Starting environment reset."
|
|
WriteLog "RestoreDefaults: Paths -> Apps=$appsPath Drivers=$driversPath FFUCapture=$ffuCapturePath"
|
|
|
|
# Remove JSON artifact files if present
|
|
$artifactFiles = @(
|
|
(Join-Path $rootPath 'config\FFUConfig.json'),
|
|
(Join-Path $appsPath 'AppList.json'),
|
|
(Join-Path $driversPath 'Drivers.json'),
|
|
(Join-Path $appsPath 'UserAppList.json')
|
|
) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
|
|
|
foreach ($file in $artifactFiles) {
|
|
if ((-not [string]::IsNullOrWhiteSpace($file)) -and (Test-Path -LiteralPath $file)) {
|
|
try {
|
|
WriteLog "RestoreDefaults: Removing $file"
|
|
Remove-Item -LiteralPath $file -Force -ErrorAction Stop
|
|
}
|
|
catch {
|
|
WriteLog "RestoreDefaults: Failed removing $file : $($_.Exception.Message)"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Force all cleanup flags true
|
|
Invoke-FFUPostBuildCleanup `
|
|
-RootPath $rootPath `
|
|
-AppsPath $appsPath `
|
|
-DriversPath $driversPath `
|
|
-FFUCapturePath $ffuCapturePath `
|
|
-CaptureISOPath $captureISOPath `
|
|
-DeployISOPath $deployISOPath `
|
|
-AppsISOPath $appsISOPath `
|
|
-KBPath (Join-Path $rootPath 'KB') `
|
|
-RemoveCaptureISO:$true `
|
|
-RemoveDeployISO:$true `
|
|
-RemoveAppsISO:$true `
|
|
-RemoveDrivers:$true `
|
|
-RemoveFFU:$true `
|
|
-RemoveApps:$true `
|
|
-RemoveUpdates:$true `
|
|
-RemoveDownloadedESD:$true
|
|
|
|
# Clear UI lists / state
|
|
if ($null -ne $State.Data.allDriverModels) { $State.Data.allDriverModels.Clear() }
|
|
if ($null -ne $State.Controls.lstDriverModels) { $State.Controls.lstDriverModels.Items.Refresh() }
|
|
if ($null -ne $State.Controls.lstApplications) {
|
|
try {
|
|
if ($State.Controls.lstApplications.ItemsSource) { $State.Controls.lstApplications.ItemsSource = $null }
|
|
$State.Controls.lstApplications.Items.Clear()
|
|
} catch {}
|
|
}
|
|
if ($null -ne $State.Controls.lstWingetResults) {
|
|
try {
|
|
if ($State.Controls.lstWingetResults.ItemsSource) { $State.Controls.lstWingetResults.ItemsSource = $null }
|
|
$State.Controls.lstWingetResults.Items.Clear()
|
|
} catch {}
|
|
}
|
|
if ($null -ne $State.Controls.lstAppsScriptVariables) {
|
|
try {
|
|
if ($State.Controls.lstAppsScriptVariables.ItemsSource) { $State.Controls.lstAppsScriptVariables.ItemsSource = $null }
|
|
$State.Controls.lstAppsScriptVariables.Items.Clear()
|
|
} catch {}
|
|
}
|
|
|
|
$State.Data.lastConfigFilePath = $null
|
|
|
|
Initialize-UIDefaults -State $State
|
|
|
|
WriteLog "RestoreDefaults: Completed."
|
|
[System.Windows.MessageBox]::Show("Environment restored to defaults.", "Restore Defaults", "OK", "Information")
|
|
}
|
|
catch {
|
|
WriteLog "RestoreDefaults: Failed with $($_.Exception.Message)"
|
|
[System.Windows.MessageBox]::Show("Restore Defaults failed:`n$($_.Exception.Message)", "Error", "OK", "Error")
|
|
}
|
|
}
|
|
|
|
function Invoke-AutoLoadPreviousEnvironment {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State
|
|
)
|
|
try {
|
|
$ffuDevRoot = $State.FFUDevelopmentPath
|
|
if ([string]::IsNullOrWhiteSpace($ffuDevRoot)) {
|
|
WriteLog "AutoLoad: FFUDevelopmentPath not set; skipping."
|
|
return
|
|
}
|
|
$configPath = Join-Path $ffuDevRoot "config\FFUConfig.json"
|
|
if (-not (Test-Path -LiteralPath $configPath)) {
|
|
WriteLog "AutoLoad: No existing FFUConfig.json found at $configPath."
|
|
return
|
|
}
|
|
WriteLog "AutoLoad: Found config file at $configPath. Parsing..."
|
|
$raw = Get-Content -Path $configPath -Raw -ErrorAction SilentlyContinue
|
|
if ([string]::IsNullOrWhiteSpace($raw)) {
|
|
WriteLog "AutoLoad: Config file empty; aborting."
|
|
return
|
|
}
|
|
$configContent = $null
|
|
try {
|
|
$configContent = $raw | ConvertFrom-Json -ErrorAction Stop
|
|
}
|
|
catch {
|
|
WriteLog "AutoLoad: JSON parse failed: $($_.Exception.Message)"
|
|
return
|
|
}
|
|
if ($null -eq $configContent) {
|
|
WriteLog "AutoLoad: Parsed object null; aborting."
|
|
return
|
|
}
|
|
WriteLog "AutoLoad: Applying core configuration."
|
|
Update-UIFromConfig -ConfigContent $configContent -State $State
|
|
$State.Data.lastConfigFilePath = $configPath
|
|
Import-ConfigSupplementalAssets -ConfigContent $configContent -State $State -ShowWarnings:$false
|
|
WriteLog "AutoLoad: Completed supplemental import with warnings disabled."
|
|
}
|
|
catch {
|
|
WriteLog "AutoLoad: Unexpected failure: $($_.Exception.ToString())"
|
|
}
|
|
}
|
|
|
|
function Import-ConfigSupplementalAssets {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$ConfigContent,
|
|
[Parameter(Mandatory = $true)]
|
|
[psobject]$State,
|
|
[Parameter()]
|
|
[bool]$ShowWarnings = $false
|
|
)
|
|
WriteLog "SupplementalImport: Starting import of helper assets."
|
|
$loadedWinget = $false
|
|
$loadedBYO = $false
|
|
$loadedDrivers = $false
|
|
$missing = New-Object System.Collections.Generic.List[string]
|
|
|
|
# Winget AppList
|
|
$appListPath = $null
|
|
if ($ConfigContent.PSObject.Properties.Match('AppListPath').Count -gt 0) {
|
|
$appListPath = $ConfigContent.AppListPath
|
|
}
|
|
if (-not [string]::IsNullOrWhiteSpace($appListPath)) {
|
|
if (Test-Path -LiteralPath $appListPath) {
|
|
WriteLog "SupplementalImport: Loading Winget AppList from $appListPath"
|
|
try {
|
|
$importedAppsData = Get-Content -Path $appListPath -Raw | ConvertFrom-Json -ErrorAction Stop
|
|
if ($null -ne $importedAppsData -and $null -ne $importedAppsData.apps) {
|
|
$defaultArch = $State.Controls.cmbWindowsArch.SelectedItem
|
|
$appsBuffer = [System.Collections.Generic.List[object]]::new()
|
|
foreach ($appInfo in $importedAppsData.apps) {
|
|
$arch = if ($appInfo.source -eq 'msstore') { 'NA' } else {
|
|
if ($appInfo.PSObject.Properties['architecture']) { $appInfo.architecture } else { $defaultArch }
|
|
}
|
|
$appsBuffer.Add([PSCustomObject]@{
|
|
IsSelected = $true
|
|
Name = $appInfo.name
|
|
Id = $appInfo.id
|
|
Version = ""
|
|
Source = $appInfo.source
|
|
Architecture = $arch
|
|
AdditionalExitCodes = if ($appInfo.PSObject.Properties['AdditionalExitCodes']) { $appInfo.AdditionalExitCodes } else { "" }
|
|
IgnoreNonZeroExitCodes = if ($appInfo.PSObject.Properties['IgnoreNonZeroExitCodes']) { [bool]$appInfo.IgnoreNonZeroExitCodes } else { $false }
|
|
DownloadStatus = ""
|
|
})
|
|
}
|
|
$State.Controls.lstWingetResults.ItemsSource = $appsBuffer.ToArray()
|
|
Request-ListViewColumnAutoResize -ListView $State.Controls.lstWingetResults
|
|
$loadedWinget = $true
|
|
if ($null -ne $State.Controls.wingetSearchPanel) {
|
|
$State.Controls.wingetSearchPanel.Visibility = 'Visible'
|
|
}
|
|
if ($null -ne $State.Controls.chkSelectAllWingetResults -and (Get-Command -Name Update-SelectAllHeaderCheckBoxState -ErrorAction SilentlyContinue)) {
|
|
Update-SelectAllHeaderCheckBoxState -ListView $State.Controls.lstWingetResults -HeaderCheckBox $State.Controls.chkSelectAllWingetResults
|
|
}
|
|
WriteLog "SupplementalImport: Winget list loaded with $($appsBuffer.Count) entries."
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: Winget AppList missing 'apps' array."
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "SupplementalImport: Failed loading Winget AppList ($appListPath): $($_.Exception.Message)"
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: Winget AppList file missing: $appListPath"
|
|
$missing.Add("Winget AppList (AppListPath): $appListPath")
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: AppListPath not defined in config."
|
|
}
|
|
|
|
# UserAppList (BYO)
|
|
$userAppListPath = $null
|
|
if ($ConfigContent.PSObject.Properties.Match('UserAppListPath').Count -gt 0) {
|
|
$userAppListPath = $ConfigContent.UserAppListPath
|
|
}
|
|
if (-not [string]::IsNullOrWhiteSpace($userAppListPath)) {
|
|
if (Test-Path -LiteralPath $userAppListPath) {
|
|
WriteLog "SupplementalImport: Loading UserAppList from $userAppListPath"
|
|
try {
|
|
$applications = Get-Content -Path $userAppListPath -Raw | ConvertFrom-Json -ErrorAction Stop
|
|
if ($applications) {
|
|
$listView = $State.Controls.lstApplications
|
|
$listView.Items.Clear()
|
|
$sortedApps = $applications | Sort-Object Priority
|
|
foreach ($app in $sortedApps) {
|
|
$ignoreNonZero = if ($app.PSObject.Properties['IgnoreNonZeroExitCodes']) { $app.IgnoreNonZeroExitCodes } else { $false }
|
|
$listView.Items.Add([PSCustomObject]@{
|
|
IsSelected = $false
|
|
Priority = $app.Priority
|
|
Name = $app.Name
|
|
CommandLine = $app.CommandLine
|
|
Arguments = if ($app.PSObject.Properties['Arguments']) { $app.Arguments } else { "" }
|
|
Source = $app.Source
|
|
AdditionalExitCodes = if ($app.PSObject.Properties['AdditionalExitCodes']) { $app.AdditionalExitCodes } else { "" }
|
|
IgnoreNonZeroExitCodes = $ignoreNonZero
|
|
IgnoreExitCodes = if ($ignoreNonZero) { "Yes" } else { "No" }
|
|
CopyStatus = ""
|
|
})
|
|
}
|
|
if (Get-Command -Name Update-ListViewPriorities -ErrorAction SilentlyContinue) {
|
|
Update-ListViewPriorities -ListView $listView
|
|
}
|
|
if (Get-Command -Name Update-CopyButtonState -ErrorAction SilentlyContinue) {
|
|
Update-CopyButtonState -State $State
|
|
}
|
|
if (Get-Command -Name Update-BYOAppsActionButtonsState -ErrorAction SilentlyContinue) {
|
|
Update-BYOAppsActionButtonsState -State $State
|
|
}
|
|
$loadedBYO = $true
|
|
WriteLog "SupplementalImport: UserAppList loaded with $($listView.Items.Count) entries."
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: UserAppList JSON empty."
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "SupplementalImport: Failed loading UserAppList ($userAppListPath): $($_.Exception.Message)"
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: UserAppList file missing: $userAppListPath"
|
|
$missing.Add("UserAppList (UserAppListPath): $userAppListPath")
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: UserAppListPath not defined in config."
|
|
}
|
|
|
|
# Drivers JSON
|
|
$driversJsonPath = $null
|
|
if ($ConfigContent.PSObject.Properties.Match('DriversJsonPath').Count -gt 0) {
|
|
$driversJsonPath = $ConfigContent.DriversJsonPath
|
|
}
|
|
if (-not [string]::IsNullOrWhiteSpace($driversJsonPath)) {
|
|
if (Test-Path -LiteralPath $driversJsonPath) {
|
|
WriteLog "SupplementalImport: Loading Drivers JSON from $driversJsonPath"
|
|
try {
|
|
$rawDrivers = Get-Content -Path $driversJsonPath -Raw | ConvertFrom-Json -ErrorAction Stop
|
|
if ($rawDrivers -and $rawDrivers.PSObject.Properties.Count -gt 0) {
|
|
$State.Data.allDriverModels.Clear()
|
|
foreach ($makeProp in $rawDrivers.PSObject.Properties) {
|
|
$makeName = $makeProp.Name
|
|
$makeObject = $makeProp.Value
|
|
if ($null -eq $makeObject -or -not ($makeObject.PSObject.Properties['Models'])) { continue }
|
|
$models = $makeObject.Models
|
|
if ($models -and ($models -is [System.Collections.IEnumerable])) {
|
|
foreach ($modelEntry in $models) {
|
|
if ($null -eq $modelEntry -or -not ($modelEntry.PSObject.Properties['Name'])) { continue }
|
|
$modelName = $modelEntry.Name
|
|
if ([string]::IsNullOrWhiteSpace($modelName)) { continue }
|
|
$downloadStatus = if ($modelEntry.PSObject.Properties['DownloadStatus']) { $modelEntry.DownloadStatus } else { "" }
|
|
$linkValue = if ($modelEntry.PSObject.Properties['Link']) { $modelEntry.Link } else { $null }
|
|
$productName = if ($modelEntry.PSObject.Properties['ProductName']) { $modelEntry.ProductName } else { $null }
|
|
$machineType = if ($modelEntry.PSObject.Properties['MachineType']) { $modelEntry.MachineType } else { $null }
|
|
$systemId = if ($modelEntry.PSObject.Properties['SystemId']) { $modelEntry.SystemId } else { $null }
|
|
$idValue = if ($modelEntry.PSObject.Properties['Id']) { $modelEntry.Id } else { $null }
|
|
if ($null -eq $idValue -and -not [string]::IsNullOrWhiteSpace($systemId)) { $idValue = $systemId }
|
|
if ($null -eq $idValue -and -not [string]::IsNullOrWhiteSpace($machineType)) { $idValue = $machineType }
|
|
$displayModel = Get-ConfigDriverDisplayName -Make $makeName -StoredName $modelName -ProductName $productName -SystemId $systemId -MachineType $machineType
|
|
if ([string]::IsNullOrWhiteSpace($displayModel)) {
|
|
$displayModel = $modelName
|
|
}
|
|
$driverObj = [PSCustomObject]@{
|
|
IsSelected = $true
|
|
Make = $makeName
|
|
Model = $displayModel
|
|
DownloadStatus = $downloadStatus
|
|
Link = $linkValue
|
|
ProductName = $productName
|
|
MachineType = $machineType
|
|
SystemId = $systemId
|
|
Id = $idValue
|
|
}
|
|
$State.Data.allDriverModels.Add($driverObj)
|
|
}
|
|
}
|
|
}
|
|
$State.Controls.lstDriverModels.ItemsSource = $State.Data.allDriverModels
|
|
Request-ListViewColumnAutoResize -ListView $State.Controls.lstDriverModels
|
|
if (Get-Command -Name Update-SelectAllHeaderCheckBoxState -ErrorAction SilentlyContinue) {
|
|
$headerChk = $State.Controls.chkSelectAllDriverModels
|
|
if ($null -ne $headerChk) {
|
|
Update-SelectAllHeaderCheckBoxState -ListView $State.Controls.lstDriverModels -HeaderCheckBox $headerChk
|
|
}
|
|
}
|
|
if ($State.Data.allDriverModels.Count -gt 0) {
|
|
if ($null -ne $State.Controls.spModelFilterSection) { $State.Controls.spModelFilterSection.Visibility = 'Visible' }
|
|
if ($null -ne $State.Controls.lstDriverModels) { $State.Controls.lstDriverModels.Visibility = 'Visible' }
|
|
if ($null -ne $State.Controls.spDriverActionButtons) { $State.Controls.spDriverActionButtons.Visibility = 'Visible' }
|
|
try {
|
|
if ($State.Controls.cmbMake.SelectedIndex -lt 0 -and $State.Data.allDriverModels.Count -gt 0) {
|
|
$firstMake = ($State.Data.allDriverModels | Select-Object -First 1).Make
|
|
if (-not [string]::IsNullOrWhiteSpace($firstMake)) {
|
|
$makeItem = $State.Controls.cmbMake.Items | Where-Object { $_ -eq $firstMake } | Select-Object -First 1
|
|
if ($makeItem) { $State.Controls.cmbMake.SelectedItem = $makeItem }
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "SupplementalImport: Non-fatal error selecting first Make: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
$loadedDrivers = $true
|
|
WriteLog "SupplementalImport: Loaded $($State.Data.allDriverModels.Count) driver models."
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: Drivers JSON empty or structure unexpected."
|
|
}
|
|
}
|
|
catch {
|
|
WriteLog "SupplementalImport: Failed loading Drivers JSON ($driversJsonPath): $($_.Exception.Message)"
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: Drivers JSON file missing: $driversJsonPath"
|
|
$missing.Add("Drivers (DriversJsonPath): $driversJsonPath")
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "SupplementalImport: DriversJsonPath not defined in config."
|
|
}
|
|
|
|
if ($loadedWinget -or $loadedBYO) {
|
|
$State.Controls.chkInstallApps.IsChecked = $true
|
|
}
|
|
if ($loadedWinget) {
|
|
$State.Controls.chkInstallWingetApps.IsChecked = $true
|
|
}
|
|
if ($loadedBYO) {
|
|
$State.Controls.chkBringYourOwnApps.IsChecked = $true
|
|
}
|
|
if ($loadedDrivers) {
|
|
$State.Controls.chkDownloadDrivers.IsChecked = $true
|
|
}
|
|
|
|
if (Get-Command -Name Update-ApplicationPanelVisibility -ErrorAction SilentlyContinue) {
|
|
Update-ApplicationPanelVisibility -State $State -TriggeringControlName 'SupplementalImport'
|
|
}
|
|
if (Get-Command -Name Update-DriverDownloadPanelVisibility -ErrorAction SilentlyContinue) {
|
|
Update-DriverDownloadPanelVisibility -State $State
|
|
}
|
|
if (Get-Command -Name Update-DriverCheckboxStates -ErrorAction SilentlyContinue) {
|
|
Update-DriverCheckboxStates -State $State
|
|
}
|
|
if (Get-Command -Name Update-OfficePanelVisibility -ErrorAction SilentlyContinue) {
|
|
Update-OfficePanelVisibility -State $State
|
|
}
|
|
if (Get-Command -Name Update-CopyButtonState -ErrorAction SilentlyContinue) {
|
|
Update-CopyButtonState -State $State
|
|
}
|
|
|
|
# Updated message to clarify successful load and that missing helper files are optional if not yet created.
|
|
if ($ShowWarnings -and $missing.Count -gt 0) {
|
|
$msg = "Configuration file loaded successfully.`n`n" +
|
|
"Optional helper file(s) referenced in the configuration were not found:`n" +
|
|
($missing | ForEach-Object { "- $_" } | Out-String) +
|
|
"`nThese files are optional. They won't exist until you create Winget (AppList.json), User (UserAppList.json), or Driver (Drivers.json) manifests. You can create them later or ignore this message."
|
|
[System.Windows.MessageBox]::Show($msg.TrimEnd(), "Configuration Loaded - Optional Files Missing", "OK", "Information") | Out-Null
|
|
}
|
|
|
|
WriteLog ("SupplementalImport: Complete. Winget={0} BYO={1} Drivers={2} Missing={3}" -f $loadedWinget, $loadedBYO, $loadedDrivers, $missing.Count)
|
|
}
|
|
|
|
Export-ModuleMember -Function * |