Skip to content

Instantly share code, notes, and snippets.

@The-Running-Dev
Last active April 8, 2025 16:01
Show Gist options
  • Save The-Running-Dev/4bb7587cd5b7471891d62a0fab97b7b7 to your computer and use it in GitHub Desktop.
Save The-Running-Dev/4bb7587cd5b7471891d62a0fab97b7b7 to your computer and use it in GitHub Desktop.
A PowerShell Script to Upgrade All Installed Software
param (
[switch] $verbose
)
# Function to log messages
function Log-Message {
param (
[string] $message,
[string] $type = 'INFO'
)
$timestamp = Get-Date -Format 'yyyy.MM.dd HH:mm:ss'
$logMessage = "$timestamp [$type] $message"
Write-Output $logMessage
Add-Content -Path $logFile -Value $logMessage
}
$logBaseName = (Get-Item $MyInvocation.MyCommand.Path).BaseName
$logsPath = Join-Path $PSScriptRoot $logBaseName
$logFile = Join-Path $logsPath "$logBaseName.log"
if (-not (Test-Path $logsPath)) {
New-Item -ItemType Directory -Path $logsPath | Out-Null
}
try {
Log-Message "Checking for Available Updates..."
# Get the output of 'winget upgrade'
$output = winget upgrade
# Find header line number
$headerLineMatch = $output | Select-String -Pattern "^Name\s+Id\s+Version\s+Available\s+Source"
if ($headerLineMatch) {
$startIndex = [int]$headerLineMatch.LineNumber
# Skip header and separator using corrected range syntax
$dataLines = $output[($startIndex + 1)..($output.Count - 1)] |
Where-Object { $_ -match "^\S" -and $_ -notmatch "upgrade[s]? available|version numbers|pins that prevent|^-+$" }
# Get header text
$headerText = $headerLineMatch.Matches[0].Value
# Determine exact start positions of each column
$idIndex = $headerText.IndexOf('Id')
$versionIndex = $headerText.IndexOf('Version')
$availableIndex = $headerText.IndexOf('Available')
$sourceIndex = $headerText.IndexOf('Source')
# Prepare list for structured data
$parsedData = @()
# Parse each line using substring slicing
foreach ($line in $dataLines) {
# Safety: ensure line is long enough
if ($line.Length -gt $sourceIndex) {
$parsedData += [PSCustomObject]@{
Name = $line.Substring(0, $idIndex).Trim()
Id = $line.Substring($idIndex, $versionIndex - $idIndex).Trim()
Version = $line.Substring($versionIndex, $availableIndex - $versionIndex).Trim()
Available = $line.Substring($availableIndex, $sourceIndex - $availableIndex).Trim()
Source = $line.Substring($sourceIndex).Trim()
}
}
}
# Convert to JSON
$updates = $parsedData | ConvertTo-Json -Depth 2
} else {
Write-Host "Could not find column headers in winget output."
}
$updatesObject = $updates | ConvertFrom-Json
foreach ($update in $updatesObject) {
$name = $update.Name
$id =$update.Id
$currentVersion = $update.Version
$availableVersion = $update.Available
$source = $update.Source
Log-Message "New Version Found: $id ($availableVersion)"
try {
$installCommand = "& winget upgrade --id $id --accept-source-agreements --accept-package-agreements"
if (-not $verbose) {
$installCommand += " --silent"
}
$logOutput = Join-Path $logsPath "$id.log"
$logError = Join-Path $logsPath "$id-error.log"
Start-Process -FilePath "powershell" `
-ArgumentList "-Command $installCommand" `
-Wait `
-NoNewWindow `
-RedirectStandardOutput $logOutput `
-RedirectStandardError $logError
Log-Message "Package Upgraded: $id"
} catch {
Log-Message "Upgrade Failed: $($id), $($_.Exception.Message)" "ERROR"
}
}
} catch {
Log-Message "WinGet Update Check Failed: $($_.Exception.Message)" "ERROR"
exit 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment