mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 10:19:36 -06:00
Refactors application management to a new module
Moves ListView manipulation, BYO application import/export, and copy task logic from the main UI script and core UI module into a new `FFUUI.Core.Applications` module. This improves code organization and modularity for application-related features.
This commit is contained in:
@@ -474,119 +474,6 @@ function Update-WingetVersionFields {
|
||||
})
|
||||
}
|
||||
|
||||
# Function to update priorities sequentially in a ListView
|
||||
function Update-ListViewPriorities {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$currentPriority = 1
|
||||
foreach ($item in $ListView.Items) {
|
||||
if ($null -ne $item -and $item.PSObject.Properties['Priority']) {
|
||||
$item.Priority = $currentPriority
|
||||
$currentPriority++
|
||||
}
|
||||
}
|
||||
$ListView.Items.Refresh()
|
||||
}
|
||||
|
||||
# Function to move selected item to the top
|
||||
function Move-ListViewItemTop {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -gt 0) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert(0, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item up one position
|
||||
function Move-ListViewItemUp {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -gt 0) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert($currentIndex - 1, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item down one position
|
||||
function Move-ListViewItemDown {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -lt ($ListView.Items.Count - 1)) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert($currentIndex + 1, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item to the bottom
|
||||
function Move-ListViewItemBottom {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -lt ($ListView.Items.Count - 1)) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Add($selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to update the enabled state of the Copy Apps button
|
||||
function Update-CopyButtonState {
|
||||
param(
|
||||
[psobject]$State
|
||||
)
|
||||
$listView = $State.Controls.lstApplications
|
||||
$copyButton = $State.Controls.btnCopyBYOApps
|
||||
if ($listView -and $copyButton) {
|
||||
$hasSource = $false
|
||||
foreach ($item in $listView.Items) {
|
||||
if ($null -ne $item -and $item.PSObject.Properties['Source'] -and -not [string]::IsNullOrWhiteSpace($item.Source)) {
|
||||
$hasSource = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
$copyButton.IsEnabled = $hasSource
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$window.Add_Loaded({
|
||||
# Pass the state object to all initialization functions
|
||||
$script:uiState.Window = $window
|
||||
@@ -1763,100 +1650,6 @@ $window.Add_Loaded({
|
||||
|
||||
})
|
||||
|
||||
# Function to remove application and reorder priorities
|
||||
function Remove-Application {
|
||||
param(
|
||||
$priority,
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
$listView = $State.Controls.lstApplications
|
||||
|
||||
# Remove the item with the specified priority
|
||||
$itemToRemove = $listView.Items | Where-Object { $_.Priority -eq $priority } | Select-Object -First 1
|
||||
if ($itemToRemove) {
|
||||
$listView.Items.Remove($itemToRemove)
|
||||
# Reorder priorities for remaining items
|
||||
Update-ListViewPriorities -ListView $listView
|
||||
# Update the Copy Apps button state
|
||||
Update-CopyButtonState -State $State
|
||||
}
|
||||
}
|
||||
|
||||
# Function to save BYO applications to JSON
|
||||
function Save-BYOApplicationList {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Path,
|
||||
[Parameter(Mandatory)]
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
$listView = $State.Controls.lstApplications
|
||||
if (-not $listView -or $listView.Items.Count -eq 0) {
|
||||
[System.Windows.MessageBox]::Show("No applications to save.", "Save Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
# Ensure items are sorted by current priority before saving
|
||||
# Exclude CopyStatus when saving
|
||||
$applications = $listView.Items | Sort-Object Priority | Select-Object Priority, Name, CommandLine, Arguments, Source
|
||||
$applications | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Force -Encoding UTF8
|
||||
[System.Windows.MessageBox]::Show("Applications saved successfully to `"$Path`".", "Save Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
}
|
||||
catch {
|
||||
[System.Windows.MessageBox]::Show("Failed to save applications: $_", "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error)
|
||||
}
|
||||
}
|
||||
|
||||
# Function to load BYO applications from JSON
|
||||
function Import-BYOApplicationList {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Path,
|
||||
[Parameter(Mandatory)]
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
if (-not (Test-Path $Path)) {
|
||||
[System.Windows.MessageBox]::Show("Application list file not found at `"$Path`".", "Import Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$applications = Get-Content -Path $Path -Raw | ConvertFrom-Json
|
||||
$listView = $State.Controls.lstApplications
|
||||
$listView.Items.Clear()
|
||||
|
||||
# Add items and sort by priority from the file
|
||||
$sortedApps = $applications | Sort-Object Priority
|
||||
foreach ($app in $sortedApps) {
|
||||
# Ensure all properties exist, add CopyStatus
|
||||
$appObject = [PSCustomObject]@{
|
||||
Priority = $app.Priority # Keep original priority for now
|
||||
Name = $app.Name
|
||||
CommandLine = $app.CommandLine
|
||||
Arguments = if ($app.PSObject.Properties['Arguments']) { $app.Arguments } else { "" } # Handle missing Arguments
|
||||
Source = $app.Source
|
||||
CopyStatus = "" # Initialize CopyStatus
|
||||
}
|
||||
$listView.Items.Add($appObject)
|
||||
}
|
||||
|
||||
# Reorder priorities sequentially after loading
|
||||
Update-ListViewPriorities -ListView $listView
|
||||
# Update the Copy Apps button state
|
||||
Update-CopyButtonState -State $State
|
||||
|
||||
[System.Windows.MessageBox]::Show("Applications imported successfully from `"$Path`".", "Import Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
}
|
||||
catch {
|
||||
[System.Windows.MessageBox]::Show("Failed to import applications: $_", "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error)
|
||||
}
|
||||
}
|
||||
|
||||
# Button: Build FFU
|
||||
$btnRun = $window.FindName('btnRun')
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
# FFU UI Core Applications Module
|
||||
# Contains UI-layer logic for the "Bring Your Own Apps" and related features.
|
||||
|
||||
# Function to update priorities sequentially in a ListView
|
||||
function Update-ListViewPriorities {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$currentPriority = 1
|
||||
foreach ($item in $ListView.Items) {
|
||||
if ($null -ne $item -and $item.PSObject.Properties['Priority']) {
|
||||
$item.Priority = $currentPriority
|
||||
$currentPriority++
|
||||
}
|
||||
}
|
||||
$ListView.Items.Refresh()
|
||||
}
|
||||
|
||||
# Function to move selected item to the top
|
||||
function Move-ListViewItemTop {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -gt 0) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert(0, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item up one position
|
||||
function Move-ListViewItemUp {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -gt 0) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert($currentIndex - 1, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item down one position
|
||||
function Move-ListViewItemDown {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -lt ($ListView.Items.Count - 1)) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Insert($currentIndex + 1, $selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to move selected item to the bottom
|
||||
function Move-ListViewItemBottom {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[System.Windows.Controls.ListView]$ListView
|
||||
)
|
||||
|
||||
$selectedItem = $ListView.SelectedItem
|
||||
if ($null -eq $selectedItem) { return }
|
||||
|
||||
$currentIndex = $ListView.Items.IndexOf($selectedItem)
|
||||
if ($currentIndex -lt ($ListView.Items.Count - 1)) {
|
||||
$ListView.Items.RemoveAt($currentIndex)
|
||||
$ListView.Items.Add($selectedItem)
|
||||
$ListView.SelectedItem = $selectedItem
|
||||
Update-ListViewPriorities -ListView $ListView
|
||||
}
|
||||
}
|
||||
|
||||
# Function to update the enabled state of the Copy Apps button
|
||||
function Update-CopyButtonState {
|
||||
param(
|
||||
[psobject]$State
|
||||
)
|
||||
$listView = $State.Controls.lstApplications
|
||||
$copyButton = $State.Controls.btnCopyBYOApps
|
||||
if ($listView -and $copyButton) {
|
||||
$hasSource = $false
|
||||
foreach ($item in $listView.Items) {
|
||||
if ($null -ne $item -and $item.PSObject.Properties['Source'] -and -not [string]::IsNullOrWhiteSpace($item.Source)) {
|
||||
$hasSource = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
$copyButton.IsEnabled = $hasSource
|
||||
}
|
||||
}
|
||||
|
||||
# Function to remove application and reorder priorities
|
||||
function Remove-Application {
|
||||
param(
|
||||
$priority,
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
$listView = $State.Controls.lstApplications
|
||||
|
||||
# Remove the item with the specified priority
|
||||
$itemToRemove = $listView.Items | Where-Object { $_.Priority -eq $priority } | Select-Object -First 1
|
||||
if ($itemToRemove) {
|
||||
$listView.Items.Remove($itemToRemove)
|
||||
# Reorder priorities for remaining items
|
||||
Update-ListViewPriorities -ListView $listView
|
||||
# Update the Copy Apps button state
|
||||
Update-CopyButtonState -State $State
|
||||
}
|
||||
}
|
||||
|
||||
# Function to save BYO applications to JSON
|
||||
function Save-BYOApplicationList {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Path,
|
||||
[Parameter(Mandatory)]
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
$listView = $State.Controls.lstApplications
|
||||
if (-not $listView -or $listView.Items.Count -eq 0) {
|
||||
[System.Windows.MessageBox]::Show("No applications to save.", "Save Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
# Ensure items are sorted by current priority before saving
|
||||
# Exclude CopyStatus when saving
|
||||
$applications = $listView.Items | Sort-Object Priority | Select-Object Priority, Name, CommandLine, Arguments, Source
|
||||
$applications | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Force -Encoding UTF8
|
||||
[System.Windows.MessageBox]::Show("Applications saved successfully to `"$Path`".", "Save Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
}
|
||||
catch {
|
||||
[System.Windows.MessageBox]::Show("Failed to save applications: $_", "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error)
|
||||
}
|
||||
}
|
||||
|
||||
# Function to load BYO applications from JSON
|
||||
function Import-BYOApplicationList {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Path,
|
||||
[Parameter(Mandatory)]
|
||||
[psobject]$State
|
||||
)
|
||||
|
||||
if (-not (Test-Path $Path)) {
|
||||
[System.Windows.MessageBox]::Show("Application list file not found at `"$Path`".", "Import Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$applications = Get-Content -Path $Path -Raw | ConvertFrom-Json
|
||||
$listView = $State.Controls.lstApplications
|
||||
$listView.Items.Clear()
|
||||
|
||||
# Add items and sort by priority from the file
|
||||
$sortedApps = $applications | Sort-Object Priority
|
||||
foreach ($app in $sortedApps) {
|
||||
# Ensure all properties exist, add CopyStatus
|
||||
$appObject = [PSCustomObject]@{
|
||||
Priority = $app.Priority # Keep original priority for now
|
||||
Name = $app.Name
|
||||
CommandLine = $app.CommandLine
|
||||
Arguments = if ($app.PSObject.Properties['Arguments']) { $app.Arguments } else { "" } # Handle missing Arguments
|
||||
Source = $app.Source
|
||||
CopyStatus = "" # Initialize CopyStatus
|
||||
}
|
||||
$listView.Items.Add($appObject)
|
||||
}
|
||||
|
||||
# Reorder priorities sequentially after loading
|
||||
Update-ListViewPriorities -ListView $listView
|
||||
# Update the Copy Apps button state
|
||||
Update-CopyButtonState -State $State
|
||||
|
||||
[System.Windows.MessageBox]::Show("Applications imported successfully from `"$Path`".", "Import Applications", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Information)
|
||||
}
|
||||
catch {
|
||||
[System.Windows.MessageBox]::Show("Failed to import applications: $_", "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error)
|
||||
}
|
||||
}
|
||||
|
||||
# Function to copy a single BYO application (Modified for ForEach-Object -Parallel)
|
||||
function Start-CopyBYOApplicationTask {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[PSCustomObject]$ApplicationItemData, # Pass data, not the UI object
|
||||
[Parameter(Mandatory)]
|
||||
[string]$AppsPath, # Pass necessary path
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue # Add queue parameter
|
||||
# REMOVED: UI-related parameters
|
||||
)
|
||||
|
||||
$priority = $ApplicationItemData.Priority
|
||||
$appName = $ApplicationItemData.Name
|
||||
$commandLine = $ApplicationItemData.CommandLine
|
||||
$arguments = $ApplicationItemData.Arguments
|
||||
$sourcePath = $ApplicationItemData.Source
|
||||
$status = "Starting..." # Initial local status
|
||||
$success = $false
|
||||
|
||||
# Initial status update
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($AppsPath)) {
|
||||
$status = "Error: Apps Path not set"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copy error for $($appName): Apps Path not set."
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($sourcePath)) {
|
||||
$status = "No source specified"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
# This isn't an error, just nothing to do. Consider it success.
|
||||
$success = $true
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
if (-not (Test-Path -Path $sourcePath -PathType Container)) {
|
||||
$status = "Error: Source path not found"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copy error for $($appName): Source path '$sourcePath' not found."
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
$win32BasePath = Join-Path -Path $AppsPath -ChildPath "Win32"
|
||||
$destinationPath = Join-Path -Path $win32BasePath -ChildPath $appName
|
||||
|
||||
try {
|
||||
# Check destination
|
||||
if (Test-Path -Path $destinationPath -PathType Container) {
|
||||
$folderSize = (Get-ChildItem -Path $destinationPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
||||
if ($folderSize -gt 1MB) {
|
||||
$status = "Already copied"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Skipping copy for $($appName): Destination '$destinationPath' exists and has content."
|
||||
$success = $true
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
else {
|
||||
WriteLog "Destination '$destinationPath' exists but is empty/small. Proceeding with copy."
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure base directory exists
|
||||
if (-not (Test-Path -Path $win32BasePath -PathType Container)) {
|
||||
New-Item -Path $win32BasePath -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Created directory: $win32BasePath"
|
||||
}
|
||||
|
||||
# Perform the copy
|
||||
$status = "Copying..."
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copying '$sourcePath' to '$destinationPath'..."
|
||||
Copy-Item -Path $sourcePath -Destination $destinationPath -Recurse -Force -ErrorAction Stop
|
||||
$status = "Copied successfully"
|
||||
$success = $true
|
||||
WriteLog "Successfully copied '$appName' to '$destinationPath'."
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Update (or create) UserAppList.json with the copied application
|
||||
# ------------------------------------------------------------------
|
||||
try {
|
||||
WriteLog "Updating UserAppList.json for '$appName'..."
|
||||
$userAppListPath = Join-Path -Path $AppsPath -ChildPath 'UserAppList.json'
|
||||
|
||||
# Build the new entry
|
||||
$newEntry = [pscustomobject]@{
|
||||
Priority = $priority
|
||||
Name = $appName
|
||||
CommandLine = $commandLine
|
||||
Arguments = $arguments
|
||||
Source = $sourcePath
|
||||
}
|
||||
|
||||
# Load existing list if present, ensuring it's always an array
|
||||
if (Test-Path -Path $userAppListPath) {
|
||||
try {
|
||||
# Attempt to load and ensure it's an array
|
||||
$appList = @(Get-Content -Path $userAppListPath -Raw | ConvertFrom-Json -ErrorAction Stop)
|
||||
}
|
||||
catch {
|
||||
WriteLog "Warning: Could not parse '$userAppListPath' or it's not a valid JSON array. Initializing as empty array. Error: $($_.Exception.Message)"
|
||||
$appList = @() # Initialize as empty array on error
|
||||
}
|
||||
}
|
||||
else {
|
||||
$appList = @() # Initialize as empty array if file doesn't exist
|
||||
}
|
||||
|
||||
# Ensure $appList is an array even if ConvertFrom-Json returned $null or a single object somehow
|
||||
if ($null -eq $appList -or $appList -isnot [array]) {
|
||||
# If it was a single object, wrap it in an array. Otherwise, start fresh.
|
||||
$appList = if ($null -ne $appList) { @($appList) } else { @() }
|
||||
}
|
||||
|
||||
# Skip adding if an entry with the same Name already exists
|
||||
if (-not ($appList | Where-Object { $_.Name -eq $newEntry.Name })) {
|
||||
# Now $appList is guaranteed to be an array, so += is safe
|
||||
$appList += $newEntry
|
||||
# Sort by Priority before saving
|
||||
$sortedAppList = $appList | Sort-Object Priority
|
||||
$sortedAppList | ConvertTo-Json -Depth 10 | Set-Content -Path $userAppListPath -Encoding UTF8
|
||||
WriteLog "Added '$($newEntry.Name)' to '$userAppListPath'."
|
||||
}
|
||||
else {
|
||||
WriteLog "'$appName' already exists in '$userAppListPath'."
|
||||
}
|
||||
}
|
||||
catch {
|
||||
WriteLog "Failed to update UserAppList.json for '$appName': $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
}
|
||||
catch {
|
||||
$errorMessage = $_.Exception.Message
|
||||
$status = "Error: $($errorMessage)"
|
||||
WriteLog "Copy error for $($appName): $($errorMessage)"
|
||||
$success = $false
|
||||
# Enqueue error status
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
}
|
||||
|
||||
# Enqueue final success status if applicable
|
||||
if ($success) {
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
}
|
||||
|
||||
# Return the final status
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function *
|
||||
@@ -67,6 +67,7 @@ RequiredModules = @('..\FFU.Common\FFU.Common.psd1')
|
||||
|
||||
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
|
||||
NestedModules = @('FFUUI.Core.Shared.psm1',
|
||||
'FFUUI.Core.Applications.psm1',
|
||||
'FFUUI.Core.Drivers.psm1',
|
||||
'FFUUI.Core.Drivers.Dell.psm1',
|
||||
'FFUUI.Core.Drivers.HP.psm1',
|
||||
|
||||
@@ -482,159 +482,6 @@ function Get-USBDrives {
|
||||
}
|
||||
}
|
||||
|
||||
# Function to copy a single BYO application (Modified for ForEach-Object -Parallel)
|
||||
function Start-CopyBYOApplicationTask {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[PSCustomObject]$ApplicationItemData, # Pass data, not the UI object
|
||||
[Parameter(Mandatory)]
|
||||
[string]$AppsPath, # Pass necessary path
|
||||
[Parameter(Mandatory = $true)]
|
||||
[System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue # Add queue parameter
|
||||
# REMOVED: UI-related parameters
|
||||
)
|
||||
|
||||
$priority = $ApplicationItemData.Priority
|
||||
$appName = $ApplicationItemData.Name
|
||||
$commandLine = $ApplicationItemData.CommandLine
|
||||
$arguments = $ApplicationItemData.Arguments
|
||||
$sourcePath = $ApplicationItemData.Source
|
||||
$status = "Starting..." # Initial local status
|
||||
$success = $false
|
||||
|
||||
# Initial status update
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($AppsPath)) {
|
||||
$status = "Error: Apps Path not set"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copy error for $($appName): Apps Path not set."
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($sourcePath)) {
|
||||
$status = "No source specified"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
# This isn't an error, just nothing to do. Consider it success.
|
||||
$success = $true
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
if (-not (Test-Path -Path $sourcePath -PathType Container)) {
|
||||
$status = "Error: Source path not found"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copy error for $($appName): Source path '$sourcePath' not found."
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
$win32BasePath = Join-Path -Path $AppsPath -ChildPath "Win32"
|
||||
$destinationPath = Join-Path -Path $win32BasePath -ChildPath $appName
|
||||
|
||||
try {
|
||||
# Check destination
|
||||
if (Test-Path -Path $destinationPath -PathType Container) {
|
||||
$folderSize = (Get-ChildItem -Path $destinationPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
||||
if ($folderSize -gt 1MB) {
|
||||
$status = "Already copied"
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Skipping copy for $($appName): Destination '$destinationPath' exists and has content."
|
||||
$success = $true
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
else {
|
||||
WriteLog "Destination '$destinationPath' exists but is empty/small. Proceeding with copy."
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure base directory exists
|
||||
if (-not (Test-Path -Path $win32BasePath -PathType Container)) {
|
||||
New-Item -Path $win32BasePath -ItemType Directory -Force | Out-Null
|
||||
WriteLog "Created directory: $win32BasePath"
|
||||
}
|
||||
|
||||
# Perform the copy
|
||||
$status = "Copying..."
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
WriteLog "Copying '$sourcePath' to '$destinationPath'..."
|
||||
Copy-Item -Path $sourcePath -Destination $destinationPath -Recurse -Force -ErrorAction Stop
|
||||
$status = "Copied successfully"
|
||||
$success = $true
|
||||
WriteLog "Successfully copied '$appName' to '$destinationPath'."
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Update (or create) UserAppList.json with the copied application
|
||||
# ------------------------------------------------------------------
|
||||
try {
|
||||
WriteLog "Updating UserAppList.json for '$appName'..."
|
||||
$userAppListPath = Join-Path -Path $AppsPath -ChildPath 'UserAppList.json'
|
||||
|
||||
# Build the new entry
|
||||
$newEntry = [pscustomobject]@{
|
||||
Priority = $priority
|
||||
Name = $appName
|
||||
CommandLine = $commandLine
|
||||
Arguments = $arguments
|
||||
Source = $sourcePath
|
||||
}
|
||||
|
||||
# Load existing list if present, ensuring it's always an array
|
||||
if (Test-Path -Path $userAppListPath) {
|
||||
try {
|
||||
# Attempt to load and ensure it's an array
|
||||
$appList = @(Get-Content -Path $userAppListPath -Raw | ConvertFrom-Json -ErrorAction Stop)
|
||||
}
|
||||
catch {
|
||||
WriteLog "Warning: Could not parse '$userAppListPath' or it's not a valid JSON array. Initializing as empty array. Error: $($_.Exception.Message)"
|
||||
$appList = @() # Initialize as empty array on error
|
||||
}
|
||||
}
|
||||
else {
|
||||
$appList = @() # Initialize as empty array if file doesn't exist
|
||||
}
|
||||
|
||||
# Ensure $appList is an array even if ConvertFrom-Json returned $null or a single object somehow
|
||||
if ($null -eq $appList -or $appList -isnot [array]) {
|
||||
# If it was a single object, wrap it in an array. Otherwise, start fresh.
|
||||
$appList = if ($null -ne $appList) { @($appList) } else { @() }
|
||||
}
|
||||
|
||||
# Skip adding if an entry with the same Name already exists
|
||||
if (-not ($appList | Where-Object { $_.Name -eq $newEntry.Name })) {
|
||||
# Now $appList is guaranteed to be an array, so += is safe
|
||||
$appList += $newEntry
|
||||
# Sort by Priority before saving
|
||||
$sortedAppList = $appList | Sort-Object Priority
|
||||
$sortedAppList | ConvertTo-Json -Depth 10 | Set-Content -Path $userAppListPath -Encoding UTF8
|
||||
WriteLog "Added '$($newEntry.Name)' to '$userAppListPath'."
|
||||
}
|
||||
else {
|
||||
WriteLog "'$appName' already exists in '$userAppListPath'."
|
||||
}
|
||||
}
|
||||
catch {
|
||||
WriteLog "Failed to update UserAppList.json for '$appName': $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
}
|
||||
catch {
|
||||
$errorMessage = $_.Exception.Message
|
||||
$status = "Error: $($errorMessage)"
|
||||
WriteLog "Copy error for $($appName): $($errorMessage)"
|
||||
$success = $false
|
||||
# Enqueue error status
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
}
|
||||
|
||||
# Enqueue final success status if applicable
|
||||
if ($success) {
|
||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appName -Status $status
|
||||
}
|
||||
|
||||
# Return the final status
|
||||
return [PSCustomObject]@{ Name = $appName; Status = $status; Success = $success }
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# SECTION: UI Configuration
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user