Note: Run As Administrator

# winget needs an elevated session to upgrade machine-scoped packages.
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

if (-not $isAdmin) {
    throw "This script must be run as Administrator."
}

# Log stdout/stderr separately so a failed upgrade is easy to diagnose after the fact.
$logPath   = Join-Path $env:TEMP 'winget-upgrade-all.log'
$errorPath = Join-Path $env:TEMP 'winget-upgrade-all-error.log'
$timeoutMs = [int][TimeSpan]::FromMinutes(30).TotalMilliseconds

# Upgrade everything winget knows about, without any prompts.
$arguments = @(
    'upgrade'
    '--all'
    '--silent'
    '--accept-package-agreements'
    '--accept-source-agreements'
    '--include-unknown'
    '--disable-interactivity'
)

$process = Start-Process -FilePath 'winget.exe' `
    -ArgumentList $arguments `
    -NoNewWindow `
    -PassThru `
    -RedirectStandardOutput $logPath `
    -RedirectStandardError $errorPath

try {
    if (-not $process.WaitForExit($timeoutMs)) {
        # Kill winget and any installer processes it launched.
        & taskkill.exe /PID $process.Id /T /F *> $null
        $process.WaitForExit()

        throw "winget exceeded the 30-minute timeout and was terminated."
    }

    $exitCode = $process.ExitCode

    # Return a summary object instead of raw exit code so callers can log/branch on it.
    [pscustomobject]@{
        ExitCode = $exitCode
        Succeeded = ($exitCode -eq 0)
        OutputLog = $logPath
        ErrorLog  = $errorPath
    }
}
finally {
    $process.Dispose()
}