mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Refactor WinGet app handling and add command overrides
Improves the reliability of WinGet app processing by making several key changes. The build process now deletes the `WinGetWin32Apps.json` file before each run to ensure it is always freshly generated. The UI no longer relies on `WinGetWin32Apps.json` to detect previously downloaded content. Instead, it checks directly for the application's content on disk, preventing unnecessary re-downloads. This change also introduces a feature allowing users to override the default silent install commands for Win32 apps. By specifying `CommandLine` or `Arguments` properties in `AppList.json`, these values will be used to update the corresponding entries in `WinGetWin32Apps.json` during the build process.
This commit is contained in:
@@ -5871,6 +5871,13 @@ if ($AllowVHDXCaching) {
|
|||||||
throw $_
|
throw $_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Remove WinGetWin32Apps.json so it is always rebuilt next run
|
||||||
|
if (Test-Path -Path $wingetWin32jsonFile -PathType Leaf) {
|
||||||
|
WriteLog "Removing $wingetWin32jsonFile"
|
||||||
|
Remove-Item -Path $wingetWin32jsonFile -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
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ function Get-Application {
|
|||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[string]$WindowsArch,
|
[string]$WindowsArch,
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
[string]$OrchestrationPath
|
[string]$OrchestrationPath,
|
||||||
|
[switch]$SkipWin32Json
|
||||||
)
|
)
|
||||||
|
|
||||||
# Block Company Portal from winget source
|
# Block Company Portal from winget source
|
||||||
@@ -48,6 +49,29 @@ function Get-Application {
|
|||||||
# Check if the folder is not empty.
|
# Check if the folder is not empty.
|
||||||
if (Get-ChildItem -Path $appBaseFolderPathForCheck -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1) {
|
if (Get-ChildItem -Path $appBaseFolderPathForCheck -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1) {
|
||||||
WriteLog "Application '$AppName' appears to be already downloaded as content exists in '$appBaseFolderPathForCheck'. Skipping download."
|
WriteLog "Application '$AppName' appears to be already downloaded as content exists in '$appBaseFolderPathForCheck'. Skipping download."
|
||||||
|
|
||||||
|
# Add silent install command(s) only if not skipping JSON generation (build-time scenario)
|
||||||
|
$appIsWin32Existing = ($Source -eq 'winget' -or ($Source -eq 'msstore' -and $AppId.StartsWith('XP')))
|
||||||
|
if ($appIsWin32Existing -and -not $SkipWin32Json) {
|
||||||
|
$win32BasePath = Join-Path -Path "$AppsPath\Win32" -ChildPath $AppName
|
||||||
|
if (Test-Path -Path $win32BasePath -PathType Container) {
|
||||||
|
$archFolders = Get-ChildItem -Path $win32BasePath -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @('x86', 'x64', 'arm64') }
|
||||||
|
if ($archFolders) {
|
||||||
|
foreach ($archFolder in $archFolders) {
|
||||||
|
WriteLog "Adding silent install command for pre-downloaded $AppName ($($archFolder.Name)) to $OrchestrationPath\WinGetWin32Apps.json"
|
||||||
|
Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $archFolder.FullName -OrchestrationPath $OrchestrationPath -SubFolder $archFolder.Name | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "Adding silent install command for pre-downloaded $AppName to $OrchestrationPath\WinGetWin32Apps.json"
|
||||||
|
Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $win32BasePath -OrchestrationPath $OrchestrationPath | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($appIsWin32Existing -and $SkipWin32Json) {
|
||||||
|
WriteLog "Skipping WinGetWin32Apps.json regeneration for pre-downloaded $AppName (UI mode)."
|
||||||
|
}
|
||||||
|
|
||||||
return 0 # Success, already present
|
return 0 # Success, already present
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,8 +220,14 @@ function Get-Application {
|
|||||||
}
|
}
|
||||||
# If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file
|
# If app is in Win32 folder, add the silent install command to the WinGetWin32Apps.json file
|
||||||
elseif ($appFolderPath -match 'Win32') {
|
elseif ($appFolderPath -match 'Win32') {
|
||||||
WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json"
|
if (-not $SkipWin32Json) {
|
||||||
$result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath -SubFolder $subFolderForCommand
|
WriteLog "$AppName is a Win32 app. Adding silent install command to $OrchestrationPath\WinGetWin32Apps.json"
|
||||||
|
$result = Add-Win32SilentInstallCommand -AppFolder $AppName -AppFolderPath $appFolderPath -OrchestrationPath $OrchestrationPath -SubFolder $subFolderForCommand
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "$AppName is a Win32 app. Skipping WinGetWin32Apps.json generation (UI mode)."
|
||||||
|
$result = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# For any other case, set result to 0 (success)
|
# For any other case, set result to 0 (success)
|
||||||
@@ -314,7 +344,7 @@ function Get-Apps {
|
|||||||
if (-not (Test-Path -Path $storeAppsFolder -PathType Container)) {
|
if (-not (Test-Path -Path $storeAppsFolder -PathType Container)) {
|
||||||
New-Item -Path $storeAppsFolder -ItemType Directory -Force | Out-Null
|
New-Item -Path $storeAppsFolder -ItemType Directory -Force | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($storeApp in $StoreApps) {
|
foreach ($storeApp in $StoreApps) {
|
||||||
try {
|
try {
|
||||||
$appArch = if ($storeApp.PSObject.Properties['architecture']) { $storeApp.architecture } else { $WindowsArch }
|
$appArch = if ($storeApp.PSObject.Properties['architecture']) { $storeApp.architecture } else { $WindowsArch }
|
||||||
@@ -326,6 +356,62 @@ function Get-Apps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Post-processing: Override CommandLine / Arguments from AppList.json if provided
|
||||||
|
# Users may supply custom silent install commands or arguments. These optional
|
||||||
|
# properties (CommandLine, Arguments) in AppList.json replace the auto-generated
|
||||||
|
# values in WinGetWin32Apps.json. Keyed by Name.
|
||||||
|
try {
|
||||||
|
$overrideMap = @{}
|
||||||
|
foreach ($app in $apps.apps) {
|
||||||
|
if ($app.source -in @('winget', 'msstore')) {
|
||||||
|
$hasCmd = ($app.PSObject.Properties['CommandLine'] -and -not [string]::IsNullOrWhiteSpace($app.CommandLine))
|
||||||
|
$hasArgs = ($app.PSObject.Properties['Arguments'] -and -not [string]::IsNullOrWhiteSpace($app.Arguments))
|
||||||
|
if ($hasCmd -or $hasArgs) {
|
||||||
|
$overrideMap[$app.name] = @{
|
||||||
|
CommandLine = if ($hasCmd) { $app.CommandLine } else { $null }
|
||||||
|
Arguments = if ($hasArgs) { $app.Arguments } else { $null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($overrideMap.Count -gt 0) {
|
||||||
|
$winGetWin32Path = Join-Path -Path $OrchestrationPath -ChildPath 'WinGetWin32Apps.json'
|
||||||
|
if (Test-Path -Path $winGetWin32Path) {
|
||||||
|
[array]$appsDataUpdated = Get-Content -Path $winGetWin32Path -Raw | ConvertFrom-Json
|
||||||
|
$changed = $false
|
||||||
|
foreach ($entry in $appsDataUpdated) {
|
||||||
|
if ($overrideMap.ContainsKey($entry.Name)) {
|
||||||
|
$ov = $overrideMap[$entry.Name]
|
||||||
|
if ($ov.CommandLine) {
|
||||||
|
WriteLog "Override (AppList.json) CommandLine for $($entry.Name)"
|
||||||
|
$entry.CommandLine = $ov.CommandLine
|
||||||
|
$changed = $true
|
||||||
|
}
|
||||||
|
if ($ov.Arguments) {
|
||||||
|
WriteLog "Override (AppList.json) Arguments for $($entry.Name)"
|
||||||
|
$entry.Arguments = $ov.Arguments
|
||||||
|
$changed = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($changed) {
|
||||||
|
$appsDataUpdated | ConvertTo-Json -Depth 10 | Set-Content -Path $winGetWin32Path
|
||||||
|
WriteLog "Applied AppList.json command overrides to WinGetWin32Apps.json"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "No matching apps required command overrides."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "WinGetWin32Apps.json not found; no overrides applied."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
WriteLog "Failed to apply AppList.json command overrides: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function Install-WinGet {
|
function Install-WinGet {
|
||||||
param (
|
param (
|
||||||
|
|||||||
@@ -450,70 +450,35 @@ function Start-WingetAppDownloadTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# 2. Check previous Winget download
|
# 2. Check existing downloaded Win32 content (folder-based; no WinGetWin32Apps.json dependency)
|
||||||
if (-not $appFound) {
|
if (-not $appFound -and $source -eq 'winget') {
|
||||||
if (-not $appFound) {
|
$appFolder = Join-Path -Path "$AppsPath\Win32" -ChildPath $appName
|
||||||
$wingetWin32jsonFile = Join-Path -Path $OrchestrationPath -ChildPath "WinGetWin32Apps.json"
|
if (Test-Path -Path $appFolder -PathType Container) {
|
||||||
if (Test-Path -Path $wingetWin32jsonFile) {
|
$contentFound = $false
|
||||||
try {
|
if ($ApplicationItemData.Architecture -eq 'x86 x64') {
|
||||||
$wingetAppsJson = Get-Content -Path $wingetWin32jsonFile -Raw | ConvertFrom-Json
|
$x86Folder = Join-Path -Path $appFolder -ChildPath "x86"
|
||||||
# Check if app already exists in WinGetWin32Apps.json
|
$x64Folder = Join-Path -Path $appFolder -ChildPath "x64"
|
||||||
# For multi-arch apps, there might be entries like "AppName (x86)" and "AppName (x64)"
|
if ((Test-Path -Path $x86Folder -PathType Container) -and (Test-Path -Path $x64Folder -PathType Container)) {
|
||||||
$existingWin32Entries = @($wingetAppsJson | Where-Object {
|
$x86Size = (Get-ChildItem -Path $x86Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
||||||
$_.Name -eq $appName -or
|
$x64Size = (Get-ChildItem -Path $x64Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
||||||
$_.Name -eq "$appName (x86)" -or
|
if ($x86Size -gt 1MB -and $x64Size -gt 1MB) {
|
||||||
$_.Name -eq "$appName (x64)"
|
$contentFound = $true
|
||||||
})
|
|
||||||
|
|
||||||
if ($existingWin32Entries.Count -gt 0) {
|
|
||||||
$appFolder = Join-Path -Path "$AppsPath\Win32" -ChildPath $appName
|
|
||||||
$appContentFound = $false
|
|
||||||
|
|
||||||
# Check if it's a multi-arch app with subfolders
|
|
||||||
if ($ApplicationItemData.Architecture -eq 'x86 x64') {
|
|
||||||
$x86Folder = Join-Path -Path $appFolder -ChildPath "x86"
|
|
||||||
$x64Folder = Join-Path -Path $appFolder -ChildPath "x64"
|
|
||||||
|
|
||||||
if ((Test-Path -Path $x86Folder -PathType Container) -and (Test-Path -Path $x64Folder -PathType Container)) {
|
|
||||||
$x86Size = (Get-ChildItem -Path $x86Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
|
||||||
$x64Size = (Get-ChildItem -Path $x64Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
|
||||||
|
|
||||||
if ($x86Size -gt 1MB -and $x64Size -gt 1MB) {
|
|
||||||
$appContentFound = $true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# Single architecture app
|
|
||||||
if (Test-Path -Path $appFolder -PathType Container) {
|
|
||||||
$folderSize = (Get-ChildItem -Path $appFolder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
|
||||||
if ($folderSize -gt 1MB) {
|
|
||||||
$appContentFound = $true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($appContentFound) {
|
|
||||||
$appFound = $true
|
|
||||||
$status = "Not Downloaded: App already in $wingetWin32jsonFile and found in $appFolder"
|
|
||||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appId -Status $status
|
|
||||||
WriteLog "Found '$appName' in WinGetWin32Apps.json and content exists in '$appFolder'. Skipping download to prevent duplicate entry."
|
|
||||||
return [PSCustomObject]@{ Id = $appId; Status = $status; ResultCode = 0 }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# App entry exists in WinGetWin32Apps.json but folder is missing or incomplete
|
|
||||||
$appFound = $true
|
|
||||||
$status = "App in '$wingetWin32jsonFile' but content folder '$appFolder' not found or incomplete. Remove entry from WinGetWin32Apps.json or restore content."
|
|
||||||
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appId -Status $status
|
|
||||||
WriteLog $status
|
|
||||||
return [PSCustomObject]@{ Id = $appId; Status = $status; ResultCode = 1 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
}
|
||||||
WriteLog "Warning: Could not read or parse '$wingetWin32jsonFile'. Error: $($_.Exception.Message)"
|
else {
|
||||||
|
$folderSize = (Get-ChildItem -Path $appFolder -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
||||||
|
if ($folderSize -gt 1MB) {
|
||||||
|
$contentFound = $true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($contentFound) {
|
||||||
|
$appFound = $true
|
||||||
|
$status = "Not Downloaded: Existing content found in $appFolder"
|
||||||
|
Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $appId -Status $status
|
||||||
|
WriteLog "Found existing content for '$appName' in '$appFolder'. Skipping download to prevent duplicate entry."
|
||||||
|
return [PSCustomObject]@{ Id = $appId; Status = $status; ResultCode = 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +599,7 @@ function Start-WingetAppDownloadTask {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
# Call Get-Application
|
# Call Get-Application
|
||||||
$resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $ApplicationItemData.Architecture -OrchestrationPath $OrchestrationPath -ErrorAction Stop
|
$resultCode = Get-Application -AppName $appName -AppId $appId -Source $source -AppsPath $AppsPath -WindowsArch $ApplicationItemData.Architecture -OrchestrationPath $OrchestrationPath -SkipWin32Json -ErrorAction Stop
|
||||||
|
|
||||||
# Determine status based on result code
|
# Determine status based on result code
|
||||||
switch ($resultCode) {
|
switch ($resultCode) {
|
||||||
|
|||||||
Reference in New Issue
Block a user