Add USB drive detection and selection functionality

This commit is contained in:
rbalsleyMSFT
2025-02-15 11:24:17 -08:00
parent f20945be9f
commit bc4980c6b8
2 changed files with 221 additions and 26 deletions
+148 -1
View File
@@ -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 {
+73 -25
View File
@@ -190,36 +190,84 @@
</Grid>
<!-- Row 6: General Build Options Header -->
<TextBlock Grid.Row="6" Text="General Build Options" FontWeight="Bold" FontSize="16" Margin="0,10,0,5"/>
<!-- Row 7: General Build Options Checkboxes -->
<WrapPanel Grid.Row="7" Margin="0,5">
<CheckBox x:Name="chkCompactOS" Content="Compact OS" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will compact the OS when building the FFU. Default is $true."/>
<CheckBox x:Name="chkOptimize" Content="Optimize" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will optimize the FFU file. Default is $true."/>
<CheckBox x:Name="chkCreateCaptureMedia" Content="Create Capture Media" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, this will create WinPE capture media for use when $InstallApps is set to $true. This capture media will be automatically attached to the VM, and the boot order will be changed to automate the capture of the FFU."/>
<CheckBox x:Name="chkCreateDeploymentMedia" Content="Create Deployment Media" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, this will create WinPE deployment media for use when deploying to a physical device."/>
<CheckBox x:Name="chkBuildUSBDrive" Content="Build USB Drive" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will partition and format a USB drive and copy the captured FFU to the drive."/>
<CheckBox x:Name="chkCompactOS" Content="Compact OS" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will compact the OS when building the FFU."/>
<CheckBox x:Name="chkOptimize" Content="Optimize" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will optimize during FFU build."/>
<CheckBox x:Name="chkCreateCaptureMedia" Content="Create Capture Media" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will create WinPE capture media."/>
<CheckBox x:Name="chkCreateDeploymentMedia" Content="Create Deployment Media" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will create WinPE deployment media."/>
</WrapPanel>
<!-- Row 8: Build USB Drive Header -->
<!-- <TextBlock Grid.Row="8" Text="Build USB Drive" FontWeight="Bold" FontSize="16" Margin="0,10,0,5"/> -->
<!-- Row 8: Build USB Drive Options Grid -->
<Grid Grid.Row="8" Margin="0,10,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Left Column: USB Drive Options -->
<StackPanel Grid.Column="0" Margin="5">
<TextBlock Text="Build USB Drive" FontWeight="Bold" FontSize="16" Margin="0,10,0,5"/>
<CheckBox x:Name="chkBuildUSBDrive" Content="Build USB Drive" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will partition and format a USB drive and copy the captured FFU to the drive."/>
<CheckBox x:Name="chkPromptExternalHardDiskMedia" Content="Prompt External Hard Disk Media" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will prompt the user to confirm the use of media identified as External Hard Disk media via WMI class Win32_DiskDrive. Default is $true."/>
<CheckBox x:Name="chkAllowExternalHardDiskMedia" Content="Allow External Hard Disk Media" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will allow the use of media identified as External Hard Disk media via WMI class Win32_DiskDrive. Default is not defined."/>
</StackPanel>
<!-- Right Column: USB Drive Modification -->
<StackPanel Grid.Column="1" Margin="5">
<TextBlock Text="USB Drive Modification" FontWeight="Bold" FontSize="16" Margin="0,10,0,5"/>
<CheckBox x:Name="chkCopyAutopilot" Content="Copy Autopilot" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will copy the $FFUDevelopmentPath\Autopilot folder to the Deployment partition of the USB drive. Default is $false."/>
<CheckBox x:Name="chkCopyUnattend" Content="Copy Unattend" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will copy the $FFUDevelopmentPath\Unattend folder to the Deployment partition of the USB drive. Default is $false."/>
<CheckBox x:Name="chkCopyPPKG" Content="Copy PPKG" Margin="5" VerticalAlignment="Center" ToolTip="When set to $true, will copy the provisioning package from the $FFUDevelopmentPath\PPKG folder to the Deployment partition of the USB drive. Default is $false."/>
<!-- Row 8: Build USB Drive Section -->
<Grid Grid.Row="8" Margin="0,10,0,5" x:Name="usbDriveSection">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<TextBlock Grid.Row="0" Text="Build USB Drive" FontWeight="Bold" FontSize="16" Margin="0,0,0,5"/>
<!-- External Hard Disk Media Settings -->
<StackPanel Grid.Row="1" Margin="5,0,0,10">
<CheckBox x:Name="chkPromptExternalHardDiskMedia" Content="Prompt for External Hard Disk Media" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will prompt before using external hard disk media."/>
<CheckBox x:Name="chkAllowExternalHardDiskMedia" Content="Allow External Hard Disk Media" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will allow the use of external hard disk media."/>
</StackPanel>
<!-- USB Drive Detection -->
<Grid Grid.Row="2" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="btnCheckUSBDrives" Content="Check USB Drives" Grid.Row="0" Grid.Column="0" Margin="5" Padding="10,5"/>
<CheckBox x:Name="chkSelectAllUSBDrives" Content="Select All" Grid.Row="0" Grid.Column="1" Margin="10,5" VerticalAlignment="Center"/>
<ListView x:Name="lstUSBDrives" Grid.Row="1" Grid.ColumnSpan="2" Height="100" Margin="5">
<ListView.View>
<GridView>
<GridViewColumn Header="Selected" Width="70">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Model" DisplayMemberBinding="{Binding Model}" Width="200"/>
<GridViewColumn Header="Serial Number" DisplayMemberBinding="{Binding SerialNumber}" Width="150"/>
<GridViewColumn Header="Size (GB)" DisplayMemberBinding="{Binding Size}" Width="80"/>
</GridView>
</ListView.View>
</ListView>
<!-- USB Drive Options -->
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="5">
<TextBlock Text="USB Drive Options" FontWeight="Bold" Margin="0,5"/>
<CheckBox x:Name="chkCopyAutopilot" Content="Copy Autopilot" Margin="5" VerticalAlignment="Center" Tag="Copy Autopilot files to deployment partition."/>
<CheckBox x:Name="chkCopyUnattend" Content="Copy Unattend" Margin="5" VerticalAlignment="Center" Tag="Copy Unattend files to deployment partition."/>
<CheckBox x:Name="chkCopyPPKG" Content="Copy Provisioning Package" Margin="5" VerticalAlignment="Center" Tag="Copy PPKG files to deployment partition."/>
</StackPanel>
</Grid>
</Grid>
<!-- Row 9: Post-Build Cleanup -->
<StackPanel Grid.Row="9" Margin="0,10,0,5">
<TextBlock Text="Post-Build Cleanup" FontWeight="Bold" FontSize="16" Margin="0,0,0,5"/>
<CheckBox x:Name="chkCleanupAppsISO" Content="Cleanup Apps ISO" Margin="5" VerticalAlignment="Center" Tag="Remove Apps ISO after FFU capture."/>
<CheckBox x:Name="chkCleanupCaptureISO" Content="Cleanup Capture ISO" Margin="5" VerticalAlignment="Center" Tag="Remove WinPE capture ISO after FFU capture."/>
<CheckBox x:Name="chkCleanupDeployISO" Content="Cleanup Deploy ISO" Margin="5" VerticalAlignment="Center" Tag="Remove WinPE deployment ISO after FFU capture."/>
<CheckBox x:Name="chkCleanupDrivers" Content="Cleanup Drivers" Margin="5" VerticalAlignment="Center" Tag="Remove drivers folder after FFU capture."/>
<CheckBox x:Name="chkRemoveFFU" Content="Remove FFU" Margin="5" VerticalAlignment="Center" Tag="Remove FFU after copying to USB drive."/>
</StackPanel>
</Grid>
</ScrollViewer>
</TabItem>