mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
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:
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user