public/Invoke-OctaSoftwareUpdater.ps1
|
function Invoke-OctaSoftwareUpdater { <# .SYNOPSIS Bulk-updates installed software via winget (always attempted - ships with Windows 11) and Chocolatey/Scoop (only when their executable is actually present). Never installs either optional package manager itself. Default (no -Apply) is a dry preview of which managers are present, same pattern as every category's dry-run - the real update only runs with -Apply, deferred to a disposable VM in this project's own testing practice since it's a genuine, real update. #> [CmdletBinding()] param( [switch]$Apply, [switch]$Yes ) # ponytail: winget is detected the same way as the other two rather than assumed present. # It ships with Windows 11 Home/Pro, but not with LTSC/Server images, and it can be missing # on a freshly imaged machine where App Installer hasn't been provisioned yet - in which case # the `& winget` call below just wrote a "not recognized" error and left $LASTEXITCODE holding # some unrelated previous command's value, which then got reported as winget's exit code # under an overall Status = 'Success'. $managers = @( [pscustomobject]@{ Manager = 'winget'; Available = [bool](Get-Command winget -ErrorAction SilentlyContinue) } [pscustomobject]@{ Manager = 'Chocolatey'; Available = [bool](Get-Command choco -ErrorAction SilentlyContinue) } [pscustomobject]@{ Manager = 'Scoop'; Available = [bool](Get-Command scoop -ErrorAction SilentlyContinue) } ) if (-not $Apply) { foreach ($m in $managers) { $status = if ($m.Available) { 'will update' } else { 'not installed - skipped' } Write-Host ("{0,-12} {1}" -f $m.Manager, $status) } return $managers } if (-not $Yes) { $response = Read-Host "Update all software via the package manager(s) above? (y/N)" if ($response -notin @('y', 'Y', 's', 'S')) { return [pscustomobject]@{ Status = 'Cancelled' } } } $available = @($managers | Where-Object { $_.Available }) if ($available.Count -eq 0) { return [pscustomobject]@{ Status = 'NoPackageManager'; Message = 'No supported package manager (winget, Chocolatey, Scoop) is available on this system.' } } $results = @() if (($managers | Where-Object Manager -eq 'winget').Available) { & winget upgrade --all --accept-source-agreements --accept-package-agreements $results += [pscustomobject]@{ Manager = 'winget'; ExitCode = $LASTEXITCODE } } if (($managers | Where-Object Manager -eq 'Chocolatey').Available) { & choco upgrade all -y $results += [pscustomobject]@{ Manager = 'Chocolatey'; ExitCode = $LASTEXITCODE } } if (($managers | Where-Object Manager -eq 'Scoop').Available) { & scoop update '*' $results += [pscustomobject]@{ Manager = 'Scoop'; ExitCode = $LASTEXITCODE } } # Report the real outcome instead of a blanket 'Success': a package manager that exited # non-zero genuinely failed to update something, and a caller/script deserves to know. $failed = @($results | Where-Object { $_.ExitCode -ne 0 }) $status = if ($failed.Count -eq 0) { 'Success' } elseif ($failed.Count -lt $results.Count) { 'PartialFailure' } else { 'Failed' } return [pscustomobject]@{ Status = $status; Results = $results; Failed = $failed } } |