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 }
}