Last active
January 14, 2024 19:38
-
-
Save alkampfergit/19f89c1a93cc1e7b9ec9bf501f2b9134 to your computer and use it in GitHub Desktop.
Winget upgrade output parsed into a real Powershell Object
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Software { | |
[string]$Name | |
[string]$Id | |
[string]$Version | |
[string]$AvailableVersion | |
} | |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 | |
$upgradeResult = winget upgrade | Out-String | |
$lines = $upgradeResult.Split([Environment]::NewLine) | |
# Find the line that starts with Name, it contains the header | |
$fl = 0 | |
while (-not $lines[$fl].StartsWith("Name")) | |
{ | |
$fl++ | |
} | |
# Line $i has the header, we can find char where we find ID and Version | |
$idStart = $lines[$fl].IndexOf("Id") | |
$versionStart = $lines[$fl].IndexOf("Version") | |
$availableStart = $lines[$fl].IndexOf("Available") | |
$sourceStart = $lines[$fl].IndexOf("Source") | |
# Now cycle in real package and split accordingly | |
$upgradeList = @() | |
For ($i = $fl + 1; $i -le $lines.Length; $i++) | |
{ | |
$line = $lines[$i] | |
if ($line.Length -gt ($availableStart + 1) -and -not $line.StartsWith('-')) | |
{ | |
$name = $line.Substring(0, $idStart).TrimEnd() | |
$id = $line.Substring($idStart, $versionStart - $idStart).TrimEnd() | |
$version = $line.Substring($versionStart, $availableStart - $versionStart).TrimEnd() | |
$available = $line.Substring($availableStart, $sourceStart - $availableStart).TrimEnd() | |
$software = [Software]::new() | |
$software.Name = $name; | |
$software.Id = $id; | |
$software.Version = $version | |
$software.AvailableVersion = $available; | |
$upgradeList += $software | |
} | |
} | |
$upgradeList | Get-Member | |
$upgradeList | Format-Table |
My output includes the following line at the end:
2 package(s) have version numbers that cannot be determined. Use --include-unknown to see all results.
and it doesn't get handled correctly,
For ($i = $fl + 1; $i -le $lines.Length; $i++)
{
$line = $lines[$i]
if ($line.Length -gt ($availableStart + 1) -and -not $line.StartsWith('-') -and -not $line.Contains("package(s) have version numbers"))
{
Here is the suggested edit that just ignores these lines
Thanks for the usefl script. I made some changes:
- Added
--include-unknown
to thewinget upgrade
command to avoid the issue mentioned below - Becasue some of the software installed on my system has non-ascii name, I worked around the quirks
- Made this code snippet to a function. (This is just for my use case)
function Get-Winget-Upgradables
{
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$upgradeResult = winget upgrade --include-unknown | Out-String
$lines = $upgradeResult.Split([Environment]::NewLine)
# Find the line that starts with Name, it contains the header
$fl = 0
while (-not $lines[$fl].StartsWith("Name"))
{
$fl++
}
# Line $i has the header, we can find char where we find ID and Version
$idStart = $lines[$fl].IndexOf("Id")
$versionStart = $lines[$fl].IndexOf("Version")
$availableStart = $lines[$fl].IndexOf("Available")
$sourceStart = $lines[$fl].IndexOf("Source")
# Now cycle in real package and split accordingly
$upgradeList = @()
For ($i = $fl + 1; $i -le $lines.Length; $i++)
{
$line = $lines[$i]
if ($line.Length -gt ($sourceStart + 1) -and -not $line.StartsWith('-'))
{
# when the name of the software is non-ascii, rune counting becomes messy.
$nameWithSpaceEnding = $line.Substring(0, $idStart)
$nameWithSpaceEndingByteCount = [System.Text.Encoding]::UTF8.GetByteCount($nameWithSpaceEnding)
$nameOffset = ($nameWithSpaceEndingByteCount - $nameWithSpaceEnding.Length) / 2;
$name = $line.Substring(0, $idStart - $nameOffset).Trim()
# need to Trim() instead of TrimEnd() because somehow when run with | Out-String,
# the winget output of name becomse ellipsized... Trim() would work around this.
$id = $line.Substring($idStart - $nameOffset, $versionStart - $idStart).Trim()
$version = $line.Substring($versionStart - $nameOffset, $availableStart - $versionStart).Trim()
$available = $line.Substring($availableStart - $nameOffset, $sourceStart - $availableStart).Trim()
$software = [WingetSoftware]::new()
$software.Name = $name;
$software.Id = $id;
$software.Version = $version
$software.AvailableVersion = $available;
$upgradeList += $software
}
}
return $upgradeList;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Done!