mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Add Winget search panel with results list and save/import functionality
This commit is contained in:
+357
-152
@@ -7,7 +7,6 @@ param()
|
|||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
$FFUDevelopmentPath = $PSScriptRoot
|
$FFUDevelopmentPath = $PSScriptRoot
|
||||||
$AppsPath = Join-Path $FFUDevelopmentPath "Apps"
|
$AppsPath = Join-Path $FFUDevelopmentPath "Apps"
|
||||||
$OfficePath = Join-Path $AppsPath "Office"
|
|
||||||
|
|
||||||
# Add the new function for USB drive detection
|
# Add the new function for USB drive detection
|
||||||
function Get-USBDrives {
|
function Get-USBDrives {
|
||||||
@@ -204,7 +203,6 @@ function Confirm-WinGetInstallation {
|
|||||||
|
|
||||||
# Some default values
|
# Some default values
|
||||||
$defaultISOPath = ""
|
$defaultISOPath = ""
|
||||||
$defaultWindowsRelease = 11 # numeric
|
|
||||||
$defaultWindowsArch = "x64"
|
$defaultWindowsArch = "x64"
|
||||||
$defaultWindowsLang = "en-us"
|
$defaultWindowsLang = "en-us"
|
||||||
$defaultWindowsSKU = "Pro"
|
$defaultWindowsSKU = "Pro"
|
||||||
@@ -279,156 +277,81 @@ $windowsVersionMap = @{
|
|||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Clean up the Get-UIConfig function to remove duplicates and fix USBDriveList
|
||||||
function Get-UIConfig {
|
function Get-UIConfig {
|
||||||
# --- Build Tab Values ---
|
# Create hash to store configuration
|
||||||
$ffuDevPath = $window.FindName('txtFFUDevPath').Text
|
|
||||||
$customFFUNameTemplate = $window.FindName('txtCustomFFUNameTemplate').Text
|
|
||||||
$ffuCaptureLocation = $window.FindName('txtFFUCaptureLocation').Text
|
|
||||||
$shareName = $window.FindName('txtShareName').Text
|
|
||||||
$username = $window.FindName('txtUsername').Text
|
|
||||||
|
|
||||||
# General Build Options (Build tab WrapPanel)
|
|
||||||
$buildUSB = $window.FindName('chkBuildUSBDriveEnable').IsChecked
|
|
||||||
$compactOS = $window.FindName('chkCompactOS').IsChecked
|
|
||||||
$optimize = $window.FindName('chkOptimize').IsChecked
|
|
||||||
$allowVHDXCaching = $window.FindName('chkAllowVHDXCaching').IsChecked
|
|
||||||
$createCapture = $window.FindName('chkCreateCaptureMedia').IsChecked
|
|
||||||
$createDeployMedia = $window.FindName('chkCreateDeploymentMedia').IsChecked
|
|
||||||
|
|
||||||
# Build USB Drive Section (new)
|
|
||||||
$promptExt = $window.FindName('chkPromptExternalHardDiskMedia').IsChecked
|
|
||||||
$allowExt = $window.FindName('chkAllowExternalHardDiskMedia').IsChecked
|
|
||||||
|
|
||||||
# USB Drive Modification group (Build tab right column in new section)
|
|
||||||
$copyAutopilot = $window.FindName('chkCopyAutopilot').IsChecked
|
|
||||||
$copyUnattend = $window.FindName('chkCopyUnattend').IsChecked
|
|
||||||
$copyPPKG = $window.FindName('chkCopyPPKG').IsChecked
|
|
||||||
|
|
||||||
# --- Hyper-V Settings (from Hyper-V tab) ---
|
|
||||||
$cmbVMSwitch = $window.FindName('cmbVMSwitchName')
|
|
||||||
$vmSwitchName = $cmbVMSwitch.SelectedItem
|
|
||||||
if ($vmSwitchName -eq 'Other') { $vmSwitchName = $window.FindName('txtCustomVMSwitchName').Text }
|
|
||||||
$vmHostIPAddress = $window.FindName('txtVMHostIPAddress').Text
|
|
||||||
[int64]$diskSizeInGB = [int64]$window.FindName('txtDiskSize').Text
|
|
||||||
$diskSize = $diskSizeInGB * 1GB
|
|
||||||
[int64]$memoryInGB = [int64]$window.FindName('txtMemory').Text
|
|
||||||
$memory = $memoryInGB * 1GB
|
|
||||||
[int]$processors = [int]$window.FindName('txtProcessors').Text
|
|
||||||
$vmLocation = $window.FindName('txtVMLocation').Text
|
|
||||||
$logicalSectorObj = $window.FindName('cmbLogicalSectorSize').SelectedItem
|
|
||||||
$logicalSectorSize = [int]$logicalSectorObj.Content
|
|
||||||
|
|
||||||
# <-- NEW: retrieve FFUPrefix from the new textbox (VM Name Prefix)
|
|
||||||
$ffuPrefix = $window.FindName('txtVMNamePrefix').Text
|
|
||||||
|
|
||||||
# --- Windows Settings 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
|
|
||||||
$productKey = $window.FindName('txtProductKey').Text
|
|
||||||
$isoPath = $window.FindName('txtISOPath').Text
|
|
||||||
|
|
||||||
# --- M365 Apps/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
|
|
||||||
|
|
||||||
# --- Updates tab ---
|
|
||||||
$updateLatestCU = $window.FindName('chkUpdateLatestCU').IsChecked
|
|
||||||
$updateLatestNet = $window.FindName('chkUpdateLatestNet').IsChecked
|
|
||||||
$updateLatestDefender = $window.FindName('chkUpdateLatestDefender').IsChecked
|
|
||||||
$updateEdge = $window.FindName('chkUpdateEdge').IsChecked
|
|
||||||
$updateOneDrive = $window.FindName('chkUpdateOneDrive').IsChecked
|
|
||||||
$updateLatestMSRT = $window.FindName('chkUpdateLatestMSRT').IsChecked
|
|
||||||
$updatePreviewCU = $window.FindName('chkUpdatePreviewCU').IsChecked
|
|
||||||
|
|
||||||
# --- Applications tab ---
|
|
||||||
$installApps = $window.FindName('chkInstallApps').IsChecked
|
|
||||||
$installWingetApps = $window.FindName('chkInstallWingetApps').IsChecked
|
|
||||||
|
|
||||||
# Add USB drive selection to config
|
|
||||||
$selectedUSBDrives = @{}
|
|
||||||
$window.FindName('lstUSBDrives').Items | Where-Object { $_.IsSelected } | ForEach-Object {
|
|
||||||
$selectedUSBDrives[$_.Model] = $_.SerialNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
# Build configuration hashtable (unsorted)
|
|
||||||
$config = [ordered]@{
|
$config = [ordered]@{
|
||||||
AllowExternalHardDiskMedia = $allowExt
|
AllowExternalHardDiskMedia = $window.FindName('chkAllowExternalHardDiskMedia').IsChecked
|
||||||
AllowVHDXCaching = $allowVHDXCaching
|
AllowVHDXCaching = $window.FindName('chkAllowVHDXCaching').IsChecked
|
||||||
BuildUSBDrive = $buildUSB
|
BuildUSBDrive = $window.FindName('chkBuildUSBDriveEnable').IsChecked
|
||||||
CompactOS = $compactOS
|
CleanupAppsISO = $window.FindName('chkCleanupAppsISO').IsChecked
|
||||||
CopyAutopilot = $copyAutopilot
|
CleanupCaptureISO = $window.FindName('chkCleanupCaptureISO').IsChecked
|
||||||
CopyOfficeConfigXML = $copyOfficeConfig
|
CleanupDeployISO = $window.FindName('chkCleanupDeployISO').IsChecked
|
||||||
CopyPEDrivers = $copyPEDrivers
|
CleanupDrivers = $window.FindName('chkCleanupDrivers').IsChecked
|
||||||
CopyPPKG = $copyPPKG
|
CompactOS = $window.FindName('chkCompactOS').IsChecked
|
||||||
CopyUnattend = $copyUnattend
|
CopyAutopilot = $window.FindName('chkCopyAutopilot').IsChecked
|
||||||
CreateCaptureMedia = $createCapture
|
CopyDrivers = $window.FindName('chkCopyDrivers').IsChecked
|
||||||
CreateDeploymentMedia = $createDeployMedia
|
CopyOfficeConfigXML = $window.FindName('chkCopyOfficeConfigXML').IsChecked
|
||||||
CleanupAppsISO = $window.FindName('chkCleanupAppsISO').IsChecked
|
CopyPEDrivers = $window.FindName('chkCopyPEDrivers').IsChecked
|
||||||
CleanupCaptureISO = $window.FindName('chkCleanupCaptureISO').IsChecked
|
CopyPPKG = $window.FindName('chkCopyPPKG').IsChecked
|
||||||
CleanupDeployISO = $window.FindName('chkCleanupDeployISO').IsChecked
|
CopyUnattend = $window.FindName('chkCopyUnattend').IsChecked
|
||||||
CleanupDrivers = $window.FindName('chkCleanupDrivers').IsChecked
|
CreateCaptureMedia = $window.FindName('chkCreateCaptureMedia').IsChecked
|
||||||
Disksize = $diskSize
|
CreateDeploymentMedia = $window.FindName('chkCreateDeploymentMedia').IsChecked
|
||||||
DownloadDrivers = $downloadDrivers
|
CustomFFUNameTemplate = $window.FindName('txtCustomFFUNameTemplate').Text
|
||||||
PromptExternalHardDiskMedia = $promptExt
|
DiskSize = [int64]$window.FindName('txtDiskSize').Text * 1GB
|
||||||
FFUCaptureLocation = $ffuCaptureLocation
|
DownloadDrivers = $window.FindName('chkDownloadDrivers').IsChecked
|
||||||
FFUDevelopmentPath = $ffuDevPath
|
DriversFolder = $window.FindName('txtDriversFolder').Text
|
||||||
ISOPath = $isoPath # <-- NEW: Add Windows ISO Path to config
|
FFUCaptureLocation = $window.FindName('txtFFUCaptureLocation').Text
|
||||||
MediaType = $mediaType
|
FFUDevelopmentPath = $window.FindName('txtFFUDevPath').Text
|
||||||
Make = $make
|
FFUPrefix = $window.FindName('txtVMNamePrefix').Text
|
||||||
Model = $model
|
InstallApps = $window.FindName('chkInstallApps').IsChecked
|
||||||
OfficeConfigXMLFile = $officeConfigXMLFile
|
InstallDrivers = $window.FindName('chkInstallDrivers').IsChecked
|
||||||
OfficePath = $officePath
|
InstallOffice = $window.FindName('chkInstallOffice').IsChecked
|
||||||
OptionalFeatures = $window.FindName('txtOptionalFeatures').Text
|
InstallWingetApps = $window.FindName('chkInstallWingetApps').IsChecked
|
||||||
PEDriversFolder = $peDriversFolder
|
ISOPath = $window.FindName('txtISOPath').Text
|
||||||
ProductKey = $productKey
|
LogicalSectorSizeBytes = [int]$window.FindName('cmbLogicalSectorSize').SelectedItem.Content
|
||||||
Processors = $processors
|
Make = $window.FindName('cmbMake').SelectedItem
|
||||||
RemoveFFU = $window.FindName('chkRemoveFFU').IsChecked
|
MediaType = $window.FindName('cmbMediaType').SelectedItem
|
||||||
UpdateEdge = $updateEdge
|
Memory = [int64]$window.FindName('txtMemory').Text * 1GB
|
||||||
UpdateLatestCU = $updateLatestCU
|
Model = $window.FindName('cmbModel').Text
|
||||||
UpdateLatestDefender = $updateLatestDefender
|
OfficeConfigXMLFile = $window.FindName('txtOfficeConfigXMLFilePath').Text
|
||||||
UpdateLatestMSRT = $updateLatestMSRT
|
OfficePath = $window.FindName('txtOfficePath').Text
|
||||||
UpdateLatestNet = $updateLatestNet
|
Optimize = $window.FindName('chkOptimize').IsChecked
|
||||||
UpdateOneDrive = $updateOneDrive
|
PEDriversFolder = $window.FindName('txtPEDriversFolder').Text
|
||||||
UpdatePreviewCU = $updatePreviewCU
|
ProductKey = $window.FindName('txtProductKey').Text
|
||||||
VMHostIPAddress = $vmHostIPAddress
|
PromptExternalHardDiskMedia = $window.FindName('chkPromptExternalHardDiskMedia').IsChecked
|
||||||
VMLocation = $vmLocation
|
Processors = [int]$window.FindName('txtProcessors').Text
|
||||||
VMSwitchName = $vmSwitchName
|
RemoveFFU = $window.FindName('chkRemoveFFU').IsChecked
|
||||||
LogicalSectorSizeBytes = $logicalSectorSize
|
ShareName = $window.FindName('txtShareName').Text
|
||||||
Memory = $memory
|
UpdateEdge = $window.FindName('chkUpdateEdge').IsChecked
|
||||||
WindowsArch = $windowsArch
|
UpdateLatestCU = $window.FindName('chkUpdateLatestCU').IsChecked
|
||||||
WindowsLang = $windowsLang
|
UpdateLatestDefender = $window.FindName('chkUpdateLatestDefender').IsChecked
|
||||||
WindowsRelease = $windowsRelease
|
UpdateLatestMSRT = $window.FindName('chkUpdateLatestMSRT').IsChecked
|
||||||
WindowsSKU = $windowsSKU
|
UpdateLatestNet = $window.FindName('chkUpdateLatestNet').IsChecked
|
||||||
WindowsVersion = $windowsVersion
|
UpdateOneDrive = $window.FindName('chkUpdateOneDrive').IsChecked
|
||||||
FFUPrefix = $ffuPrefix # <-- new option for VM Name Prefix
|
UpdatePreviewCU = $window.FindName('chkUpdatePreviewCU').IsChecked
|
||||||
USBDriveList = $selectedUSBDrives # Add USB drive selection
|
USBDriveList = @{}
|
||||||
InstallApps = $installApps
|
Username = $window.FindName('txtUsername').Text
|
||||||
InstallWingetApps = $installWingetApps
|
VMHostIPAddress = $window.FindName('txtVMHostIPAddress').Text
|
||||||
|
VMLocation = $window.FindName('txtVMLocation').Text
|
||||||
|
VMSwitchName = if ($window.FindName('cmbVMSwitchName').SelectedItem -eq 'Other') {
|
||||||
|
$window.FindName('txtCustomVMSwitchName').Text
|
||||||
|
} else {
|
||||||
|
$window.FindName('cmbVMSwitchName').SelectedItem
|
||||||
|
}
|
||||||
|
WindowsArch = $window.FindName('cmbWindowsArch').SelectedItem
|
||||||
|
WindowsLang = $window.FindName('cmbWindowsLang').SelectedItem
|
||||||
|
WindowsRelease = [int]$window.FindName('cmbWindowsRelease').SelectedItem.Value
|
||||||
|
WindowsSKU = $window.FindName('cmbWindowsSKU').SelectedItem
|
||||||
|
WindowsVersion = $window.FindName('cmbWindowsVersion').SelectedItem
|
||||||
}
|
}
|
||||||
|
|
||||||
# Sort the configuration hashtable alphabetically by key
|
# Add selected USB drives to the config
|
||||||
$sortedConfig = [ordered]@{}
|
$window.FindName('lstUSBDrives').Items | Where-Object { $_.IsSelected } | ForEach-Object {
|
||||||
foreach ($key in ($config.Keys | Sort-Object)) {
|
$config.USBDriveList[$_.Model] = $_.SerialNumber
|
||||||
$sortedConfig[$key] = $config[$key]
|
|
||||||
}
|
}
|
||||||
return $sortedConfig
|
|
||||||
|
return $config
|
||||||
}
|
}
|
||||||
|
|
||||||
function UpdateWindowsReleaseList {
|
function UpdateWindowsReleaseList {
|
||||||
@@ -599,6 +522,84 @@ $script:versionData | Add-Member -MemberType ScriptMethod -Name NotifyPropertyCh
|
|||||||
$script:versionData | Add-Member -MemberType NoteProperty -Name PropertyChanged -Value $null
|
$script:versionData | Add-Member -MemberType NoteProperty -Name PropertyChanged -Value $null
|
||||||
$script:versionData | Add-Member -TypeName "System.ComponentModel.INotifyPropertyChanged"
|
$script:versionData | Add-Member -TypeName "System.ComponentModel.INotifyPropertyChanged"
|
||||||
|
|
||||||
|
# Add a function to create a sortable list view for Winget search results
|
||||||
|
function Add-SortableColumn {
|
||||||
|
param(
|
||||||
|
[System.Windows.Controls.GridView]$gridView,
|
||||||
|
[string]$header,
|
||||||
|
[string]$binding,
|
||||||
|
[int]$width = 'Auto',
|
||||||
|
[bool]$isCheckbox = $false
|
||||||
|
)
|
||||||
|
|
||||||
|
$column = New-Object System.Windows.Controls.GridViewColumn
|
||||||
|
if ($isCheckbox) {
|
||||||
|
$template = New-Object System.Windows.FrameworkElementFactory([System.Windows.Controls.CheckBox])
|
||||||
|
$template.SetBinding([System.Windows.Controls.CheckBox]::IsCheckedProperty, (New-Object System.Windows.Data.Binding("IsSelected")))
|
||||||
|
$column.CellTemplate = New-Object System.Windows.DataTemplate
|
||||||
|
$column.CellTemplate.VisualTree = $template
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$column.DisplayMemberBinding = New-Object System.Windows.Data.Binding($binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the header with sorting support
|
||||||
|
$columnHeader = New-Object System.Windows.Controls.GridViewColumnHeader
|
||||||
|
$columnHeader.Content = $header
|
||||||
|
$columnHeader.Tag = $binding
|
||||||
|
$column.Header = $columnHeader
|
||||||
|
|
||||||
|
if ($width -ne 'Auto') {
|
||||||
|
$column.Width = $width
|
||||||
|
}
|
||||||
|
|
||||||
|
$gridView.Columns.Add($column)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize tracking variables for sorting
|
||||||
|
$script:lastSortProperty = $null
|
||||||
|
$script:lastSortAscending = $true
|
||||||
|
|
||||||
|
# Function to sort ListView items
|
||||||
|
function Invoke-ListViewSort {
|
||||||
|
param(
|
||||||
|
[System.Windows.Controls.ListView]$listView,
|
||||||
|
[string]$property
|
||||||
|
)
|
||||||
|
|
||||||
|
# Toggle sort direction if clicking the same column
|
||||||
|
if ($script:lastSortProperty -eq $property) {
|
||||||
|
$script:lastSortAscending = -not $script:lastSortAscending
|
||||||
|
} else {
|
||||||
|
$script:lastSortAscending = $true
|
||||||
|
}
|
||||||
|
$script:lastSortProperty = $property
|
||||||
|
|
||||||
|
# Convert ListView items to array and split into selected and unselected
|
||||||
|
$items = @($listView.Items)
|
||||||
|
$selectedItems = @($items | Where-Object { $_.IsSelected })
|
||||||
|
$unselectedItems = @($items | Where-Object { -not $_.IsSelected })
|
||||||
|
|
||||||
|
# Sort unselected items
|
||||||
|
$sortedUnselected = if ($script:lastSortAscending) {
|
||||||
|
@($unselectedItems | Sort-Object -Property $property)
|
||||||
|
} else {
|
||||||
|
@($unselectedUnselected | Sort-Object -Property $property -Descending)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clear and repopulate ListView
|
||||||
|
$listView.Items.Clear()
|
||||||
|
|
||||||
|
# Add items back in correct order (selected first, then sorted unselected)
|
||||||
|
foreach ($item in $selectedItems) {
|
||||||
|
$listView.Items.Add($item)
|
||||||
|
}
|
||||||
|
foreach ($item in $sortedUnselected) {
|
||||||
|
$listView.Items.Add($item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fix event handler parameter names to avoid $eventArgs conflicts
|
||||||
$window.Add_Loaded({
|
$window.Add_Loaded({
|
||||||
$script:cmbWindowsRelease = $window.FindName('cmbWindowsRelease')
|
$script:cmbWindowsRelease = $window.FindName('cmbWindowsRelease')
|
||||||
$script:cmbWindowsVersion = $window.FindName('cmbWindowsVersion')
|
$script:cmbWindowsVersion = $window.FindName('cmbWindowsVersion')
|
||||||
@@ -843,8 +844,8 @@ $window.Add_Loaded({
|
|||||||
|
|
||||||
# Add keyboard handler
|
# Add keyboard handler
|
||||||
$script:lstUSBDrives.Add_KeyDown({
|
$script:lstUSBDrives.Add_KeyDown({
|
||||||
param($sender, $e)
|
param($eventSrc, $keyEvent)
|
||||||
if ($e.Key -eq 'Space') {
|
if ($keyEvent.Key -eq 'Space') {
|
||||||
$selectedItem = $script:lstUSBDrives.SelectedItem
|
$selectedItem = $script:lstUSBDrives.SelectedItem
|
||||||
if ($selectedItem) {
|
if ($selectedItem) {
|
||||||
$selectedItem.IsSelected = !$selectedItem.IsSelected
|
$selectedItem.IsSelected = !$selectedItem.IsSelected
|
||||||
@@ -858,7 +859,7 @@ $window.Add_Loaded({
|
|||||||
|
|
||||||
# Add selection change handler
|
# Add selection change handler
|
||||||
$script:lstUSBDrives.Add_SelectionChanged({
|
$script:lstUSBDrives.Add_SelectionChanged({
|
||||||
param($sender, $e)
|
param($eventSrc, $selChangeEvent)
|
||||||
# Update Select All checkbox state
|
# Update Select All checkbox state
|
||||||
$allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected })
|
$allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected })
|
||||||
$script:chkSelectAllUSBDrives.IsChecked = $allSelected
|
$script:chkSelectAllUSBDrives.IsChecked = $allSelected
|
||||||
@@ -936,8 +937,14 @@ $window.Add_Loaded({
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Show/Hide Winget panel based on checkbox state
|
# Show/Hide Winget panel based on checkbox state
|
||||||
$script:chkInstallWingetApps.Add_Checked({ $script:wingetPanel.Visibility = 'Visible' })
|
$script:chkInstallWingetApps.Add_Checked({
|
||||||
$script:chkInstallWingetApps.Add_Unchecked({ $script:wingetPanel.Visibility = 'Collapsed' })
|
$script:wingetPanel.Visibility = 'Visible'
|
||||||
|
# Don't show search panel here - it should only show after validation
|
||||||
|
})
|
||||||
|
$script:chkInstallWingetApps.Add_Unchecked({
|
||||||
|
$script:wingetPanel.Visibility = 'Collapsed'
|
||||||
|
$script:wingetSearchPanel.Visibility = 'Collapsed'
|
||||||
|
})
|
||||||
|
|
||||||
# Handle Winget component check/installation
|
# Handle Winget component check/installation
|
||||||
$script:btnCheckWingetModule.Add_Click({
|
$script:btnCheckWingetModule.Add_Click({
|
||||||
@@ -958,6 +965,13 @@ $window.Add_Loaded({
|
|||||||
|
|
||||||
# Update UI with final status
|
# Update UI with final status
|
||||||
Update-WingetVersionFields -wingetText $cliStatus.Status -moduleText $module.Version
|
Update-WingetVersionFields -wingetText $cliStatus.Status -moduleText $module.Version
|
||||||
|
|
||||||
|
# Show search panel only if versions are valid and checkbox is still checked
|
||||||
|
if ($cliStatus.Status -match '^\d+\.\d+\.\d+$' -and
|
||||||
|
$module.Version -match '^\d+\.\d+\.\d+$' -and
|
||||||
|
$script:chkInstallWingetApps.IsChecked) {
|
||||||
|
$script:wingetSearchPanel.Visibility = 'Visible'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Update-WingetVersionFields -wingetText "Error" -moduleText "Error"
|
Update-WingetVersionFields -wingetText "Error" -moduleText "Error"
|
||||||
@@ -974,8 +988,199 @@ $window.Add_Loaded({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Create Winget Search section (initially hidden)
|
||||||
|
$script:wingetSearchPanel = $window.FindName('wingetSearchPanel')
|
||||||
|
$script:txtWingetSearch = $window.FindName('txtWingetSearch')
|
||||||
|
$script:btnWingetSearch = $window.FindName('btnWingetSearch')
|
||||||
|
$script:lstWingetResults = $window.FindName('lstWingetResults')
|
||||||
|
$script:btnSaveWingetList = $window.FindName('btnSaveWingetList')
|
||||||
|
$script:btnImportWingetList = $window.FindName('btnImportWingetList')
|
||||||
|
|
||||||
|
# Initialize ListView with GridView columns
|
||||||
|
$gridView = New-Object System.Windows.Controls.GridView
|
||||||
|
Add-SortableColumn -gridView $gridView -header "Selected" -binding "IsSelected" -width 60 -isCheckbox $true
|
||||||
|
Add-SortableColumn -gridView $gridView -header "Name" -binding "Name" -width 200
|
||||||
|
Add-SortableColumn -gridView $gridView -header "Id" -binding "Id" -width 200
|
||||||
|
Add-SortableColumn -gridView $gridView -header "Version" -binding "Version" -width 100
|
||||||
|
Add-SortableColumn -gridView $gridView -header "Source" -binding "Source" -width 100
|
||||||
|
$script:lstWingetResults.View = $gridView
|
||||||
|
|
||||||
|
# Hide search panel initially
|
||||||
|
$script:wingetSearchPanel.Visibility = 'Collapsed'
|
||||||
|
|
||||||
|
# Add search functionality
|
||||||
|
$script:btnWingetSearch.Add_Click({
|
||||||
|
Search-WingetApps
|
||||||
|
})
|
||||||
|
|
||||||
|
$script:txtWingetSearch.Add_KeyDown({
|
||||||
|
param($eventSrc, $keyEvent)
|
||||||
|
if ($keyEvent.Key -eq 'Return') {
|
||||||
|
Search-WingetApps
|
||||||
|
$keyEvent.Handled = $true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# Save and Import buttons
|
||||||
|
$script:btnSaveWingetList.Add_Click({
|
||||||
|
Save-WingetList
|
||||||
|
})
|
||||||
|
|
||||||
|
$script:btnImportWingetList.Add_Click({
|
||||||
|
Import-WingetList
|
||||||
|
})
|
||||||
|
|
||||||
|
# Show search panel after successful Winget validation
|
||||||
|
$script:btnCheckWingetModule.Add_Click({
|
||||||
|
# ...existing code...
|
||||||
|
try {
|
||||||
|
# Check Winget CLI first
|
||||||
|
$cliStatus = Test-WingetCLI
|
||||||
|
|
||||||
|
# Install/Update PowerShell module if needed
|
||||||
|
$module = Install-WingetComponents -currentWingetVersion $cliStatus.Status
|
||||||
|
|
||||||
|
# Update UI with final status
|
||||||
|
Update-WingetVersionFields -wingetText $cliStatus.Status -moduleText $module.Version
|
||||||
|
|
||||||
|
# Show search panel if versions are valid
|
||||||
|
if ($cliStatus.Status -match '^\d+\.\d+\.\d+$' -and $module.Version -match '^\d+\.\d+\.\d+$') {
|
||||||
|
$script:wingetSearchPanel.Visibility = 'Visible'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
# ...existing error handling code...
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$script:lstWingetResults.Add_PreviewMouseLeftButtonUp({
|
||||||
|
param($eventSrc, $mouseEventArgs)
|
||||||
|
$originalSource = $mouseEventArgs.OriginalSource
|
||||||
|
$header = [System.Windows.Media.VisualTreeHelper]::GetParent($originalSource)
|
||||||
|
while ($header -ne $null -and $header -isnot [System.Windows.Controls.GridViewColumnHeader]) {
|
||||||
|
$header = [System.Windows.Media.VisualTreeHelper]::GetParent($header)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($header -is [System.Windows.Controls.GridViewColumnHeader]) {
|
||||||
|
$headerContent = $header.Column.Header
|
||||||
|
if ($headerContent -is [System.Windows.Controls.GridViewColumnHeader]) {
|
||||||
|
if ($headerContent.Tag) {
|
||||||
|
Invoke-ListViewSort -listView $script:lstWingetResults -property $headerContent.Tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Function to search for Winget apps
|
||||||
|
function Search-WingetApps {
|
||||||
|
try {
|
||||||
|
$searchQuery = $script:txtWingetSearch.Text
|
||||||
|
if ([string]::IsNullOrWhiteSpace($searchQuery)) { return }
|
||||||
|
|
||||||
|
# Store selected apps
|
||||||
|
$selectedApps = $script:lstWingetResults.Items | Where-Object { $_.IsSelected }
|
||||||
|
|
||||||
|
# Search for new apps
|
||||||
|
$results = Find-WingetPackage -Query $searchQuery | ForEach-Object {
|
||||||
|
[PSCustomObject]@{
|
||||||
|
IsSelected = $false
|
||||||
|
Name = $_.Name
|
||||||
|
Id = $_.Id
|
||||||
|
Version = $_.Version
|
||||||
|
Source = $_.Source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clear and repopulate list view
|
||||||
|
$script:lstWingetResults.Items.Clear()
|
||||||
|
|
||||||
|
# Add back selected apps first
|
||||||
|
foreach ($app in $selectedApps) {
|
||||||
|
$script:lstWingetResults.Items.Add($app)
|
||||||
|
# Remove from new results if already selected
|
||||||
|
$results = $results | Where-Object { $_.Id -ne $app.Id }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add new search results
|
||||||
|
foreach ($result in $results) {
|
||||||
|
$script:lstWingetResults.Items.Add($result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
[System.Windows.MessageBox]::Show("Error searching for apps: $_", "Error", "OK", "Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to save selected apps to JSON
|
||||||
|
function Save-WingetList {
|
||||||
|
try {
|
||||||
|
$selectedApps = $script:lstWingetResults.Items | Where-Object { $_.IsSelected }
|
||||||
|
if (-not $selectedApps) {
|
||||||
|
[System.Windows.MessageBox]::Show("No apps selected to save.", "Warning", "OK", "Warning")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$appList = @{
|
||||||
|
apps = @($selectedApps | ForEach-Object {
|
||||||
|
[ordered]@{
|
||||||
|
name = $_.Name
|
||||||
|
id = $_.Id
|
||||||
|
source = $_.Source.ToLower()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$sfd = New-Object System.Windows.Forms.SaveFileDialog
|
||||||
|
$sfd.Filter = "JSON files (*.json)|*.json"
|
||||||
|
$sfd.Title = "Save App List"
|
||||||
|
$sfd.InitialDirectory = $AppsPath
|
||||||
|
$sfd.FileName = "AppList.json"
|
||||||
|
|
||||||
|
if ($sfd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||||
|
$appList | ConvertTo-Json -Depth 10 | Set-Content $sfd.FileName -Encoding UTF8
|
||||||
|
[System.Windows.MessageBox]::Show("App list saved successfully.", "Success", "OK", "Information")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
[System.Windows.MessageBox]::Show("Error saving app list: $_", "Error", "OK", "Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to import app list from JSON
|
||||||
|
function Import-WingetList {
|
||||||
|
try {
|
||||||
|
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
||||||
|
$ofd.Filter = "JSON files (*.json)|*.json"
|
||||||
|
$ofd.Title = "Import App List"
|
||||||
|
$ofd.InitialDirectory = $AppsPath
|
||||||
|
|
||||||
|
if ($ofd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||||
|
$importedApps = Get-Content $ofd.FileName -Raw | ConvertFrom-Json
|
||||||
|
|
||||||
|
# Clear existing items
|
||||||
|
$script:lstWingetResults.Items.Clear()
|
||||||
|
|
||||||
|
# Add imported apps
|
||||||
|
foreach ($app in $importedApps.apps) {
|
||||||
|
$script:lstWingetResults.Items.Add([PSCustomObject]@{
|
||||||
|
IsSelected = $true
|
||||||
|
Name = $app.name
|
||||||
|
Id = $app.id
|
||||||
|
Version = "" # Will be populated when searching
|
||||||
|
Source = $app.source
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Windows.MessageBox]::Show("App list imported successfully.", "Success", "OK", "Information")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
[System.Windows.MessageBox]::Show("Error importing app list: $_", "Error", "OK", "Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Button: Build FFU
|
# Button: Build FFU
|
||||||
$btnRun = $window.FindName('btnRun')
|
$btnRun = $window.FindName('btnRun')
|
||||||
$btnRun.Add_Click({
|
$btnRun.Add_Click({
|
||||||
|
|||||||
@@ -598,6 +598,58 @@
|
|||||||
ToolTip="Check installation status and version of Winget CLI and PowerShell module. Will install or update if needed."/>
|
ToolTip="Check installation status and version of Winget CLI and PowerShell module. Will install or update if needed."/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Winget Search Panel -->
|
||||||
|
<StackPanel x:Name="wingetSearchPanel"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Margin="25,10,5,5">
|
||||||
|
|
||||||
|
<TextBlock Text="Winget Search"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Margin="0,0,0,5"/>
|
||||||
|
|
||||||
|
<Grid Margin="0,0,0,10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="100"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBox x:Name="txtWingetSearch"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Height="24"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
ToolTip="Enter an application name to search for"/>
|
||||||
|
|
||||||
|
<Button x:Name="btnWingetSearch"
|
||||||
|
Grid.Column="1"
|
||||||
|
Content="Search"
|
||||||
|
Width="100"
|
||||||
|
Height="24"
|
||||||
|
ToolTip="Search for applications using Windows Package Manager"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Results ListView -->
|
||||||
|
<ListView x:Name="lstWingetResults"
|
||||||
|
Height="300"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Auto"/>
|
||||||
|
|
||||||
|
<!-- Save/Import Buttons -->
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
|
<Button x:Name="btnSaveWingetList"
|
||||||
|
Content="Save Applist.json"
|
||||||
|
Padding="15,5"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
ToolTip="Save selected applications to a JSON file"/>
|
||||||
|
<Button x:Name="btnImportWingetList"
|
||||||
|
Content="Import Applist.json"
|
||||||
|
Padding="15,5"
|
||||||
|
ToolTip="Import applications from a JSON file"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
Reference in New Issue
Block a user