functions/Get-WGInstalled.ps1
Function Get-WGInstalled { [cmdletbinding()] [OutputType("WGInstalled")] Param( [Parameter(Position = 0, HelpMessage = "Specify a winget source")] [ValidateNotNullOrEmpty()] [string]$Source = "winget" ) Begin { Write-Verbose "[$((Get-Date).TimeofDay) BEGIN ] Starting $($myinvocation.mycommand)" $tmpFile = "$env:temp\wgExport_{0}.json" -f (Get-Date -Format yyyymmdd) $Winget = Get-WGPath } #begin Process { Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Building list of packages with a winget source" [void](& $winget export -s winget -o $tmpFile --include-versions) if (Test-Path -Path $tmpFile) { #import the json file Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Importing temporary JSON data" $json = Get-Content -Path $tmpFile | ConvertFrom-Json #get the packages $count = $json.Sources.packages.count Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Found $count packages. Getting details." $jobList = [system.collections.generic.list[object]]::new() $wingetPath = $winget foreach ($pkg in $json.Sources.packages) { Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] $($pkg.PackageIdentifier)" $i++ #9 August 2022 Using Threadjobs to get online package details for better scaling - JDH $sb = { Param([object]$pkg, [string]$source, [string]$wingetPath) Function _parseVersion { #parse out odd characters from version strings [cmdletbinding()] Param([string]$VersionString) if ($versionString -match "unknown") { $out = $null } elseif ($VersionString -match "[\<\>]") { $out = ($VersionString -replace $matches.values, "").Trim() } else { $out = $VersionString.Trim() } $out } try { $show = & $wingetPath show --id $pkg.PackageIdentifier --source $source $pkg | Add-Member -MemberType NoteProperty -Name show -Value $show -PassThru -Force } #Try catch { #$show | Out-String | Write-Host -fore red Write-Warning "There was an unknown problem with $($pkg.PackageIdentifier)" } } $joblist.add($(Start-ThreadJob -ScriptBlock $sb -ArgumentList $pkg, $source, $wingetPath -Name wg)) } #foreach pkg #process jobs Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting thread job results" Do { $joblist.FindAll({ $args[0].state -eq 'Completed' }) | ForEach-Object { #convert the job output to a defined object $jobresult = $_ | Receive-Job $show = $jobresult.show | Where-Object { $_ -notmatch "(\d+%|\d MB|\s+)$" -and $_.length -gt 0 } $show | Out-String | Write-Debug Try { $yml = $show.replace(" - ", " ") | Select-Object -Skip 1 | Where-Object { $_ -match "^(\s+)?(\b(\w+)\b).*:" } | ConvertFrom-Yaml -ErrorAction stop } Catch { Write-Warning "Failed to convert to YAML" $show | Out-String | Write-Warning } [regex]$rxname = "(?<name>(?<=\w\s).*)(?=\s\[(?<id>[\S\.]+)\])" $id = $jobresult.PackageIdentifier #$rxname.match($show[0]).groups["id"].value Write-Verbose "[$((Get-Date).TimeofDay) PROCESS] Getting installed version for $id" # 8/16/2022 Need to account for multiple versions JDH $installed = _parseVersion $jobresult.version #($json.sources.packages.where({$_.packageIdentifier -eq $id}).version) $online = _parseVersion (($show | Select-String "$($localized.version):") -split "$($localized.version): ")[1].trim() $out = [wginstalled]::new() $out.Name = $rxname.match($show[0]).groups["name"].value $out.ID = $id $out.InstalledVersion = $installed $out.Version = $online $out.Publisher = $yml.$($localized.Publisher) $out.PublisherUrl = $yml.$($localized.PublisherURL) $out.PublisherSupportUrl = $yml.$($localized.PublisherSupportUrl) $out.Author = $yml.$($localized.Author) $out.Moniker = $yml.$($localized.Moniker) $out.Description = $yml.$($localized.Description) $out.Homepage = $yml.$($Localized.homepage) $out.Source = $Source $out [void]$joblist.remove($_) } } Until ($jobList.count -eq 0) } else { Write-Warning "There was a problem getting a list of installed packages." } } #process End { if (Test-Path -Path $tmpFile) { #always remove the temp file Remove-Item $tmpFile -WhatIf:$false } if (Get-Job -Name wg) { #always remove the threadjob Remove-Job -Name wg -Force -WhatIf:$false } Write-Verbose "[$((Get-Date).TimeofDay) END ] Ending $($myinvocation.mycommand)" } #end } #close Get-WGInstalled Update-TypeData -TypeName WGInstalled -MemberType ScriptProperty -MemberName Update -Value { <# compare versions first at [version] type, then as a simple string comparison to determine if there is an upgrade available. #> $a = $null $z = $null if (([version]::tryparse($this.onlineversion, [ref]$a)) -AND ([version]::tryparse($this.installedversion, [ref]$z))) { $a -gt $z } elseif ($null -eq $this.InstalledVersion) { $False } else { $this.installedversion -ne $This.onlineversion } } -Force |