Files
winutil/functions/private/Invoke-WinUtilCurrentSystem.ps1
T
Panagiotis KaralioliosandClaude Opus 5.5 23f84b7f1a Detect WinGet-fallback apps in Get Installed when Chocolatey is selected (#5156)
* Detect WinGet-fallback apps in Chocolatey-mode Get Installed

In Chocolatey mode, apps with an empty or "na" Chocolatey ID are
installed through WinGet (Get-WinUtilSelectedPackages), but Get
Installed only checked choco list, so they were never selected.

After the Chocolatey match, collect those fallback apps with the same
rule as install routing. When there are any and WinGet is installed,
reuse the WinGet matcher with one winget list and keep only the
fallback apps. A WinGet failure warns and keeps the Chocolatey
results. WinGet mode and install routing are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Skip winget when no fallback app has a WinGet ID

Only treat an app as a WinGet fallback when it also has a usable
WinGet ID, matching Get-WinUtilSelectedPackages, so Chocolatey mode
does not run winget list when no app could be found that way.

Reword the Show Installed Apps note so it no longer says detection
always uses WinGet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 15:13:26 -05:00

165 lines
6.8 KiB
PowerShell

Function Invoke-WinUtilCurrentSystem {
<#
.SYNOPSIS
Checks to see what tweaks have already been applied and what programs are installed, and checks the according boxes
.EXAMPLE
InvokeWinUtilCurrentSystem -Checkbox "winget"
#>
param(
$CheckBox,
[switch]$BypassToggleStatusCache,
[switch]$StopOnReadError
)
if ($CheckBox -eq "choco") {
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
$packageId = ($_.Value.choco -split ";")[-1].Trim()
if ($packageId -ne "na" -and $packageId -in $apps) {
Write-Output $_.Key
}
}
# Apps without a Chocolatey package are installed through WinGet (see Get-WinUtilSelectedPackages),
# so check those against one winget list
$wingetFallbackKeys = @($sync.configs.applicationsHashtable.GetEnumerator() | Where-Object {
([string]::IsNullOrWhiteSpace([string]$_.Value.choco) -or $_.Value.choco -eq "na") -and
-not ([string]::IsNullOrWhiteSpace([string]$_.Value.winget) -or $_.Value.winget -eq "na")
} | ForEach-Object { $_.Key })
if ($wingetFallbackKeys.Count -gt 0 -and (Test-WinUtilPackageManager -winget) -eq "installed") {
try {
Invoke-WinUtilCurrentSystem -CheckBox "winget" | Where-Object { $_ -in $wingetFallbackKeys }
} catch {
Write-Warning "Could not check apps installed through WinGet: $($_.Exception.Message)"
}
}
}
if ($checkbox -eq "winget") {
$originalEncoding = [Console]::OutputEncoding
try {
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
$installedProgramOutput = @(winget list --accept-source-agreements --disable-interactivity 2>&1)
if ($LASTEXITCODE -ne 0) {
throw "winget list failed with exit code $LASTEXITCODE."
}
} finally {
[Console]::OutputEncoding = $originalEncoding
}
$installedProgramText = $installedProgramOutput -join "`n"
$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
$packageId = (($_.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
if ([string]::IsNullOrWhiteSpace($packageId) -or $packageId -eq "na") {
return
}
$packagePattern = "(?im)[^\S\r\n]{2,}$([regex]::Escape($packageId))(?=[^\S\r\n]{2,}|$)"
if ($installedProgramText -match $packagePattern) {
Write-Output $_.Key
}
}
}
if ($CheckBox -eq "tweaks") {
if (!(Test-Path 'HKU:\')) {$null = (New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS)}
$readErrorAction = if ($StopOnReadError) { "Stop" } else { "SilentlyContinue" }
$sync.configs.tweaks | Get-Member -MemberType NoteProperty | ForEach-Object {
$Config = $psitem.Name
$entry = $sync.configs.tweaks.$Config
$registryKeys = $entry.registry
$serviceKeys = $entry.service
$entryType = $entry.Type
if (($registryKeys -or $serviceKeys) -and $entryType -ne "Combobox") {
$Values = @()
if ($entryType -eq "Toggle") {
if (-not (Get-WinUtilToggleStatus $Config `
-BypassCache:$BypassToggleStatusCache `
-StopOnReadError:$StopOnReadError)) {
$values += $False
}
} else {
$registryMatchCount = 0
$registryTotal = 0
Foreach ($tweaks in $registryKeys) {
Foreach ($tweak in $tweaks) {
$registryTotal++
$regstate = $null
if (Test-Path $tweak.Path -ErrorAction $readErrorAction) {
if ($StopOnReadError) {
$regstate = (Get-ItemProperty -Path $tweak.Path -ErrorAction Stop).$($tweak.Name)
} else {
$regstate = Get-ItemProperty -Name $tweak.Name -Path $tweak.Path -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $($tweak.Name)
}
}
if ($null -eq $regstate) {
switch ($tweak.DefaultState) {
"true" {
$regstate = $tweak.Value
}
"false" {
$regstate = $tweak.OriginalValue
}
default {
$regstate = $tweak.OriginalValue
}
}
}
if ($regstate -eq $tweak.Value) {
$registryMatchCount++
}
}
}
if ($registryTotal -gt 0 -and $registryMatchCount -ne $registryTotal) {
$values += $False
}
}
Foreach ($tweaks in $serviceKeys) {
Foreach ($tweak in $tweaks) {
try {
$Service = Get-Service -Name $tweak.Name -ErrorAction $readErrorAction
} catch {
if ($StopOnReadError -and $_.FullyQualifiedErrorId -like "NoServiceFoundForGivenName*") {
# A removed optional service means this tweak is not applied; it does
# not make the registry and service state for every other tweak unknown.
$values += $False
continue
}
throw
}
if ($Service) {
$actualValue = $Service.StartType
$expectedValue = $tweak.StartupType
if ($expectedValue -ne $actualValue) {
$values += $False
}
} elseif ($StopOnReadError) {
$values += $False
}
}
}
if ($values -notcontains $false) {
Write-Output $Config
}
}
}
}
}