-
-
Save alkampfergit/19f89c1a93cc1e7b9ec9bf501f2b9134 to your computer and use it in GitHub Desktop.
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 |
@houtianze I tried to run your function, but it generates an error.
Line |
1 | while (-not $lines[$fl].StartsWith("Name"))
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| You cannot call a method on a null-valued expression.
That's why I created a function that creates a array with an object for each value.
Of course, it can be improved, but we'll leave that for later...
function Get-Winget-Upgradables {
$apps = @()
$start = $false
# Remove unnecessary first lines
winget upgrade --accept-source-agreements --include-unknown | foreach-object {
if ( $psitem -match '^([-]+)$' ) {
$start = $true
}
elseif ( $start -eq $true ) {
$apps += $psitem
}
}
# Remove the last line
$apps = $apps[ 0..( $apps.length - 2 ) ]
# Loop the array and create an object for any value
$index = 0
$apps.foreach({
$pattern = "^(.+\u2026?)\s+([\u2026\.\w\+]+)\s+([\.\d]+)\s+([\.\d]+)\s+([\w]+)$"
$apps[ $index ] = @{
'name' = ( $apps[ $index ] -replace $pattern, '$1' ) -replace '\s+$', ''
'id' = $apps[ $index ] -replace $pattern, '$2'
'version' = $apps[ $index ] -replace $pattern, '$3'
'available' = $apps[ $index ] -replace $pattern, '$4'
'source' = $apps[ $index ] -replace $pattern, '$5'
}
$index += 1
})
return $apps
}
@F4Jonatas Thanks for the feedback. I tried again and it works on my computer, my guess is that your system is set to some non-English language that shows a localized string of Name
and that's why the function failed to locate the line and the index ran out of bound. Locating using ---...
is a better option in this case.
In addition to the language setting, it also makes a difference whether you use Powershell, Powershell ISE or Visual Studio Code.
This has a particular effect on the truncation of text. Sometimes it is a character string like  and sometimes it is a special character that looks like 3 dots (Unicode ellipsis [char]0x2026).
I encountered this problem in a similar project.
Thanks for the usefl script. I made some changes:
--include-unknown
to thewinget upgrade
command to avoid the issue mentioned below