Private/Core/Install-ApplicationUpdate.ps1
|
function Install-ApplicationUpdate { <# .SYNOPSIS Installs an application update using winget .DESCRIPTION Handles the actual installation of an application update with pre/post scripts .PARAMETER AppId The winget app ID to update .PARAMETER AppConfig Optional managed application configuration .PARAMETER Force Force installation even if conflicting processes are running #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$AppId, [Parameter()] [ManagedApplication]$AppConfig, [Parameter()] [switch]$Force ) $result = [InstallationResult]::new() $result.AppId = $AppId $result.Status = [InstallationStatus]::InProgress $startTime = Get-Date try { Write-PatchLog "Starting update for $AppId" -Type Info # Get app name $pkg = Get-WinGetPackage -Id $AppId -ErrorAction SilentlyContinue if ($pkg) { $result.AppName = $pkg.Name } else { $result.AppName = $AppId } # Check for conflicting processes if ($AppConfig -and $AppConfig.ConflictingProcesses.Count -gt 0) { $running = Test-ConflictingProcess -ProcessNames $AppConfig.ConflictingProcesses if ($running -and -not $Force) { $result.Status = [InstallationStatus]::Deferred $result.Message = "Conflicting processes running: $($AppConfig.ConflictingProcesses -join ', ')" $result.ExitCode = 1602 # User cancelled / deferred Write-PatchLog $result.Message -Type Warning return $result } elseif ($running -and $Force) { # Force close conflicting processes Write-PatchLog "Force closing conflicting processes for $AppId" -Type Warning foreach ($procName in $AppConfig.ConflictingProcesses) { $procNameClean = $procName -replace '\.exe$', '' Get-Process -Name $procNameClean -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 2 } } # Run pre-installation script if configured if ($AppConfig -and $AppConfig.PreScript) { Write-PatchLog "Running pre-install script for $AppId" -Type Info try { $scriptBlock = [ScriptBlock]::Create($AppConfig.PreScript) Invoke-Command -ScriptBlock $scriptBlock -ErrorAction Stop } catch { Write-PatchLog "Pre-install script failed: $_" -Type Warning } } # Build update parameters $updateParams = @{ Id = $AppId Mode = 'Silent' } if ($AppConfig -and $AppConfig.InstallArguments) { $updateParams['Override'] = $AppConfig.InstallArguments } # Perform the update Write-PatchLog "Installing update for $AppId" -Type Info $updateResult = Update-WinGetPackage @updateParams -ErrorAction Stop # Check result if ($updateResult.Status -eq 'Ok' -or $updateResult.RebootRequired) { $result.Status = [InstallationStatus]::Success $result.ExitCode = 0 $result.Message = "Successfully updated $($result.AppName)" if ($updateResult.RebootRequired) { $result.RebootRequired = $true $result.Message += " (reboot required)" } Write-PatchLog $result.Message -Type Info } else { $result.Status = [InstallationStatus]::Failed $result.ExitCode = 1 $result.Message = "Update failed for $($result.AppName): $($updateResult.Status)" Write-PatchLog $result.Message -Type Error } # Run post-installation script if configured if ($AppConfig -and $AppConfig.PostScript -and $result.Status -eq [InstallationStatus]::Success) { Write-PatchLog "Running post-install script for $AppId" -Type Info try { $scriptBlock = [ScriptBlock]::Create($AppConfig.PostScript) Invoke-Command -ScriptBlock $scriptBlock -ErrorAction Stop } catch { Write-PatchLog "Post-install script failed: $_" -Type Warning } } # Check if app config indicates reboot required if ($AppConfig -and $AppConfig.RequiresReboot) { $result.RebootRequired = $true } } catch { $result.Status = [InstallationStatus]::Failed $result.ExitCode = 1 $result.Message = "Update failed for $AppId : $_" Write-PatchLog $result.Message -Type Error } finally { $result.Duration = (Get-Date) - $startTime } return $result } |