Allow custom BYO app list file paths in UI

Updates the FFU UI and orchestration scripts to allow users to specify custom file paths for their Bring Your Own (BYO) app lists, rather than forcing the use of `UserAppList.json` in a specific directory.

Also modifies the orchestration to sync this custom path via `AppInstallConfig.json` so that the runtime orchestration phase resolves the correct file name and path during installation. Refreshes the Apps ISO if the custom BYO app list is updated.
This commit is contained in:
rbalsleyMSFT
2026-03-18 18:59:28 -07:00
parent b388eae439
commit eac8be3d31
12 changed files with 237 additions and 60 deletions
@@ -1,3 +1,11 @@
# Allow Orchestrator.ps1 to override the app list file paths while preserving legacy defaults.
param(
[Parameter()]
[string]$wingetAppsJsonFile = (Join-Path -Path $PSScriptRoot -ChildPath "WinGetWin32Apps.json"),
[Parameter()]
[string]$userAppsJsonFile = (Join-Path -Path (Split-Path -Parent $PSScriptRoot) -ChildPath "UserAppList.json")
)
function Invoke-Process { function Invoke-Process {
[CmdletBinding(SupportsShouldProcess)] [CmdletBinding(SupportsShouldProcess)]
param param
@@ -247,11 +255,6 @@ function Install-Applications {
} }
} }
# Define paths for the JSON files
$wingetAppsJsonFile = "$PSScriptRoot\WinGetWin32Apps.json"
# Look for UserAppList.json one directory level up from the script's location. This keeps the user specific json files (AppList.json and UserAppList.json in the Apps dir)
$userAppsJsonFile = Join-Path -Path (Split-Path -Parent $PSScriptRoot) -ChildPath "UserAppList.json"
# Initialize empty arrays for apps from each source # Initialize empty arrays for apps from each source
$wingetApps = @() $wingetApps = @()
$userApps = @() $userApps = @()
@@ -286,9 +289,9 @@ if ($wingetApps.Count -gt 0) {
Install-Applications -apps $wingetApps Install-Applications -apps $wingetApps
} }
# Read the UserAppList.json file if it exists # Read the configured BYO app list file if it exists
if (Test-Path -Path $userAppsJsonFile) { if (Test-Path -Path $userAppsJsonFile) {
Write-Host "Processing UserAppList.json..." Write-Host "Processing $(Split-Path -Path $userAppsJsonFile -Leaf)..."
try { try {
$userContent = Get-Content -Path $userAppsJsonFile -Raw -ErrorAction Stop | ConvertFrom-Json $userContent = Get-Content -Path $userAppsJsonFile -Raw -ErrorAction Stop | ConvertFrom-Json
if ($userContent -is [array]) { if ($userContent -is [array]) {
@@ -296,19 +299,19 @@ if (Test-Path -Path $userAppsJsonFile) {
Write-Host "Found $(($userApps | Measure-Object).Count) user-defined apps." Write-Host "Found $(($userApps | Measure-Object).Count) user-defined apps."
} }
elseif ($userContent) { elseif ($userContent) {
$userApps = @($userContent) # Ensure it's an array $userApps = @($userContent)
Write-Host "Found 1 user-defined app." Write-Host "Found 1 user-defined app."
} }
else { else {
Write-Host "UserAppList.json is empty or invalid." Write-Host "$(Split-Path -Path $userAppsJsonFile -Leaf) is empty or invalid."
} }
} }
catch { catch {
Write-Error "Failed to read or parse UserAppList.json file: $_" Write-Error "Failed to read or parse BYO app list file '$userAppsJsonFile': $_"
} }
} }
else { else {
Write-Host "UserAppList.json file not found. Skipping." Write-Host "BYO app list file not found at $userAppsJsonFile. Skipping."
} }
# Install User apps if any were found # Install User apps if any were found
@@ -28,6 +28,23 @@ Write-Host "---------------------------------------------------" -ForegroundColo
# Define the path to the scripts # Define the path to the scripts
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition $scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
# Resolve the configured BYO app list path for runtime orchestration.
$appInstallConfigPath = Join-Path -Path $scriptPath -ChildPath "AppInstallConfig.json"
$userAppsJsonFile = Join-Path -Path (Split-Path -Parent $scriptPath) -ChildPath "UserAppList.json"
if (Test-Path -Path $appInstallConfigPath) {
try {
$appInstallConfig = Get-Content -Path $appInstallConfigPath -Raw | ConvertFrom-Json
if ($null -ne $appInstallConfig -and $appInstallConfig.PSObject.Properties.Match('UserAppListPath').Count -gt 0 -and -not [string]::IsNullOrWhiteSpace($appInstallConfig.UserAppListPath)) {
$userAppsJsonFile = $appInstallConfig.UserAppListPath
Write-Host "Using BYO app list path from AppInstallConfig.json: $userAppsJsonFile"
}
}
catch {
Write-Host "Failed to parse AppInstallConfig.json. Falling back to default BYO app list path."
}
}
# Define the list of scripts to run # Define the list of scripts to run
$scriptList = @( $scriptList = @(
"Install-LTSCUpdate.ps1", "Install-LTSCUpdate.ps1",
@@ -51,7 +68,6 @@ foreach ($script in $scriptList) {
switch ($script) { switch ($script) {
"Install-Win32Apps.ps1" { "Install-Win32Apps.ps1" {
$wingetAppsJsonFile = Join-Path -Path $scriptPath -ChildPath "WinGetWin32Apps.json" $wingetAppsJsonFile = Join-Path -Path $scriptPath -ChildPath "WinGetWin32Apps.json"
$userAppsJsonFile = Join-Path -Path (Split-Path -Parent $scriptPath) -ChildPath "UserAppList.json"
if (-not (Test-Path -Path $wingetAppsJsonFile) -and -not (Test-Path -Path $userAppsJsonFile)) { if (-not (Test-Path -Path $wingetAppsJsonFile) -and -not (Test-Path -Path $userAppsJsonFile)) {
$shouldRun = $false $shouldRun = $false
} }
@@ -69,10 +85,15 @@ foreach ($script in $scriptList) {
Write-Host "---------------------------------------------------" -ForegroundColor Yellow Write-Host "---------------------------------------------------" -ForegroundColor Yellow
Write-Host " Running script: $script " -ForegroundColor Yellow Write-Host " Running script: $script " -ForegroundColor Yellow
Write-Host "---------------------------------------------------" -ForegroundColor Yellow Write-Host "---------------------------------------------------" -ForegroundColor Yellow
# Run script and wait for it to finish # Run script and wait for it to finish.
if ($script -eq "Install-Win32Apps.ps1") {
& $scriptFile -UserAppsJsonFile $userAppsJsonFile
}
else {
& $scriptFile & $scriptFile
} }
} }
}
# Invoke-AppsScript.ps1 if it exists and AppsScriptVariables.json is present # Invoke-AppsScript.ps1 if it exists and AppsScriptVariables.json is present
$appsScriptFile = Join-Path -Path $scriptPath -ChildPath "Invoke-AppsScript.ps1" $appsScriptFile = Join-Path -Path $scriptPath -ChildPath "Invoke-AppsScript.ps1"
+77 -5
View File
@@ -633,6 +633,7 @@ if (-not $AppsPath) { $AppsPath = "$FFUDevelopmentPath\Apps" }
if (-not $AppListPath) { $AppListPath = "$AppsPath\AppList.json" } if (-not $AppListPath) { $AppListPath = "$AppsPath\AppList.json" }
if (-not $UserAppListPath) { $UserAppListPath = "$AppsPath\UserAppList.json" } if (-not $UserAppListPath) { $UserAppListPath = "$AppsPath\UserAppList.json" }
if (-not $OrchestrationPath) { $OrchestrationPath = "$AppsPath\Orchestration" } if (-not $OrchestrationPath) { $OrchestrationPath = "$AppsPath\Orchestration" }
if (-not $appInstallConfigPath) { $appInstallConfigPath = "$OrchestrationPath\AppInstallConfig.json" }
if (-not $wingetWin32jsonFile) { $wingetWin32jsonFile = "$OrchestrationPath\WinGetWin32Apps.json" } if (-not $wingetWin32jsonFile) { $wingetWin32jsonFile = "$OrchestrationPath\WinGetWin32Apps.json" }
if (-not $InstallOfficePath) { $InstallOfficePath = "$OrchestrationPath\Install-Office.ps1" } if (-not $InstallOfficePath) { $InstallOfficePath = "$OrchestrationPath\Install-Office.ps1" }
if (-not $InstallDefenderPath) { $InstallDefenderPath = "$OrchestrationPath\Update-Defender.ps1" } if (-not $InstallDefenderPath) { $InstallDefenderPath = "$OrchestrationPath\Update-Defender.ps1" }
@@ -2437,6 +2438,54 @@ function Save-KB {
return $fileName return $fileName
} }
function Sync-UserAppListForOrchestration {
param(
[Parameter(Mandatory)]
[string]$SourcePath,
[Parameter(Mandatory)]
[string]$AppsPath,
[Parameter(Mandatory)]
[string]$OrchestrationPath,
[Parameter(Mandatory)]
[string]$AppInstallConfigPath
)
# Ensure the orchestration folder exists before writing runtime configuration.
if (-not (Test-Path -Path $OrchestrationPath -PathType Container)) {
New-Item -Path $OrchestrationPath -ItemType Directory -Force | Out-Null
}
# Persist the runtime BYO app list path so Orchestrator can honor custom file names.
$appInstallConfig = [ordered]@{
UserAppListPath = $null
}
if (-not [string]::IsNullOrWhiteSpace($SourcePath) -and (Test-Path -Path $SourcePath -PathType Leaf)) {
$stagedUserAppListName = Split-Path -Path $SourcePath -Leaf
$stagedUserAppListPath = Join-Path -Path $AppsPath -ChildPath $stagedUserAppListName
if (-not [string]::Equals([System.IO.Path]::GetFullPath($SourcePath), [System.IO.Path]::GetFullPath($stagedUserAppListPath), [System.StringComparison]::OrdinalIgnoreCase)) {
Copy-Item -Path $SourcePath -Destination $stagedUserAppListPath -Force | Out-Null
WriteLog "Staged BYO app list for orchestration: $SourcePath -> $stagedUserAppListPath"
}
else {
WriteLog "Using BYO app list already staged at $stagedUserAppListPath"
}
$appInstallConfig.UserAppListPath = "D:\$stagedUserAppListName"
}
elseif (Test-Path -Path (Join-Path -Path $AppsPath -ChildPath 'UserAppList.json') -PathType Leaf) {
$appInstallConfig.UserAppListPath = "D:\UserAppList.json"
WriteLog "Using default BYO app list path for orchestration."
}
else {
WriteLog "No BYO app list found at configured path '$SourcePath'."
}
$appInstallConfig | ConvertTo-Json | Set-Content -Path $AppInstallConfigPath -Encoding UTF8
WriteLog "Wrote app install config to $AppInstallConfigPath"
}
function New-AppsISO { function New-AppsISO {
#Create Apps ISO file #Create Apps ISO file
$OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe" $OSCDIMG = "$adkpath`Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe"
@@ -6082,8 +6131,20 @@ if ($InstallApps) {
Set-Progress -Percentage 6 -Message "Downloading and preparing applications..." Set-Progress -Percentage 6 -Message "Downloading and preparing applications..."
if (Test-Path -Path $AppsISO) { if (Test-Path -Path $AppsISO) {
WriteLog "Apps ISO exists at: $AppsISO" WriteLog "Apps ISO exists at: $AppsISO"
# Refresh the Apps ISO when a BYO app list is present so the staged manifest
# and AppInstallConfig.json stay in sync with the current build inputs.
if (Test-Path -Path $UserAppListPath) {
WriteLog "Configured BYO app list detected. Refreshing Apps ISO to include the latest BYO app list data."
Sync-UserAppListForOrchestration -SourcePath $UserAppListPath -AppsPath $AppsPath -OrchestrationPath $OrchestrationPath -AppInstallConfigPath $appInstallConfigPath
Remove-Item -Path $AppsISO -Force -ErrorAction SilentlyContinue
New-AppsISO
WriteLog "Apps ISO refreshed to include the latest BYO app list data."
}
else {
WriteLog "Will use existing ISO" WriteLog "Will use existing ISO"
} }
}
else { else {
try { try {
#Check for and download WinGet applications #Check for and download WinGet applications
@@ -6125,7 +6186,7 @@ if ($InstallApps) {
# If there are no existing apps, use the original AppList.json directly # If there are no existing apps, use the original AppList.json directly
if (-not $hasExistingApps) { if (-not $hasExistingApps) {
WriteLog "No existing applications found. Using original AppList.json for all apps." WriteLog "No existing applications found. Using original AppList.json for all apps."
Get-Apps -AppList $AppListPath -AppsPath $AppsPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath -LogFilePath $LogFile -ThrottleLimit $Threads Get-Apps -AppList $AppListPath -AppsPath $AppsPath -UserAppListPath $UserAppListPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath -LogFilePath $LogFile -ThrottleLimit $Threads
} }
else { else {
# Compare apps in AppList.json with existing installations # Compare apps in AppList.json with existing installations
@@ -6197,7 +6258,7 @@ if ($InstallApps) {
# Download missing apps # Download missing apps
WriteLog "Downloading missing applications" WriteLog "Downloading missing applications"
Get-Apps -AppList $modifiedAppListPath -AppsPath $AppsPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath -LogFilePath $LogFile -ThrottleLimit $Threads Get-Apps -AppList $modifiedAppListPath -AppsPath $AppsPath -UserAppListPath $UserAppListPath -WindowsArch $WindowsArch -OrchestrationPath $OrchestrationPath -LogFilePath $LogFile -ThrottleLimit $Threads
# Cleanup modified app list # Cleanup modified app list
Remove-Item -Path $modifiedAppListPath -Force Remove-Item -Path $modifiedAppListPath -Force
@@ -6207,11 +6268,11 @@ if ($InstallApps) {
} }
} }
} }
# Check is UserAppList.json exists and output to the user which apps will be installed # Check if the configured BYO app list exists and output which apps will be installed.
# It's expected that the user will have already copied the applications and created the UserAppList.json file # It is expected that the user will have already copied the applications and created the BYO app list file.
if (Test-Path -Path $UserAppListPath) { if (Test-Path -Path $UserAppListPath) {
$userAppList = Get-Content -Path $UserAppListPath -Raw | ConvertFrom-Json $userAppList = Get-Content -Path $UserAppListPath -Raw | ConvertFrom-Json
WriteLog "UserAppList.json found, the following apps will be installed:" WriteLog "$(Split-Path -Path $UserAppListPath -Leaf) found, the following apps will be installed:"
foreach ($app in $userAppList) { foreach ($app in $userAppList) {
WriteLog "$($app.name)" WriteLog "$($app.name)"
} }
@@ -6525,6 +6586,9 @@ if ($InstallApps) {
WriteLog "InjectUnattend is true but source file missing: $unattendSource. Skipping unattend injection." WriteLog "InjectUnattend is true but source file missing: $unattendSource. Skipping unattend injection."
} }
} }
# Stage the configured BYO app list and runtime config before creating the Apps ISO.
Sync-UserAppListForOrchestration -SourcePath $UserAppListPath -AppsPath $AppsPath -OrchestrationPath $OrchestrationPath -AppInstallConfigPath $appInstallConfigPath
Set-Progress -Percentage 10 -Message "Creating Apps ISO..." Set-Progress -Percentage 10 -Message "Creating Apps ISO..."
WriteLog "Creating $AppsISO file" WriteLog "Creating $AppsISO file"
New-AppsISO New-AppsISO
@@ -7434,6 +7498,7 @@ if ($InstallApps) {
Remove-Item -Path $AppsISO -Force -ErrorAction SilentlyContinue Remove-Item -Path $AppsISO -Force -ErrorAction SilentlyContinue
WriteLog 'Removal complete' WriteLog 'Removal complete'
} }
Sync-UserAppListForOrchestration -SourcePath $UserAppListPath -AppsPath $AppsPath -OrchestrationPath $OrchestrationPath -AppInstallConfigPath $appInstallConfigPath
New-AppsISO New-AppsISO
WriteLog "Apps ISO refreshed with LTSC CU assets" WriteLog "Apps ISO refreshed with LTSC CU assets"
} }
@@ -7621,6 +7686,13 @@ if (Test-Path -Path $wingetWin32jsonFile -PathType Leaf) {
Remove-Item -Path $wingetWin32jsonFile -Force -ErrorAction SilentlyContinue Remove-Item -Path $wingetWin32jsonFile -Force -ErrorAction SilentlyContinue
WriteLog "Removal complete" WriteLog "Removal complete"
} }
# Remove AppInstallConfig.json so it is always rebuilt next run
if (Test-Path -Path $appInstallConfigPath -PathType Leaf) {
WriteLog "Removing $appInstallConfigPath"
Remove-Item -Path $appInstallConfigPath -Force -ErrorAction SilentlyContinue
WriteLog "Removal complete"
}
#Set $LongPathsEnabled registry value back to original value. $LongPathsEnabled could be $null if the registry value was not found #Set $LongPathsEnabled registry value back to original value. $LongPathsEnabled could be $null if the registry value was not found
if ($null -eq $LongPathsEnabled) { if ($null -eq $LongPathsEnabled) {
Remove-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -ErrorAction SilentlyContinue Remove-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -ErrorAction SilentlyContinue
+20 -7
View File
@@ -270,19 +270,32 @@
</Grid> </Grid>
</StackPanel> </StackPanel>
<!-- AppList.json Path - Shows only when Install Applications is checked --> <!-- Winget AppList Path - Shows only when Install Applications is checked -->
<StackPanel x:Name="appListJsonPathPanel" Visibility="Collapsed" Margin="25,5,5,10"> <StackPanel x:Name="appListJsonPathPanel" Visibility="Collapsed" Margin="25,5,5,10">
<TextBlock Text="AppList.json Path:" Margin="0,0,0,5" ToolTip="Path to the AppList.json file"/> <TextBlock Text="Winget AppList Path:" Margin="0,0,0,5" ToolTip="Path to the Winget AppList JSON file"/>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox x:Name="txtAppListJsonPath" Grid.Column="0" VerticalAlignment="Center" ToolTip="Path to the AppList.json file"/> <TextBox x:Name="txtAppListJsonPath" Grid.Column="0" VerticalAlignment="Center" ToolTip="Path to the Winget AppList JSON file (AppList.json)"/>
<Button x:Name="btnBrowseAppListJsonPath" Grid.Column="1" Content="Browse..." Width="80" Margin="5,0,0,0" VerticalAlignment="Center"/> <Button x:Name="btnBrowseAppListJsonPath" Grid.Column="1" Content="Browse..." Width="80" Margin="5,0,0,0" VerticalAlignment="Center"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
<!-- BYO AppList Path - Shows only when Install Applications is checked -->
<StackPanel x:Name="userAppListPathPanel" Visibility="Collapsed" Margin="25,5,5,10">
<TextBlock Text="BYO AppList Path:" Margin="0,0,0,5" ToolTip="Path to the Bring Your Own applications JSON file (UserAppList.json)"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="txtUserAppListPath" Grid.Column="0" VerticalAlignment="Center" ToolTip="Path to the Bring Your Own applications JSON file (UserAppList.json)"/>
<Button x:Name="btnBrowseUserAppListPath" Grid.Column="1" Content="Browse..." Width="80" Margin="5,0,0,0" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
<!-- Winget Applications Section - Indented under Install Applications --> <!-- Winget Applications Section - Indented under Install Applications -->
<CheckBox x:Name="chkInstallWingetApps" Content="Install Winget Applications" Margin="5" ToolTip="Enable to install applications using Windows Package Manager (winget)"/> <CheckBox x:Name="chkInstallWingetApps" Content="Install Winget Applications" Margin="5" ToolTip="Enable to install applications using Windows Package Manager (winget)"/>
@@ -336,8 +349,8 @@
<!-- Save/Import/Clear Buttons --> <!-- Save/Import/Clear Buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Button x:Name="btnSaveWingetList" Content="Save AppList.json" Padding="15,5" Margin="0,0,10,0" ToolTip="Save selected applications to a JSON file"/> <Button x:Name="btnSaveWingetList" Content="Save Winget AppList" Padding="15,5" Margin="0,0,10,0" ToolTip="Save selected applications to a JSON file"/>
<Button x:Name="btnImportWingetList" Content="Import AppList.json" Padding="15,5" Margin="0,0,10,0" ToolTip="Import applications from a JSON file"/> <Button x:Name="btnImportWingetList" Content="Import Winget AppList" Padding="15,5" Margin="0,0,10,0" ToolTip="Import applications from a JSON file"/>
<Button x:Name="btnDownloadSelected" Content="Download Selected" Padding="15,5" Margin="0,0,10,0" ToolTip="Download all selected applications"/> <Button x:Name="btnDownloadSelected" Content="Download Selected" Padding="15,5" Margin="0,0,10,0" ToolTip="Download all selected applications"/>
<Button x:Name="btnClearWingetList" Content="Clear List" Padding="15,5" ToolTip="Clear all applications from the list"/> <Button x:Name="btnClearWingetList" Content="Clear List" Padding="15,5" ToolTip="Clear all applications from the list"/>
</StackPanel> </StackPanel>
@@ -405,8 +418,8 @@
<!-- Save/Import/Clear Buttons --> <!-- Save/Import/Clear Buttons -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,10"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,10">
<Button x:Name="btnSaveBYOApplications" Content="Save UserAppList.json" Margin="0,0,10,0" Padding="10,5" ToolTip="Save application list to JSON file"/> <Button x:Name="btnSaveBYOApplications" Content="Save BYO AppList" Margin="0,0,10,0" Padding="10,5" ToolTip="Save application list to JSON file"/>
<Button x:Name="btnLoadBYOApplications" Content="Import UserAppList.json" Margin="0,0,10,0" Padding="10,5" ToolTip="Import application list from JSON file"/> <Button x:Name="btnLoadBYOApplications" Content="Import BYO AppList" Margin="0,0,10,0" Padding="10,5" ToolTip="Import application list from JSON file"/>
<Button x:Name="btnEditApplication" Content="Edit Application" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Edit the selected application's details"/> <Button x:Name="btnEditApplication" Content="Edit Application" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Edit the selected application's details"/>
<Button x:Name="btnCopyBYOApps" Content="Copy Apps" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Copy applications with a specified source path to the AppsPath\Win32 folder"/> <Button x:Name="btnCopyBYOApps" Content="Copy Apps" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Copy applications with a specified source path to the AppsPath\Win32 folder"/>
<Button x:Name="btnRemoveSelectedBYOApps" Content="Remove Selected" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Remove selected applications from the list"/> <Button x:Name="btnRemoveSelectedBYOApps" Content="Remove Selected" IsEnabled="False" Margin="0,0,10,0" Padding="10,5" ToolTip="Remove selected applications from the list"/>
@@ -161,6 +161,7 @@ function Invoke-ParallelProcessing {
ApplicationItemData = $currentItem ApplicationItemData = $currentItem
AppListJsonPath = $localJobArgs['AppListJsonPath'] AppListJsonPath = $localJobArgs['AppListJsonPath']
AppsPath = $localJobArgs['AppsPath'] AppsPath = $localJobArgs['AppsPath']
UserAppListPath = $localJobArgs['UserAppListPath']
OrchestrationPath = $localJobArgs['OrchestrationPath'] OrchestrationPath = $localJobArgs['OrchestrationPath']
ProgressQueue = $localProgressQueue ProgressQueue = $localProgressQueue
WindowsArch = $localJobArgs['WindowsArch'] WindowsArch = $localJobArgs['WindowsArch']
@@ -358,6 +358,8 @@ function Start-WingetAppDownloadTask {
[string]$AppListJsonPath, [string]$AppListJsonPath,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$AppsPath, [string]$AppsPath,
[Parameter()]
[string]$UserAppListPath,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$OrchestrationPath, [string]$OrchestrationPath,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
@@ -379,11 +381,11 @@ function Start-WingetAppDownloadTask {
WriteLog "Starting download task for $($appName) with ID $($appId) from source $($source)." WriteLog "Starting download task for $($appName) with ID $($appId) from source $($source)."
try { try {
# Define paths # Resolve the BYO app list path so duplicate checks honor custom file names.
$userAppListPath = Join-Path -Path $AppsPath -ChildPath "UserAppList.json" $userAppListPath = if (-not [string]::IsNullOrWhiteSpace($UserAppListPath)) { $UserAppListPath } else { Join-Path -Path $AppsPath -ChildPath "UserAppList.json" }
$appFound = $false $appFound = $false
# 1. Check UserAppList.json and content # 1. Check the configured BYO app list and content
if (Test-Path -Path $userAppListPath) { if (Test-Path -Path $userAppListPath) {
try { try {
$userAppListContent = Get-Content -Path $userAppListPath -Raw | ConvertFrom-Json $userAppListContent = Get-Content -Path $userAppListPath -Raw | ConvertFrom-Json
@@ -724,6 +726,8 @@ function Get-Apps {
[string]$AppList, [string]$AppList,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$AppsPath, [string]$AppsPath,
[Parameter()]
[string]$UserAppListPath,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$WindowsArch, [string]$WindowsArch,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
@@ -787,6 +791,7 @@ function Get-Apps {
# CLI builds should create WinGetWin32Apps.json, so SkipWin32Json is false # CLI builds should create WinGetWin32Apps.json, so SkipWin32Json is false
$taskArguments = @{ $taskArguments = @{
AppsPath = $AppsPath AppsPath = $AppsPath
UserAppListPath = $UserAppListPath
AppListJsonPath = $AppList AppListJsonPath = $AppList
OrchestrationPath = $OrchestrationPath OrchestrationPath = $OrchestrationPath
WindowsArch = $WindowsArch WindowsArch = $WindowsArch
@@ -27,6 +27,22 @@ function Update-BYOAppsActionButtonsState {
} }
} }
# Function to resolve the configured BYO app list path
function Get-BYOApplicationListPath {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[psobject]$State
)
# Fall back to the legacy default path when the textbox is empty.
if (-not [string]::IsNullOrWhiteSpace($State.Controls.txtUserAppListPath.Text)) {
return $State.Controls.txtUserAppListPath.Text
}
return (Join-Path -Path $State.Controls.txtApplicationPath.Text -ChildPath 'UserAppList.json')
}
# Function to remove all selected BYO applications # Function to remove all selected BYO applications
function Remove-SelectedBYOApplications { function Remove-SelectedBYOApplications {
[CmdletBinding()] [CmdletBinding()]
@@ -76,10 +92,10 @@ function Remove-SelectedBYOApplications {
} }
# Ask user if they want to save the changes # Ask user if they want to save the changes
$result = [System.Windows.MessageBox]::Show("The selected applications have been removed from the list. Do you want to save these changes to UserAppList.json now?", "Save Changes", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Question) $result = [System.Windows.MessageBox]::Show("The selected applications have been removed from the list. Do you want to save these changes to the configured BYO app list now?", "Save Changes", [System.Windows.MessageBoxButton]::YesNo, [System.Windows.MessageBoxImage]::Question)
if ($result -eq 'Yes') { if ($result -eq 'Yes') {
$userAppListPath = Join-Path -Path $State.Controls.txtApplicationPath.Text -ChildPath 'UserAppList.json' $userAppListPath = Get-BYOApplicationListPath -State $State
Save-BYOApplicationList -Path $userAppListPath -State $State Save-BYOApplicationList -Path $userAppListPath -State $State
} }
} }
@@ -391,18 +407,24 @@ function Invoke-CopyBYOApps {
) )
$localAppsPath = $State.Controls.txtApplicationPath.Text $localAppsPath = $State.Controls.txtApplicationPath.Text
$userAppListPath = Join-Path -Path $localAppsPath -ChildPath 'UserAppList.json' $userAppListPath = Get-BYOApplicationListPath -State $State
$listView = $State.Controls.lstApplications $listView = $State.Controls.lstApplications
try { try {
# Ensure items are sorted by current priority before saving # Ensure the configured BYO app list folder exists before writing the manifest.
# Exclude CopyStatus when saving and ensure Priority is an integer; include AdditionalExitCodes and IgnoreNonZeroExitCodes for parity with Save-BYOApplicationList $userAppListDirectory = Split-Path -Path $userAppListPath -Parent
if (-not [string]::IsNullOrWhiteSpace($userAppListDirectory) -and -not (Test-Path -Path $userAppListDirectory -PathType Container)) {
New-Item -Path $userAppListDirectory -ItemType Directory -Force | Out-Null
}
# Ensure items are sorted by current priority before saving.
# Exclude CopyStatus when saving and ensure Priority is an integer; include AdditionalExitCodes and IgnoreNonZeroExitCodes for parity with Save-BYOApplicationList.
$applications = $listView.Items | Sort-Object Priority | Select-Object @{N = 'Priority'; E = { [int]$_.Priority } }, Name, CommandLine, Arguments, Source, AdditionalExitCodes, IgnoreNonZeroExitCodes $applications = $listView.Items | Sort-Object Priority | Select-Object @{N = 'Priority'; E = { [int]$_.Priority } }, Name, CommandLine, Arguments, Source, AdditionalExitCodes, IgnoreNonZeroExitCodes
$applications | ConvertTo-Json -Depth 5 | Set-Content -Path $userAppListPath -Force -Encoding UTF8 $applications | ConvertTo-Json -Depth 5 | Set-Content -Path $userAppListPath -Force -Encoding UTF8
WriteLog "Successfully updated UserAppList.json with all applications from the UI." WriteLog "Successfully updated BYO app list at $userAppListPath with all applications from the UI."
} }
catch { catch {
$errorMessage = "Failed to update UserAppList.json: $_" $errorMessage = "Failed to update BYO app list at $($userAppListPath): $_"
WriteLog $errorMessage WriteLog $errorMessage
[System.Windows.MessageBox]::Show($errorMessage, "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error) [System.Windows.MessageBox]::Show($errorMessage, "Error", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Error)
return return
@@ -93,7 +93,7 @@ function Get-UIConfig {
UpdateLatestNet = $State.Controls.chkUpdateLatestNet.IsChecked UpdateLatestNet = $State.Controls.chkUpdateLatestNet.IsChecked
UpdateOneDrive = $State.Controls.chkUpdateOneDrive.IsChecked UpdateOneDrive = $State.Controls.chkUpdateOneDrive.IsChecked
UpdatePreviewCU = $State.Controls.chkUpdatePreviewCU.IsChecked UpdatePreviewCU = $State.Controls.chkUpdatePreviewCU.IsChecked
UserAppListPath = "$($State.Controls.txtApplicationPath.Text)\UserAppList.json" UserAppListPath = $State.Controls.txtUserAppListPath.Text
USBDriveList = @{} USBDriveList = @{}
Username = $State.Controls.txtUsername.Text Username = $State.Controls.txtUsername.Text
Threads = [int]$State.Controls.txtThreads.Text Threads = [int]$State.Controls.txtThreads.Text
@@ -585,6 +585,7 @@ function Update-UIFromConfig {
Set-UIValue -ControlName 'chkBringYourOwnApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'BringYourOwnApps' -State $State Set-UIValue -ControlName 'chkBringYourOwnApps' -PropertyName 'IsChecked' -ConfigObject $ConfigContent -ConfigKey 'BringYourOwnApps' -State $State
Set-UIValue -ControlName 'txtApplicationPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppsPath' -State $State Set-UIValue -ControlName 'txtApplicationPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppsPath' -State $State
Set-UIValue -ControlName 'txtAppListJsonPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppListPath' -State $State Set-UIValue -ControlName 'txtAppListJsonPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'AppListPath' -State $State
Set-UIValue -ControlName 'txtUserAppListPath' -PropertyName 'Text' -ConfigObject $ConfigContent -ConfigKey 'UserAppListPath' -State $State
# Handle AppsScriptVariables # Handle AppsScriptVariables
$appsScriptVarsKeyExists = $false $appsScriptVarsKeyExists = $false
@@ -435,10 +435,18 @@ function Register-EventHandlers {
param($eventSource, $routedEventArgs) param($eventSource, $routedEventArgs)
$window = [System.Windows.Window]::GetWindow($eventSource) $window = [System.Windows.Window]::GetWindow($eventSource)
$localState = $window.Tag $localState = $window.Tag
$selectedPath = Invoke-BrowseAction -Type 'OpenFile' -Title "Select AppList.json File" -Filter "JSON files (*.json)|*.json" -AllowNewFile $selectedPath = Invoke-BrowseAction -Type 'OpenFile' -Title "Select Winget AppList File" -Filter "JSON files (*.json)|*.json" -AllowNewFile
if ($selectedPath) { $localState.Controls.txtAppListJsonPath.Text = $selectedPath } if ($selectedPath) { $localState.Controls.txtAppListJsonPath.Text = $selectedPath }
}) })
$State.Controls.btnBrowseUserAppListPath.Add_Click({
param($eventSource, $routedEventArgs)
$window = [System.Windows.Window]::GetWindow($eventSource)
$localState = $window.Tag
$selectedPath = Invoke-BrowseAction -Type 'OpenFile' -Title "Select BYO AppList File" -Filter "JSON files (*.json)|*.json" -AllowNewFile
if ($selectedPath) { $localState.Controls.txtUserAppListPath.Text = $selectedPath }
})
$State.Controls.btnBrowseAppSource.Add_Click({ $State.Controls.btnBrowseAppSource.Add_Click({
param($eventSource, $routedEventArgs) param($eventSource, $routedEventArgs)
$window = [System.Windows.Window]::GetWindow($eventSource) $window = [System.Windows.Window]::GetWindow($eventSource)
@@ -466,17 +474,23 @@ function Register-EventHandlers {
$window = [System.Windows.Window]::GetWindow($eventSource) $window = [System.Windows.Window]::GetWindow($eventSource)
$localState = $window.Tag $localState = $window.Tag
$initialDir = $localState.Controls.txtApplicationPath.Text # Default the save dialog to the configured BYO app list path.
$currentPath = $localState.Controls.txtUserAppListPath.Text
$initialDir = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Parent } else { $localState.Controls.txtApplicationPath.Text }
if ([string]::IsNullOrWhiteSpace($initialDir) -or -not (Test-Path $initialDir)) { $initialDir = $localState.FFUDevelopmentPath } if ([string]::IsNullOrWhiteSpace($initialDir) -or -not (Test-Path $initialDir)) { $initialDir = $localState.FFUDevelopmentPath }
$fileName = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Leaf } else { "UserAppList.json" }
$savePath = Invoke-BrowseAction -Type 'SaveFile' ` $savePath = Invoke-BrowseAction -Type 'SaveFile' `
-Title "Save Application List" ` -Title "Save BYO App List" `
-Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" ` -Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" `
-InitialDirectory $initialDir ` -InitialDirectory $initialDir `
-FileName "UserAppList.json" ` -FileName $fileName `
-DefaultExt ".json" -DefaultExt ".json"
if ($savePath) { Save-BYOApplicationList -Path $savePath -State $localState } if ($savePath) {
$localState.Controls.txtUserAppListPath.Text = $savePath
Save-BYOApplicationList -Path $savePath -State $localState
}
}) })
$State.Controls.btnLoadBYOApplications.Add_Click({ $State.Controls.btnLoadBYOApplications.Add_Click({
@@ -484,15 +498,18 @@ function Register-EventHandlers {
$window = [System.Windows.Window]::GetWindow($eventSource) $window = [System.Windows.Window]::GetWindow($eventSource)
$localState = $window.Tag $localState = $window.Tag
$initialDir = $localState.Controls.txtApplicationPath.Text # Default the import dialog to the configured BYO app list path.
$currentPath = $localState.Controls.txtUserAppListPath.Text
$initialDir = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Parent } else { $localState.Controls.txtApplicationPath.Text }
if ([string]::IsNullOrWhiteSpace($initialDir) -or -not (Test-Path $initialDir)) { $initialDir = $localState.FFUDevelopmentPath } if ([string]::IsNullOrWhiteSpace($initialDir) -or -not (Test-Path $initialDir)) { $initialDir = $localState.FFUDevelopmentPath }
$loadPath = Invoke-BrowseAction -Type 'OpenFile' ` $loadPath = Invoke-BrowseAction -Type 'OpenFile' `
-Title "Import Application List" ` -Title "Import BYO App List" `
-Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" ` -Filter "JSON files (*.json)|*.json|All files (*.*)|*.*" `
-InitialDirectory $initialDir -InitialDirectory $initialDir
if ($loadPath) { if ($loadPath) {
$localState.Controls.txtUserAppListPath.Text = $loadPath
Import-BYOApplicationList -Path $loadPath -State $localState Import-BYOApplicationList -Path $loadPath -State $localState
Update-CopyButtonState -State $localState Update-CopyButtonState -State $localState
} }
@@ -70,8 +70,10 @@ function Initialize-UIControls {
$State.Controls.txtWingetModuleVersion = $window.FindName('txtWingetModuleVersion') $State.Controls.txtWingetModuleVersion = $window.FindName('txtWingetModuleVersion')
$State.Controls.applicationPathPanel = $window.FindName('applicationPathPanel') $State.Controls.applicationPathPanel = $window.FindName('applicationPathPanel')
$State.Controls.appListJsonPathPanel = $window.FindName('appListJsonPathPanel') $State.Controls.appListJsonPathPanel = $window.FindName('appListJsonPathPanel')
$State.Controls.userAppListPathPanel = $window.FindName('userAppListPathPanel')
$State.Controls.btnBrowseApplicationPath = $window.FindName('btnBrowseApplicationPath') $State.Controls.btnBrowseApplicationPath = $window.FindName('btnBrowseApplicationPath')
$State.Controls.btnBrowseAppListJsonPath = $window.FindName('btnBrowseAppListJsonPath') $State.Controls.btnBrowseAppListJsonPath = $window.FindName('btnBrowseAppListJsonPath')
$State.Controls.btnBrowseUserAppListPath = $window.FindName('btnBrowseUserAppListPath')
$State.Controls.chkBringYourOwnApps = $window.FindName('chkBringYourOwnApps') $State.Controls.chkBringYourOwnApps = $window.FindName('chkBringYourOwnApps')
$State.Controls.byoApplicationPanel = $window.FindName('byoApplicationPanel') $State.Controls.byoApplicationPanel = $window.FindName('byoApplicationPanel')
$State.Controls.wingetSearchPanel = $window.FindName('wingetSearchPanel') $State.Controls.wingetSearchPanel = $window.FindName('wingetSearchPanel')
@@ -159,6 +161,7 @@ function Initialize-UIControls {
$State.Controls.chkUpdatePreviewCU = $window.FindName('chkUpdatePreviewCU') $State.Controls.chkUpdatePreviewCU = $window.FindName('chkUpdatePreviewCU')
$State.Controls.txtApplicationPath = $window.FindName('txtApplicationPath') $State.Controls.txtApplicationPath = $window.FindName('txtApplicationPath')
$State.Controls.txtAppListJsonPath = $window.FindName('txtAppListJsonPath') $State.Controls.txtAppListJsonPath = $window.FindName('txtAppListJsonPath')
$State.Controls.txtUserAppListPath = $window.FindName('txtUserAppListPath')
$State.Controls.chkInstallDrivers = $window.FindName('chkInstallDrivers') $State.Controls.chkInstallDrivers = $window.FindName('chkInstallDrivers')
$State.Controls.chkCopyDrivers = $window.FindName('chkCopyDrivers') $State.Controls.chkCopyDrivers = $window.FindName('chkCopyDrivers')
$State.Controls.chkCompressDriversToWIM = $window.FindName('chkCompressDriversToWIM') $State.Controls.chkCompressDriversToWIM = $window.FindName('chkCompressDriversToWIM')
@@ -305,6 +308,7 @@ function Initialize-UIDefaults {
$State.Controls.chkInstallApps.IsChecked = $State.Defaults.generalDefaults.InstallApps $State.Controls.chkInstallApps.IsChecked = $State.Defaults.generalDefaults.InstallApps
$State.Controls.txtApplicationPath.Text = $State.Defaults.generalDefaults.ApplicationPath $State.Controls.txtApplicationPath.Text = $State.Defaults.generalDefaults.ApplicationPath
$State.Controls.txtAppListJsonPath.Text = $State.Defaults.generalDefaults.AppListJsonPath $State.Controls.txtAppListJsonPath.Text = $State.Defaults.generalDefaults.AppListJsonPath
$State.Controls.txtUserAppListPath.Text = $State.Defaults.generalDefaults.UserAppListPath
$State.Controls.chkInstallWingetApps.IsChecked = $State.Defaults.generalDefaults.InstallWingetApps $State.Controls.chkInstallWingetApps.IsChecked = $State.Defaults.generalDefaults.InstallWingetApps
$State.Controls.chkBringYourOwnApps.IsChecked = $State.Defaults.generalDefaults.BringYourOwnApps $State.Controls.chkBringYourOwnApps.IsChecked = $State.Defaults.generalDefaults.BringYourOwnApps
@@ -108,20 +108,28 @@ function Save-WingetList {
}) })
} }
# Default the save dialog to the configured Winget app list path.
$currentPath = $State.Controls.txtAppListJsonPath.Text
$initialDirectory = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Parent } else { $State.Controls.txtApplicationPath.Text }
if ([string]::IsNullOrWhiteSpace($initialDirectory) -or -not (Test-Path -Path $initialDirectory -PathType Container)) {
$initialDirectory = $State.Controls.txtApplicationPath.Text
}
$fileName = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Leaf } else { "AppList.json" }
$sfd = New-Object System.Windows.Forms.SaveFileDialog $sfd = New-Object System.Windows.Forms.SaveFileDialog
$sfd.Filter = "JSON files (*.json)|*.json" $sfd.Filter = "JSON files (*.json)|*.json"
$sfd.Title = "Save App List" $sfd.Title = "Save Winget App List"
# Correctly get the path from the UI control via the State object $sfd.InitialDirectory = $initialDirectory
$sfd.InitialDirectory = $State.Controls.txtApplicationPath.Text $sfd.FileName = $fileName
$sfd.FileName = "AppList.json"
if ($sfd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { if ($sfd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
$appList | ConvertTo-Json -Depth 10 | Set-Content $sfd.FileName -Encoding UTF8 $appList | ConvertTo-Json -Depth 10 | Set-Content $sfd.FileName -Encoding UTF8
[System.Windows.MessageBox]::Show("App list saved successfully.", "Success", "OK", "Information") $State.Controls.txtAppListJsonPath.Text = $sfd.FileName
[System.Windows.MessageBox]::Show("Winget app list saved successfully.", "Success", "OK", "Information")
} }
} }
catch { catch {
[System.Windows.MessageBox]::Show("Error saving app list: $_", "Error", "OK", "Error") [System.Windows.MessageBox]::Show("Error saving Winget app list: $_", "Error", "OK", "Error")
} }
} }
@@ -132,11 +140,17 @@ function Import-WingetList {
[psobject]$State [psobject]$State
) )
try { try {
# Default the import dialog to the configured Winget app list path.
$currentPath = $State.Controls.txtAppListJsonPath.Text
$initialDirectory = if (-not [string]::IsNullOrWhiteSpace($currentPath)) { Split-Path -Path $currentPath -Parent } else { $State.Controls.txtApplicationPath.Text }
if ([string]::IsNullOrWhiteSpace($initialDirectory) -or -not (Test-Path -Path $initialDirectory -PathType Container)) {
$initialDirectory = $State.Controls.txtApplicationPath.Text
}
$ofd = New-Object System.Windows.Forms.OpenFileDialog $ofd = New-Object System.Windows.Forms.OpenFileDialog
$ofd.Filter = "JSON files (*.json)|*.json" $ofd.Filter = "JSON files (*.json)|*.json"
$ofd.Title = "Import App List" $ofd.Title = "Import Winget App List"
# Correctly get the path from the UI control via the State object $ofd.InitialDirectory = $initialDirectory
$ofd.InitialDirectory = $State.Controls.txtApplicationPath.Text
if ($ofd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { if ($ofd.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
$importedAppsData = Get-Content $ofd.FileName -Raw | ConvertFrom-Json $importedAppsData = Get-Content $ofd.FileName -Raw | ConvertFrom-Json
@@ -144,16 +158,16 @@ function Import-WingetList {
$newAppListForItemsSource = [System.Collections.Generic.List[object]]::new() $newAppListForItemsSource = [System.Collections.Generic.List[object]]::new()
if ($null -ne $importedAppsData.apps) { if ($null -ne $importedAppsData.apps) {
# Get default architecture from the UI for fallback # Get default architecture from the UI for fallback.
$defaultArch = $State.Controls.cmbWindowsArch.SelectedItem $defaultArch = $State.Controls.cmbWindowsArch.SelectedItem
foreach ($appInfo in $importedAppsData.apps) { foreach ($appInfo in $importedAppsData.apps) {
$arch = if ($appInfo.source -eq 'msstore') { 'NA' } else { if ($appInfo.PSObject.Properties['architecture']) { $appInfo.architecture } else { $defaultArch } } $arch = if ($appInfo.source -eq 'msstore') { 'NA' } else { if ($appInfo.PSObject.Properties['architecture']) { $appInfo.architecture } else { $defaultArch } }
$newAppListForItemsSource.Add([PSCustomObject]@{ $newAppListForItemsSource.Add([PSCustomObject]@{
IsSelected = $true # Imported apps are marked as selected IsSelected = $true
Name = $appInfo.name Name = $appInfo.name
Id = $appInfo.id Id = $appInfo.id
Version = "" # Will be populated when searching or if data exists Version = ""
Source = $appInfo.source Source = $appInfo.source
Architecture = $arch Architecture = $arch
AdditionalExitCodes = if ($appInfo.PSObject.Properties['AdditionalExitCodes']) { $appInfo.AdditionalExitCodes } else { "" } AdditionalExitCodes = if ($appInfo.PSObject.Properties['AdditionalExitCodes']) { $appInfo.AdditionalExitCodes } else { "" }
@@ -164,12 +178,13 @@ function Import-WingetList {
} }
$State.Controls.lstWingetResults.ItemsSource = $newAppListForItemsSource.ToArray() $State.Controls.lstWingetResults.ItemsSource = $newAppListForItemsSource.ToArray()
$State.Controls.txtAppListJsonPath.Text = $ofd.FileName
[System.Windows.MessageBox]::Show("App list imported successfully.", "Success", "OK", "Information") [System.Windows.MessageBox]::Show("Winget app list imported successfully.", "Success", "OK", "Information")
} }
} }
catch { catch {
[System.Windows.MessageBox]::Show("Error importing app list: $_", "Error", "OK", "Error") [System.Windows.MessageBox]::Show("Error importing Winget app list: $_", "Error", "OK", "Error")
} }
} }
@@ -108,6 +108,7 @@ function Get-GeneralDefaults {
$ffuCapturePath = Join-Path -Path $FFUDevelopmentPath -ChildPath "FFU" $ffuCapturePath = Join-Path -Path $FFUDevelopmentPath -ChildPath "FFU"
$officePath = Join-Path -Path $appsPath -ChildPath "Office" $officePath = Join-Path -Path $appsPath -ChildPath "Office"
$appListJsonPath = Join-Path -Path $appsPath -ChildPath "AppList.json" $appListJsonPath = Join-Path -Path $appsPath -ChildPath "AppList.json"
$userAppListPath = Join-Path -Path $appsPath -ChildPath "UserAppList.json"
$driversJsonPath = Join-Path -Path $driversPath -ChildPath "Drivers.json" $driversJsonPath = Join-Path -Path $driversPath -ChildPath "Drivers.json"
return [PSCustomObject]@{ return [PSCustomObject]@{
@@ -163,6 +164,7 @@ function Get-GeneralDefaults {
InstallApps = $false InstallApps = $false
ApplicationPath = $appsPath ApplicationPath = $appsPath
AppListJsonPath = $appListJsonPath AppListJsonPath = $appListJsonPath
UserAppListPath = $userAppListPath
InstallWingetApps = $false InstallWingetApps = $false
BringYourOwnApps = $false BringYourOwnApps = $false
# M365 Apps/Office Tab Defaults # M365 Apps/Office Tab Defaults
@@ -305,6 +307,7 @@ function Update-ApplicationPanelVisibility {
$subOptionVisibility = if ($installAppsChecked) { 'Visible' } else { 'Collapsed' } $subOptionVisibility = if ($installAppsChecked) { 'Visible' } else { 'Collapsed' }
$State.Controls.applicationPathPanel.Visibility = $subOptionVisibility $State.Controls.applicationPathPanel.Visibility = $subOptionVisibility
$State.Controls.appListJsonPathPanel.Visibility = $subOptionVisibility $State.Controls.appListJsonPathPanel.Visibility = $subOptionVisibility
$State.Controls.userAppListPathPanel.Visibility = $subOptionVisibility
$State.Controls.chkInstallWingetApps.Visibility = $subOptionVisibility $State.Controls.chkInstallWingetApps.Visibility = $subOptionVisibility
$State.Controls.chkBringYourOwnApps.Visibility = $subOptionVisibility $State.Controls.chkBringYourOwnApps.Visibility = $subOptionVisibility
$State.Controls.chkDefineAppsScriptVariables.Visibility = $subOptionVisibility $State.Controls.chkDefineAppsScriptVariables.Visibility = $subOptionVisibility