feat: Add MaxUSBDrives parameter for parallel USB drive processing

- Introduced a new parameter `MaxUSBDrives` to control the maximum number of USB drives that can be built in parallel, with a default value of 5.
- Updated UI to include a textbox for setting `MaxUSBDrives`.
- Implemented validation to ensure the value is a non-negative integer.
- Adjusted the deployment function to respect the `MaxUSBDrives` limit during USB drive creation.
This commit is contained in:
rbalsleyMSFT
2025-08-07 16:32:25 -07:00
parent db9b7335f2
commit 846d449aac
6 changed files with 35 additions and 2 deletions
+8 -1
View File
@@ -193,6 +193,9 @@ A hashtable containing USB drives from win32_diskdrive where:
Example: @{ "SanDisk Ultra" = "1234567890"; "Kingston DataTraveler" = "0987654321" } Example: @{ "SanDisk Ultra" = "1234567890"; "Kingston DataTraveler" = "0987654321" }
.PARAMETER MaxUSBDrives
Maximum number of USB drives to build in parallel. Default is 5. Set to 0 to process all discovered drives (or all selected drives when USBDriveList or selection is used). Actual throttle will never exceed the number of drives discovered.
.PARAMETER UserAgent .PARAMETER UserAgent
User agent string to use when downloading files. User agent string to use when downloading files.
@@ -344,6 +347,7 @@ param(
[string]$ProductKey, [string]$ProductKey,
[bool]$BuildUSBDrive, [bool]$BuildUSBDrive,
[hashtable]$USBDriveList, [hashtable]$USBDriveList,
[int]$MaxUSBDrives = 5,
[Parameter(Mandatory = $false)] [Parameter(Mandatory = $false)]
[ValidateSet(10, 11, 2016, 2019, 2021, 2022, 2024, 2025)] [ValidateSet(10, 11, 2016, 2019, 2021, 2022, 2024, 2025)]
[int]$WindowsRelease = 11, [int]$WindowsRelease = 11,
@@ -3310,6 +3314,9 @@ Function New-DeploymentUSB {
# 2. Partition and format USB drives in parallel # 2. Partition and format USB drives in parallel
WriteLog "Starting parallel creation for $USBDrivesCount USB drive(s)." WriteLog "Starting parallel creation for $USBDrivesCount USB drive(s)."
$resolvedUSBThrottle = if ($MaxUSBDrives -gt 0) { [math]::Min($MaxUSBDrives, $USBDrivesCount) } else { $USBDrivesCount }
WriteLog "Using USB drive throttle limit: $resolvedUSBThrottle (MaxUSBDrives param: $MaxUSBDrives; Drives to process: $USBDrivesCount)"
$USBDrives | ForEach-Object -Parallel { $USBDrives | ForEach-Object -Parallel {
$USBDrive = $_ $USBDrive = $_
@@ -3391,7 +3398,7 @@ Function New-DeploymentUSB {
Set-Volume -DriveLetter $DeployPartition.DriveLetter -NewFileSystemLabel "Deploy" Set-Volume -DriveLetter $DeployPartition.DriveLetter -NewFileSystemLabel "Deploy"
WriteLog "Finished processing disk $DiskNumber" WriteLog "Finished processing disk $DiskNumber"
} -ThrottleLimit 2 } -ThrottleLimit $resolvedUSBThrottle
# Dismount ISO after all parallel jobs are complete # Dismount ISO after all parallel jobs are complete
WriteLog "Dismounting deployment ISO." WriteLog "Dismounting deployment ISO."
+6
View File
@@ -755,6 +755,12 @@
<CheckBox x:Name="chkCopyUnattend" Content="Copy Unattend.xml" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will copy the Unattend.xml file to the USB drive."/> <CheckBox x:Name="chkCopyUnattend" Content="Copy Unattend.xml" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will copy the Unattend.xml file to the USB drive."/>
<CheckBox x:Name="chkCopyPPKG" Content="Copy Provisioning Package" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will copy the provisioning package to the USB drive."/> <CheckBox x:Name="chkCopyPPKG" Content="Copy Provisioning Package" Margin="5" VerticalAlignment="Center" Tag="When set to $true, will copy the provisioning package to the USB drive."/>
<!-- Max USB Drives -->
<StackPanel Orientation="Horizontal" Margin="5">
<TextBlock Text="Max USB Drives" VerticalAlignment="Center" ToolTip="Maximum number of USB drives to build at once. Enter 0 to process all discovered (or all selected) drives."/>
<TextBox x:Name="txtMaxUSBDrives" Width="50" Margin="10,0,0,0" Text="5" VerticalAlignment="Center" ToolTip="Maximum number of USB drives to build at once. Enter 0 to process all discovered (or all selected) drives."/>
</StackPanel>
<!-- USB Drive Selection Section --> <!-- USB Drive Selection Section -->
<Grid x:Name="usbDriveSelectionPanel" Margin="5,0,0,0"> <Grid x:Name="usbDriveSelectionPanel" Margin="5,0,0,0">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -93,6 +93,7 @@ function Get-UIConfig {
USBDriveList = @{} USBDriveList = @{}
Username = $State.Controls.txtUsername.Text Username = $State.Controls.txtUsername.Text
Threads = [int]$State.Controls.txtThreads.Text Threads = [int]$State.Controls.txtThreads.Text
MaxUSBDrives = [int]$State.Controls.txtMaxUSBDrives.Text
Verbose = $State.Controls.chkVerbose.IsChecked Verbose = $State.Controls.chkVerbose.IsChecked
VMHostIPAddress = $State.Controls.txtVMHostIPAddress.Text VMHostIPAddress = $State.Controls.txtVMHostIPAddress.Text
VMLocation = $State.Controls.txtVMLocation.Text VMLocation = $State.Controls.txtVMLocation.Text
@@ -277,6 +278,7 @@ function Update-UIFromConfig {
Set-UIValue -ControlName 'txtShareName' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'ShareName' -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 'txtUsername' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Username' -State $State
Set-UIValue -ControlName 'txtThreads' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Threads' -State $State Set-UIValue -ControlName 'txtThreads' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'Threads' -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 'chkBuildUSBDriveEnable' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'BuildUSBDrive' -State $State
Set-UIValue -ControlName 'chkCompactOS' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'CompactOS' -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 'chkUpdateADK' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'UpdateADK' -State $State
@@ -44,7 +44,8 @@ function Register-EventHandlers {
$State.Controls.txtDiskSize, $State.Controls.txtDiskSize,
$State.Controls.txtMemory, $State.Controls.txtMemory,
$State.Controls.txtProcessors, $State.Controls.txtProcessors,
$State.Controls.txtThreads $State.Controls.txtThreads,
$State.Controls.txtMaxUSBDrives
) )
# Attach the handlers to each relevant textbox # Attach the handlers to each relevant textbox
@@ -72,6 +73,20 @@ function Register-EventHandlers {
}) })
} }
# Add specific validation for the Max USB Drives textbox to ensure it's an integer >=0 (allow 0 meaning all)
if ($null -ne $State.Controls.txtMaxUSBDrives) {
$State.Controls.txtMaxUSBDrives.Add_LostFocus({
param($eventSource, $routedEventArgs)
$textBox = $eventSource
$currentValue = 0
$isValidInteger = [int]::TryParse($textBox.Text, [ref]$currentValue)
if (-not $isValidInteger -or $currentValue -lt 0) {
$textBox.Text = '0'
WriteLog "Max USB Drives value was invalid or less than 0. Reset to 0 (process all)."
}
})
}
# Build Tab Event Handlers # Build Tab Event Handlers
$State.Controls.btnBrowseFFUDevPath.Add_Click({ $State.Controls.btnBrowseFFUDevPath.Add_Click({
param($eventSource, $routedEventArgs) param($eventSource, $routedEventArgs)
@@ -115,6 +115,7 @@ function Initialize-UIControls {
$State.Controls.txtShareName = $window.FindName('txtShareName') $State.Controls.txtShareName = $window.FindName('txtShareName')
$State.Controls.txtUsername = $window.FindName('txtUsername') $State.Controls.txtUsername = $window.FindName('txtUsername')
$State.Controls.txtThreads = $window.FindName('txtThreads') $State.Controls.txtThreads = $window.FindName('txtThreads')
$State.Controls.txtMaxUSBDrives = $window.FindName('txtMaxUSBDrives')
$State.Controls.chkCompactOS = $window.FindName('chkCompactOS') $State.Controls.chkCompactOS = $window.FindName('chkCompactOS')
$State.Controls.chkOptimize = $window.FindName('chkOptimize') $State.Controls.chkOptimize = $window.FindName('chkOptimize')
$State.Controls.chkAllowVHDXCaching = $window.FindName('chkAllowVHDXCaching') $State.Controls.chkAllowVHDXCaching = $window.FindName('chkAllowVHDXCaching')
@@ -227,6 +228,7 @@ function Initialize-UIDefaults {
$State.Controls.txtShareName.Text = $State.Defaults.generalDefaults.ShareName $State.Controls.txtShareName.Text = $State.Defaults.generalDefaults.ShareName
$State.Controls.txtUsername.Text = $State.Defaults.generalDefaults.Username $State.Controls.txtUsername.Text = $State.Defaults.generalDefaults.Username
$State.Controls.txtThreads.Text = $State.Defaults.generalDefaults.Threads $State.Controls.txtThreads.Text = $State.Defaults.generalDefaults.Threads
$State.Controls.txtMaxUSBDrives.Text = $State.Defaults.generalDefaults.MaxUSBDrives
$State.Controls.chkBuildUSBDriveEnable.IsChecked = $State.Defaults.generalDefaults.BuildUSBDriveEnable $State.Controls.chkBuildUSBDriveEnable.IsChecked = $State.Defaults.generalDefaults.BuildUSBDriveEnable
$State.Controls.chkCompactOS.IsChecked = $State.Defaults.generalDefaults.CompactOS $State.Controls.chkCompactOS.IsChecked = $State.Defaults.generalDefaults.CompactOS
$State.Controls.chkUpdateADK.IsChecked = $State.Defaults.generalDefaults.UpdateADK $State.Controls.chkUpdateADK.IsChecked = $State.Defaults.generalDefaults.UpdateADK
@@ -117,6 +117,7 @@ function Get-GeneralDefaults {
ShareName = "FFUCaptureShare" ShareName = "FFUCaptureShare"
Username = "ffu_user" Username = "ffu_user"
Threads = 5 Threads = 5
MaxUSBDrives = 5
BuildUSBDriveEnable = $false BuildUSBDriveEnable = $false
CompactOS = $true CompactOS = $true
Optimize = $true Optimize = $true