From 8229aa73fe6b591680a6b1fb79227ea1a8874bc0 Mon Sep 17 00:00:00 2001 From: rbalsleyMSFT <53497092+rbalsleyMSFT@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:04:52 -0800 Subject: [PATCH] Add BITS transfer priority configuration support Introduces a new parameter to control BITS download priority across the build system and UI, allowing users to optimize transfer speeds when needed. The feature adds a priority selector to the UI with four options (Foreground, High, Normal, Low) and propagates the selection through the build script and common modules. Priority can be set via UI, command-line parameter, or environment variable, with Normal as the default. Updates the BITS transfer retry logic to respect the configured priority instead of hardcoding Normal priority, and fixes minor code formatting inconsistencies. --- FFUDevelopment/BuildFFUVM.ps1 | 3 ++ FFUDevelopment/BuildFFUVM_UI.xaml | 42 +++++++++++------ .../FFU.Common/FFU.Common.Core.psm1 | 43 ++++++++++++++++-- .../FFUUI.Core/FFUUI.Core.Config.psm1 | 15 +++--- .../FFUUI.Core/FFUUI.Core.Handlers.psm1 | 11 +++++ .../FFUUI.Core/FFUUI.Core.Initialize.psm1 | 3 ++ .../FFUUI.Core/FFUUI.Core.Shared.psm1 | 26 +++++++++++ FFUDevelopment/FFUUI.Core/FFUUI.Core.psm1 | 1 + FFUDevelopment/config/Sample_default.json | Bin 6196 -> 6254 bytes 9 files changed, 121 insertions(+), 23 deletions(-) diff --git a/FFUDevelopment/BuildFFUVM.ps1 b/FFUDevelopment/BuildFFUVM.ps1 index 4d7fbd2..a6d2b6e 100644 --- a/FFUDevelopment/BuildFFUVM.ps1 +++ b/FFUDevelopment/BuildFFUVM.ps1 @@ -354,6 +354,8 @@ param( [bool]$BuildUSBDrive, [hashtable]$USBDriveList, [int]$MaxUSBDrives = 5, + [ValidateSet('Foreground', 'High', 'Normal', 'Low')] + [string]$BitsPriority = 'Normal', [Parameter(Mandatory = $false)] [ValidateSet(10, 11, 2016, 2019, 2021, 2022, 2024, 2025)] [int]$WindowsRelease = 11, @@ -659,6 +661,7 @@ if ($WindowsSKU -like "*LTS*") { # Set the log path for the common logger Set-CommonCoreLogPath -Path $LogFile +Set-BitsTransferPriority -Priority $BitsPriority #FUNCTIONS diff --git a/FFUDevelopment/BuildFFUVM_UI.xaml b/FFUDevelopment/BuildFFUVM_UI.xaml index cf20f8e..d9884d6 100644 --- a/FFUDevelopment/BuildFFUVM_UI.xaml +++ b/FFUDevelopment/BuildFFUVM_UI.xaml @@ -641,7 +641,7 @@ - + @@ -657,13 +657,15 @@ - + - + - + - + + + @@ -729,11 +731,25 @@ - - + + + + + + + + + Foreground + High + Normal + Low + + + + - - + + @@ -745,8 +761,8 @@ - - + + @@ -811,8 +827,8 @@ - - + + diff --git a/FFUDevelopment/FFU.Common/FFU.Common.Core.psm1 b/FFUDevelopment/FFU.Common/FFU.Common.Core.psm1 index 30a3dd2..0b2a564 100644 --- a/FFUDevelopment/FFU.Common/FFU.Common.Core.psm1 +++ b/FFUDevelopment/FFU.Common/FFU.Common.Core.psm1 @@ -12,6 +12,10 @@ $script:CommonCoreLogFilePath = $null # Mutex for log file access $script:commonCoreLogMutexName = "Global\FFUCommonCoreLogMutex" # Unique name $script:commonCoreLogMutex = New-Object System.Threading.Mutex($false, $script:commonCoreLogMutexName) +$script:BitsTransferPriority = 'Normal' +if (-not [string]::IsNullOrWhiteSpace($env:FFU_BITS_PRIORITY)) { + $script:BitsTransferPriority = $env:FFU_BITS_PRIORITY +} # Function to set the log file path for this module function Set-CommonCoreLogPath { @@ -30,7 +34,24 @@ function Set-CommonCoreLogPath { Write-Warning "Set-CommonCoreLogPath called with an empty or null path." } } - + +function Set-BitsTransferPriority { + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [ValidateSet('Foreground', 'High', 'Normal', 'Low')] + [string]$Priority + ) + $script:BitsTransferPriority = $Priority + try { + Set-Item -Path Env:FFU_BITS_PRIORITY -Value $Priority -ErrorAction Stop + } + catch { + WriteLog "Failed to set FFU_BITS_PRIORITY environment variable: $($_.Exception.Message)" + } + WriteLog "BITS transfer priority set to $Priority." +} + # Centralized WriteLog function function WriteLog { [CmdletBinding()] @@ -143,9 +164,23 @@ function Start-BitsTransferWithRetry { [string]$Source, [Parameter(Mandatory = $true)] [string]$Destination, - [int]$Retries = 3 + [int]$Retries = 3, + [ValidateSet('Foreground','High','Normal','Low')] + [string]$Priority ) + if ([string]::IsNullOrWhiteSpace($Priority)) { + if (-not [string]::IsNullOrWhiteSpace($env:FFU_BITS_PRIORITY)) { + $Priority = $env:FFU_BITS_PRIORITY + } + elseif (-not [string]::IsNullOrWhiteSpace($script:BitsTransferPriority)) { + $Priority = $script:BitsTransferPriority + } + else { + $Priority = 'Normal' + } + } + $attempt = 0 $lastError = $null $notLoggedOnHResult = [int]0x800704dd @@ -158,7 +193,7 @@ function Start-BitsTransferWithRetry { $VerbosePreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue' - Start-BitsTransfer -Source $Source -Destination $Destination -Priority Normal -ErrorAction Stop + Start-BitsTransfer -Source $Source -Destination $Destination -Priority $Priority -ErrorAction Stop $ProgressPreference = $OriginalProgressPreference $VerbosePreference = $OriginalVerbosePreference @@ -259,7 +294,7 @@ function ConvertTo-SafeName { # Collapse multiple consecutive dashes $sanitized = $sanitized -replace '-{2,}', '-' # Trim leading/trailing spaces, periods, and dashes - $sanitized = $sanitized.Trim(' ','.','-') + $sanitized = $sanitized.Trim(' ', '.', '-') if ([string]::IsNullOrWhiteSpace($sanitized)) { $sanitized = 'Unnamed' } diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Config.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Config.psm1 index 5105b99..13cc782 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Config.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Config.psm1 @@ -96,6 +96,7 @@ function Get-UIConfig { USBDriveList = @{} Username = $State.Controls.txtUsername.Text Threads = [int]$State.Controls.txtThreads.Text + BitsPriority = $State.Controls.cmbBitsPriority.SelectedItem MaxUSBDrives = [int]$State.Controls.txtMaxUSBDrives.Text Verbose = $State.Controls.chkVerbose.IsChecked VMHostIPAddress = $State.Controls.txtVMHostIPAddress.Text @@ -412,6 +413,7 @@ function Update-UIFromConfig { 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 @@ -748,13 +750,14 @@ function Update-UIFromConfig { 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." } - catch { - WriteLog "LoadConfig: Error applying Additional FFU selections: $($_.Exception.Message)" - } - - WriteLog "LoadConfig: Configuration loading process finished." - } function Invoke-SaveConfiguration { param( diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Handlers.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Handlers.psm1 index 5043d43..e739fb6 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Handlers.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Handlers.psm1 @@ -152,6 +152,17 @@ function Register-EventHandlers { $localState.Controls.chkPromptExternalHardDiskMedia.IsChecked = $false }) + if ($null -ne $State.Controls.cmbBitsPriority) { + $State.Controls.cmbBitsPriority.Add_SelectionChanged({ + param($eventSource, $selectionChangedEventArgs) + $window = [System.Windows.Window]::GetWindow($eventSource) + if ($null -eq $window -or $null -eq $window.Tag) { + return + } + Update-BitsPrioritySetting -State $window.Tag + }) + } + # Additional FFU Files events $State.Controls.chkCopyAdditionalFFUFiles.Add_Checked({ param($eventSource, $routedEventArgs) diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 index 0870af7..f18eec3 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Initialize.psm1 @@ -118,6 +118,7 @@ function Initialize-UIControls { $State.Controls.txtShareName = $window.FindName('txtShareName') $State.Controls.txtUsername = $window.FindName('txtUsername') $State.Controls.txtThreads = $window.FindName('txtThreads') + $State.Controls.cmbBitsPriority = $window.FindName('cmbBitsPriority') $State.Controls.txtMaxUSBDrives = $window.FindName('txtMaxUSBDrives') $State.Controls.chkCompactOS = $window.FindName('chkCompactOS') $State.Controls.chkOptimize = $window.FindName('chkOptimize') @@ -234,6 +235,7 @@ function Initialize-UIDefaults { $State.Controls.txtShareName.Text = $State.Defaults.generalDefaults.ShareName $State.Controls.txtUsername.Text = $State.Defaults.generalDefaults.Username $State.Controls.txtThreads.Text = $State.Defaults.generalDefaults.Threads + $State.Controls.cmbBitsPriority.SelectedItem = $State.Defaults.generalDefaults.BitsPriority $State.Controls.txtMaxUSBDrives.Text = $State.Defaults.generalDefaults.MaxUSBDrives $State.Controls.chkBuildUSBDriveEnable.IsChecked = $State.Defaults.generalDefaults.BuildUSBDriveEnable $State.Controls.chkCompactOS.IsChecked = $State.Defaults.generalDefaults.CompactOS @@ -263,6 +265,7 @@ function Initialize-UIDefaults { $State.Controls.chkPromptExternalHardDiskMedia.IsEnabled = $State.Controls.chkAllowExternalHardDiskMedia.IsChecked $State.Controls.chkCopyAdditionalFFUFiles.IsChecked = $State.Defaults.generalDefaults.CopyAdditionalFFUFiles $State.Controls.additionalFFUPanel.Visibility = if ($State.Controls.chkCopyAdditionalFFUFiles.IsChecked) { 'Visible' } else { 'Collapsed' } + Update-BitsPrioritySetting -State $State # Hyper-V Settings defaults from General Defaults Initialize-VMSwitchData -State $State diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Shared.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Shared.psm1 index 4299e06..0914251 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.Shared.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.Shared.psm1 @@ -220,6 +220,32 @@ function Invoke-ProgressUpdate { $ProgressQueue.Enqueue(@{ Identifier = $Identifier; Status = $Status }) } +function Update-BitsPrioritySetting { + param( + [Parameter(Mandatory)] + [pscustomobject]$State + ) + + $combo = $State.Controls.cmbBitsPriority + if ($null -eq $combo) { + WriteLog "BITS priority control not available; skipping priority update." + return + } + + $selectedPriority = $combo.SelectedItem + if ([string]::IsNullOrWhiteSpace($selectedPriority)) { + $selectedPriority = 'Normal' + } + + try { + Set-BitsTransferPriority -Priority $selectedPriority + WriteLog "BITS transfer priority set to $selectedPriority." + } + catch { + WriteLog "Failed to set BITS transfer priority: $($_.Exception.Message)" + } +} + # Add a function to create a sortable list view function Add-SortableColumn { param( diff --git a/FFUDevelopment/FFUUI.Core/FFUUI.Core.psm1 b/FFUDevelopment/FFUUI.Core/FFUUI.Core.psm1 index b4bc6d3..ebc20ed 100644 --- a/FFUDevelopment/FFUUI.Core/FFUUI.Core.psm1 +++ b/FFUDevelopment/FFUUI.Core/FFUUI.Core.psm1 @@ -117,6 +117,7 @@ function Get-GeneralDefaults { ShareName = "FFUCaptureShare" Username = "ffu_user" Threads = 5 + BitsPriority = 'Normal' MaxUSBDrives = 5 BuildUSBDriveEnable = $false CompactOS = $true diff --git a/FFUDevelopment/config/Sample_default.json b/FFUDevelopment/config/Sample_default.json index 6b8a335c0405959836859504c47c21d6226d3d6a..cf5d7a6b4338b8b8954d802fb007d88c908726ee 100644 GIT binary patch delta 38 ucmdmD@XlaE3L|SKLkUCi6h9ZVshD3&($&Kv7o0AyNi2(rOsS6qa delta 17 YcmaE7u*G0Q3ghNQjAz7Hcp11D06^jeYXATM