From bc4980c6b8d1413d9d7fc688b9a1ac164d882aaa Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Sat, 15 Feb 2025 11:24:17 -0800 Subject: [PATCH] Add USB drive detection and selection functionality --- FFUDevelopment/BuildFFUVM_UI.ps1 | 149 +++++++++++++++++++++++++++++- FFUDevelopment/BuildFFUVM_UI.xaml | 98 +++++++++++++++----- 2 files changed, 221 insertions(+), 26 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM_UI.ps1 b/FFUDevelopment/BuildFFUVM_UI.ps1 index 31fc59a..13c52a4 100644 --- a/FFUDevelopment/BuildFFUVM_UI.ps1 +++ b/FFUDevelopment/BuildFFUVM_UI.ps1 @@ -9,6 +9,24 @@ $FFUDevelopmentPath = $PSScriptRoot $AppsPath = Join-Path $FFUDevelopmentPath "Apps" $OfficePath = Join-Path $AppsPath "Office" +# Add the new function for USB drive detection +function Get-USBDrives { + Get-WmiObject Win32_DiskDrive | Where-Object { + ($_.MediaType -eq 'Removable Media' -or $_.MediaType -eq 'External hard disk media') -and + $_.InterfaceType -eq 'USB' + } | ForEach-Object { + $size = [math]::Round($_.Size / 1GB, 2) + $serialNumber = if ($_.SerialNumber) { $_.SerialNumber.Trim() } else { "N/A" } + @{ + Model = $_.Model + SerialNumber = $serialNumber + Size = $size + DeviceID = $_.DeviceID + IsSelected = $false + } + } +} + # Some default values $defaultISOPath = "" $defaultWindowsRelease = 11 # numeric @@ -26,7 +44,7 @@ $allowedFeatures = @( "Client-EmbeddedShellLauncher","Client-KeyboardFilter","Client-ProjFS","Client-UnifiedWriteFilter", "Containers","Containers-DisposableClientVM","Containers-HNS","Containers-SDN","DataCenterBridging", "DirectoryServices-ADAM-Client","DirectPlay","HostGuardian","HypervisorPlatform","IIS-ApplicationDevelopment", - "IIS-ApplicationInit","IIS-ASP","IIS-ASPNET","IIS-ASPNET45","IIS-BasicAuthentication","IIS-CertProvider", + "IIS-ApplicationInit","IIS-ASP","IIS-ASPNET45","IIS-BasicAuthentication","IIS-CertProvider", "IIS-CGI","IIS-ClientCertificateMappingAuthentication","IIS-CommonHttpFeatures","IIS-CustomLogging", "IIS-DefaultDocument","IIS-DirectoryBrowsing","IIS-DigestAuthentication","IIS-ESP","IIS-FTPServer", "IIS-FTPExtensibility","IIS-FTPSvc","IIS-HealthAndDiagnostics","IIS-HostableWebCore","IIS-HttpCompressionDynamic", @@ -167,6 +185,16 @@ function Get-UIConfig { # --- Applications tab --- $installApps = $window.FindName('chkInstallApps').IsChecked + # Add USB drive selection to config + $selectedUSBDrives = $window.FindName('lstUSBDrives').Items | Where-Object { $_.IsSelected } | ForEach-Object { + @{ + Model = $_.Model + SerialNumber = $_.SerialNumber + DeviceID = $_.DeviceID + Size = $_.Size + } + } + # Build configuration hashtable (unsorted) $config = [ordered]@{ AllowExternalHardDiskMedia = $allowExt @@ -217,6 +245,7 @@ function Get-UIConfig { WindowsSKU = $windowsSKU WindowsVersion = $windowsVersion FFUPrefix = $ffuPrefix # <-- new option for VM Name Prefix + USBDriveList = $selectedUSBDrives # Add USB drive selection } # Sort the configuration hashtable alphabetically by key @@ -588,6 +617,99 @@ $window.Add_Loaded({ $script:chkPreviewCU.Add_Unchecked({ $script:chkLatestCU.IsEnabled = $true }) + + # Add USB Drive Detection handler + $script:btnCheckUSBDrives = $window.FindName('btnCheckUSBDrives') + $script:lstUSBDrives = $window.FindName('lstUSBDrives') + $script:chkSelectAllUSBDrives = $window.FindName('chkSelectAllUSBDrives') + + $script:btnCheckUSBDrives.Add_Click({ + $usbDrives = Get-USBDrives + $script:lstUSBDrives.Items.Clear() + foreach ($drive in $usbDrives) { + [void]$script:lstUSBDrives.Items.Add($drive) + } + + if ($usbDrives.Count -eq 0) { + [System.Windows.MessageBox]::Show("No USB drives found.", "USB Drive Detection", "OK", "Information") + } + }) + + # Handle Select All checkbox + $script:chkSelectAllUSBDrives.Add_Checked({ + foreach ($item in $script:lstUSBDrives.Items) { + $item.IsSelected = $true + } + $script:lstUSBDrives.Items.Refresh() + }) + + $script:chkSelectAllUSBDrives.Add_Unchecked({ + foreach ($item in $script:lstUSBDrives.Items) { + $item.IsSelected = $false + } + $script:lstUSBDrives.Items.Refresh() + }) + + # Add keyboard handler + $script:lstUSBDrives.Add_KeyDown({ + param($sender, $e) + if ($e.Key -eq 'Space') { + $selectedItem = $script:lstUSBDrives.SelectedItem + if ($selectedItem) { + $selectedItem.IsSelected = !$selectedItem.IsSelected + $script:lstUSBDrives.Items.Refresh() + # Update Select All checkbox state + $allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected }) + $script:chkSelectAllUSBDrives.IsChecked = $allSelected + } + } + }) + + # Add selection change handler + $script:lstUSBDrives.Add_SelectionChanged({ + param($sender, $e) + # Update Select All checkbox state + $allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected }) + $script:chkSelectAllUSBDrives.IsChecked = $allSelected + }) + + # Add handler to show/hide USB drive controls based on Build USB Drive checkbox + $script:chkBuildUSBDrive = $window.FindName('chkBuildUSBDrive') + $script:usbPanel = ($window.FindName('btnCheckUSBDrives').Parent.Parent) # Get the outer Grid instead of immediate parent + $script:usbPanel.Visibility = if ($script:chkBuildUSBDrive.IsChecked) { 'Visible' } else { 'Collapsed' } + + $script:chkBuildUSBDrive.Add_Checked({ + $script:usbPanel.Visibility = 'Visible' + }) + + $script:chkBuildUSBDrive.Add_Unchecked({ + $script:lstUSBDrives.Items.Clear() + $script:chkSelectAllUSBDrives.IsChecked = $false + $script:usbPanel.Visibility = 'Collapsed' + }) + + # Add commands for keyboard selection + $script:lstUSBDrives = $window.FindName('lstUSBDrives') + $script:lstUSBDrives.Add_KeyDown({ + param($sender, $e) + if ($e.Key -eq 'Space') { + $selectedItem = $script:lstUSBDrives.SelectedItem + if ($selectedItem) { + $selectedItem.IsSelected = !$selectedItem.IsSelected + # Update Select All checkbox state + $allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected }) + $script:chkSelectAllUSBDrives.IsChecked = $allSelected + } + } + }) + + # Add handler for item selection changed + $script:lstUSBDrives.Add_SelectionChanged({ + param($sender, $e) + # Update Select All checkbox state + $allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected }) + $script:chkSelectAllUSBDrives.IsChecked = $allSelected + }) }) # Button: Build FFU @@ -718,6 +840,31 @@ $btnLoadConfig.Add_Click({ $window.FindName('chkUpdatePreviewCU').IsChecked = $configContent.UpdatePreviewCU # Applications tab $window.FindName('chkInstallApps').IsChecked = $configContent.InstallApps + + # Update USB Drive selection if present in config + if ($configContent.USBDriveList) { + # First click the Check USB Drives button to populate the list + $script:btnCheckUSBDrives.RaiseEvent( + [System.Windows.RoutedEventArgs]::new( + [System.Windows.Controls.Button]::ClickEvent + ) + ) + + # Then select the drives that match the saved configuration + foreach ($item in $script:lstUSBDrives.Items) { + if ($configContent.USBDriveList | Where-Object { + $_.Model -eq $item.Model -and + $_.SerialNumber -eq $item.SerialNumber + }) { + $item.IsSelected = $true + } + } + $script:lstUSBDrives.Items.Refresh() + + # Update the Select All checkbox state + $allSelected = -not ($script:lstUSBDrives.Items | Where-Object { -not $_.IsSelected }) + $script:chkSelectAllUSBDrives.IsChecked = $allSelected + } } } catch { diff --git a/FFUDevelopment/BuildFFUVM_UI.xaml b/FFUDevelopment/BuildFFUVM_UI.xaml index 90408b3..a684fe1 100644 --- a/FFUDevelopment/BuildFFUVM_UI.xaml +++ b/FFUDevelopment/BuildFFUVM_UI.xaml @@ -190,36 +190,84 @@ + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +