Docs: Add PowerShell comment-based help to all script modules

Adds standard PowerShell comment-based help blocks (synopsis and description) to all UI and common library script modules (`.psm1`) and the main UI entry point script (`.ps1`).

This improves maintainability and discoverability by documenting the purpose of each script file. Also removes various redundant or commented-out code blocks.
This commit is contained in:
rbalsleyMSFT
2025-07-18 14:52:03 -07:00
parent 7cc7919da4
commit 6df7b16cdf
19 changed files with 234 additions and 146 deletions
+9 -75
View File
@@ -1,6 +1,12 @@
# FFU.Common.Core.psm1
# Contains common core functions like logging and process invocation.
<#
.SYNOPSIS
Provides core, shared functions for logging, process execution, and resilient file transfers used across the FFU project.
.DESCRIPTION
This module is a central component of the FFU project, offering a set of robust, reusable functions.
It includes a centralized logging mechanism (WriteLog), a wrapper for running external processes with error handling (Invoke-Process),
a retry-aware BITS transfer function for reliable downloads (Start-BitsTransferWithRetry), and a progress reporting helper.
This module is designed to be imported by other scripts and modules within the project to ensure consistent behavior for common tasks.
#>
# Script-scoped variable for the log file path
$script:CommonCoreLogFilePath = $null
# Mutex for log file access
@@ -66,75 +72,6 @@ function WriteLog {
}
}
# Function to invoke external process
# function Invoke-Process {
# [CmdletBinding(SupportsShouldProcess)]
# param(
# [Parameter(Mandatory)]
# [ValidateNotNullOrEmpty()]
# [string]$FilePath,
# [Parameter()]
# [ValidateNotNullOrEmpty()]
# [string[]]$ArgumentList,
# [Parameter()]
# [ValidateNotNullOrEmpty()]
# [bool]$Wait = $true
# )
# $ErrorActionPreference = 'Stop' # Keep this local to the function
# try {
# $stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"
# $stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"
# $startProcessParams = @{
# FilePath = $FilePath
# ArgumentList = $ArgumentList
# RedirectStandardError = $stdErrTempFile
# RedirectStandardOutput = $stdOutTempFile
# Wait = $Wait
# PassThru = $true
# NoNewWindow = $true
# }
# # DEBUG
# # WriteLog "Running Command: $($startProcessParams.FilePath) $($startProcessParams.ArgumentList -join ' ')"
# if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) {
# $cmd = Start-Process @startProcessParams
# $cmdOutput = Get-Content -Path $stdOutTempFile -Raw -ErrorAction SilentlyContinue
# $cmdError = Get-Content -Path $stdErrTempFile -Raw -ErrorAction SilentlyContinue
# if (-not [string]::IsNullOrWhiteSpace($cmdOutput)) {
# WriteLog "STDOUT from '$FilePath': $cmdOutput"
# }
# if (-not [string]::IsNullOrWhiteSpace($cmdError)) {
# WriteLog "STDERR from '$FilePath': $cmdError"
# }
# if ($cmd.ExitCode -ne 0 -and $Wait) {
# $errorMessage = "Process '$FilePath' exited with code $($cmd.ExitCode)."
# if (-not [string]::IsNullOrWhiteSpace($cmdError)) {
# $errorMessage += " Error: $cmdError"
# }
# elseif (-not [string]::IsNullOrWhiteSpace($cmdOutput)) {
# $errorMessage += " Output: $cmdOutput"
# }
# throw $errorMessage.Trim()
# }
# }
# }
# catch {
# WriteLog "Error in Invoke-Process for '$FilePath': $($_.Exception.Message)"
# throw
# }
# finally {
# if (Test-Path $stdOutTempFile) { Remove-Item -Path $stdOutTempFile -Force -ErrorAction Ignore }
# if (Test-Path $stdErrTempFile) { Remove-Item -Path $stdErrTempFile -Force -ErrorAction Ignore }
# }
# return $cmd
# }
function Invoke-Process {
[CmdletBinding(SupportsShouldProcess)]
param
@@ -257,7 +194,4 @@ function Set-Progress {
WriteLog "[PROGRESS] $Percentage | $Message"
}
# Suppress the default progress bar for a cleaner console output for any script importing this module.
# $ProgressPreference = 'SilentlyContinue'
Export-ModuleMember -Function *
@@ -1,10 +1,13 @@
# FFU Common Drivers Module
# Contains shared functions related to driver handling.
# --------------------------------------------------------------------------
# SECTION: Driver Compression Function
# --------------------------------------------------------------------------
<#
.SYNOPSIS
Provides common functions for driver management, including compression, mapping, and existence checks.
.DESCRIPTION
The FFU.Common.Drivers module contains a set of shared functions used across the FFU project for handling driver packages.
This includes compressing driver folders into WIM files for efficient storage and deployment, maintaining a JSON-based mapping
of downloaded drivers to their respective makes and models, and checking for the pre-existence of driver packages to avoid
redundant downloads.
#>
function Compress-DriverFolderToWim {
[CmdletBinding(SupportsShouldProcess)]
param(
@@ -1,10 +1,57 @@
<#
.SYNOPSIS
Manages and executes multiple background tasks in parallel, with support for updating a WPF UI with progress.
.DESCRIPTION
This function provides a generic framework for running tasks in parallel using PowerShell's ForEach-Object -Parallel.
It is designed to process an array of items, executing a specific task for each one. It can operate in two modes: UI mode and non-UI mode.
In UI mode, it updates a specified ListView control in a WPF window with the status of each item as it's being processed
(e.g., Queued, Downloading, Completed, Error). It uses a dispatcher to ensure UI updates are thread-safe.
In non-UI mode, it runs the tasks and logs the status to the FFUDevelopment.log file.
The function determines the task to run via the -TaskType parameter and passes necessary arguments using -TaskArguments.
It handles module imports and log file setup within each parallel runspace to ensure tasks have the necessary dependencies and logging capabilities.
.PARAMETER ItemsToProcess
An array of objects, where each object represents an item to be processed by a parallel task. This is a mandatory parameter.
.PARAMETER ListViewControl
(UI Mode) The WPF ListView control that the function will update with the status of each item. Defaults to $null.
.PARAMETER IdentifierProperty
The name of the property on the item objects that serves as a unique identifier (e.g., 'Name', 'Id').
This is used to find and update the correct row in the ListView.
.PARAMETER StatusProperty
The name of the property on the item objects that holds the status string. This property will be updated with progress messages.
.PARAMETER TaskType
A string specifying which task to execute for each item. This is mandatory.
Valid values are:
- 'WingetDownload': Downloads a Winget application.
- 'CopyBYO': Copies a user-provided application.
- 'DownloadDriverByMake': Downloads drivers for a specific manufacturer.
.PARAMETER TaskArguments
A hashtable containing arguments required by the specific task being run (e.g., paths, API keys, configuration settings).
.PARAMETER CompletedStatusText
The status text to display when an item is processed successfully.
.PARAMETER ErrorStatusPrefix
A prefix for status messages when an error occurs.
.PARAMETER WindowObject
(UI Mode) The main WPF Window object, used to access the UI dispatcher for safe UI updates from background threads.
.PARAMETER MainThreadLogPath
The file path for the log file that should be used by all parallel threads. This ensures consistent logging.
.PARAMETER ThrottleLimit
The maximum number of parallel jobs to run concurrently. The default is 5.
.NOTES
This function relies on ForEach-Object -Parallel, which was introduced in PowerShell 7.
When running in UI mode, both -WindowObject and -ListViewControl must be provided.
The function dynamically imports required modules ('FFU.Common' and 'FFUUI.Core') into each parallel runspace.
It uses a concurrent queue to manage intermediate progress updates from threads to the main UI thread, preventing UI blocking and providing more granular feedback.
#>
function Invoke-ParallelProcessing {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[array]$ItemsToProcess,
[Parameter(Mandatory = $false)]
[object]$ListViewControl = $null, # Changed type to [object]
[object]$ListViewControl = $null,
[Parameter(Mandatory = $false)]
[string]$IdentifierProperty = 'Identifier',
[Parameter(Mandatory = $false)]
@@ -19,9 +66,9 @@ function Invoke-ParallelProcessing {
[Parameter(Mandatory = $false)]
[string]$ErrorStatusPrefix = "Error: ",
[Parameter(Mandatory = $false)]
[object]$WindowObject = $null, # Changed type to [object]
[object]$WindowObject = $null,
[Parameter(Mandatory = $false)]
[string]$MainThreadLogPath = $null, # New parameter for the log path
[string]$MainThreadLogPath = $null,
[Parameter(Mandatory = $false)]
[int]$ThrottleLimit = 5
)
@@ -60,11 +107,9 @@ function Invoke-ParallelProcessing {
$jobScopeVariables = $TaskArguments.Clone()
$jobScopeVariables['_commonModulePath'] = $commonModulePathForJob
$jobScopeVariables['_uiCoreModulePath'] = $uiCoreModulePathForJob
$jobScopeVariables['_currentLogFilePathForJob'] = $currentLogFilePathForJob # Pass the determined log path
$jobScopeVariables['_currentLogFilePathForJob'] = $currentLogFilePathForJob
$jobScopeVariables['_progressQueue'] = $progressQueue
# The $TaskScriptBlock parameter is already a local variable in this scope
# Initial UI update needs to happen *before* starting the jobs
# Update all items to a static "Processing..." status
if ($isUiMode) {
@@ -89,13 +134,9 @@ function Invoke-ParallelProcessing {
# $jobScopeVariables and $TaskType are local here
# Inside the -Parallel scriptblock, we access them with $using:
$jobs = $ItemsToProcess | ForEach-Object -Parallel {
# Access the current item via pipeline variable $_
$currentItem = $_
# Access the combined arguments hashtable from the calling scope using $using:
$localJobArgs = $using:jobScopeVariables
# Access the task type string from the calling scope using $using:
$localTaskType = $using:TaskType
# Access the progress queue using $using:
$localProgressQueue = $localJobArgs['_progressQueue']
# Initialize result hashtable
@@ -242,9 +283,7 @@ function Invoke-ParallelProcessing {
WriteLog $nullTaskResultMessage
$resultStatus = $nullTaskResultMessage
$resultCode = 1
# $resultIdentifier is already set
}
# If it was an unsupported Make, $resultStatus and $resultCode are already set from the 'default' case.
}
Default {
# This handles unknown $localTaskType values
@@ -261,7 +300,6 @@ function Invoke-ParallelProcessing {
}
}
catch {
# Catch errors within the parallel task execution
$resultStatus = "Error: $($_.Exception.Message)"
$resultCode = 1
# Try to get an identifier
@@ -272,7 +310,6 @@ function Invoke-ParallelProcessing {
$resultIdentifier = "UnknownItemOnError"
}
WriteLog "Exception during parallel task '$localTaskType' for item '$resultIdentifier': $($_.Exception.ToString())"
# Enqueue the error status from the catch block
$localProgressQueue.Enqueue(@{ Identifier = $resultIdentifier; Status = $resultStatus })
}
@@ -284,7 +321,7 @@ function Invoke-ParallelProcessing {
# Return a consistent hashtable structure (final result)
return @{
Identifier = $resultIdentifier
Status = $resultStatus # Return the final status
Status = $resultStatus
ResultCode = $resultCode
DriverPath = $driverPathValue
}
@@ -292,7 +329,6 @@ function Invoke-ParallelProcessing {
} -ThrottleLimit $ThrottleLimit -AsJob
}
catch {
# Catch errors during the *creation* of the parallel jobs (e.g., module loading in main thread failed)
WriteLog "Error initiating ForEach-Object -Parallel: $($_.Exception.Message)"
# Update all items to show a general startup error
$errorStatus = "$ErrorStatusPrefix Failed to start processing"
@@ -302,7 +338,6 @@ function Invoke-ParallelProcessing {
Update-ListViewItemStatus -WindowObject $WindowObject -ListView $ListViewControl -IdentifierProperty $IdentifierProperty -IdentifierValue $identifier -StatusProperty $StatusProperty -StatusValue $errorStatus # Pass $WindowObject
})
}
# Exit the function as processing cannot proceed
return
}
@@ -334,7 +369,6 @@ function Invoke-ParallelProcessing {
}
$intermediateStatus = $statusUpdate.Status
if ($isUiMode) {
# Use the new $isUiMode flag
# Update the UI with the intermediate status
try {
WriteLog "Dispatching INTERMEDIATE status for '$intermediateIdentifier': '$intermediateStatus'"
@@ -361,7 +395,7 @@ function Invoke-ParallelProcessing {
$jobHandled = $false
if ($completedJob.State -eq 'Failed') {
$jobHandled = $true
$finalIdentifier = "UnknownJob" # Placeholder
$finalIdentifier = "UnknownJob"
WriteLog "Job $($completedJob.Id) failed: $($completedJob.Error)"
$finalStatus = "$ErrorStatusPrefix Job Failed"
$finalResultCode = 1
@@ -438,12 +472,11 @@ function Invoke-ParallelProcessing {
# Remove the completed/failed job from the list and clean it up
$jobs = $jobs | Where-Object { $_.Id -ne $completedJob.Id }
Remove-Job -Job $completedJob -Force -ErrorAction SilentlyContinue
} # End foreach completedJob
} # End if ($completedJobs)
}
}
# 3. Allow UI events to process and sleep briefly
if ($isUiMode) {
# Use the new $isUiMode flag
# Only sleep if jobs are still running AND the queue is empty (to avoid delaying UI updates)
if ($jobs.Count -gt 0 -and $progressQueue.IsEmpty) {
$WindowObject.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action] { }) | Out-Null
@@ -460,9 +493,8 @@ function Invoke-ParallelProcessing {
Start-Sleep -Milliseconds 100
}
}
# If jobs are done AND queue is empty, the loop condition will terminate
} # End while ($jobs.Count -gt 0 -or -not $progressQueue.IsEmpty)
}
# Final cleanup of any remaining jobs (shouldn't be necessary with this loop logic, but good practice)
if ($jobs.Count -gt 0) {
@@ -471,7 +503,6 @@ function Invoke-ParallelProcessing {
}
if ($isUiMode) {
# Use the new $isUiMode flag
WriteLog "Invoke-ParallelProcessing finished for ListView '$($ListViewControl.Name)'."
# Final overall progress update
$WindowObject.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [Action] {
@@ -1,6 +1,12 @@
# # Import the common core module for logging
# Import-Module "$PSScriptRoot\FFU.Common.Core.psm1"
<#
.SYNOPSIS
Provides functions for interacting with WinGet and the Microsoft Store to find, download, and configure applications.
.DESCRIPTION
This module contains a set of functions designed to automate application management using the WinGet package manager and the Microsoft Store.
It supports checking for and installing WinGet, downloading applications, handling different application types (Win32 and UWP), and generating silent installation commands for Win32 applications.
This module is used by both the build script (BuildFFUVM.ps1) and the UI (BuildFFUVM_UI.ps1) to manage application downloads and configuration.
#>
function Get-Application {
[CmdletBinding()]
param (