Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/src/content/docs/code-reference/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ Invoke-WinUtilISOCleanAndReset (optional)
**Modification Safety**:
- All registry changes are documented in a script (reversible)
- Original ISO never modified; only working copy
- Logged to `WinUtil_Win11ISO.log` for debugging
- Logged via `Write-WinUtilLog` to the main WinUtil session log. The output is additionally echoed to the host if `Start-Transcript` is active.
- Temporary files are cleaned up reliably; if batch deletion fails and file-by-file retry also fails, the reset flow aborts gracefully rather than displaying a false completion.
- DISM handles image dismount with automatic cleanup on error

### Win11 Creator Registry Tweaks
Expand Down
461 changes: 385 additions & 76 deletions functions/private/Find-AppsByNameOrDescription.ps1

Large diffs are not rendered by default.

374 changes: 85 additions & 289 deletions functions/private/Find-TweaksByNameOrDescription.ps1

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions functions/private/Find-WinUtilPackageManagerApps.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
function Find-WinUtilPackageManagerApps {
<#
.SYNOPSIS
Searches the repository of the currently selected package manager (Winget or Choco).

.DESCRIPTION
Executes a search query against Winget or Chocolatey CLI and parses output
into custom objects with Name and Id properties. Handles errors gracefully.

.PARAMETER SearchString
The term to search for in the package manager repository.

.PARAMETER ManagerPreference
The selected package manager preference ("Winget" or "Choco").

.NOTES
- Keep parser lightweight and fail safe without external dependencies.
#>
param(
[Parameter(Mandatory = $false)]
[string]$SearchString = "",

[Parameter(Mandatory = $false)]
[string]$ManagerPreference = "Winget"
)

if ([string]::IsNullOrWhiteSpace($SearchString)) {
return ,@()
}

$results = [System.Collections.Generic.List[PSObject]]::new()

try {
if ($ManagerPreference -eq "Choco") {
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
return ,@()
}

# choco --limit-output provides id|version format
$out = @(choco search $SearchString --limit-output 2>&1)
if ($LASTEXITCODE -ne 0) { return ,@() }
foreach ($line in $out) {
if ([string]::IsNullOrWhiteSpace($line)) { continue }
$parts = [string]$line -split '\|'
if ($parts.Count -ge 2 -and -not [string]::IsNullOrWhiteSpace($parts[0])) {
$id = $parts[0].Trim()
if ($id -notmatch '\s') {
$results.Add([pscustomobject]@{
Name = $id
Id = $id
})
}
}
}
}
else {
if (-not (Get-Command winget -ErrorAction SilentlyContinue)) {
return ,@()
}

$originalEncoding = [Console]::OutputEncoding
try {
try {
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
} catch {
# Ignore encoding failure, proceed with search
}
$out = @(winget search $SearchString --accept-source-agreements --disable-interactivity 2>&1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve WinGet source for dynamic results

On default WinGet installs, winget search can return rows from both winget and msstore sources (Microsoft documents --source as the way to narrow search results). This command neither constrains the source nor parses the Source column, so the dynamic entry later stores only $res.Id; Install-WinUtilProgramWinget then forces --source winget unless the ID is prefixed with msstore:. Store-only results surfaced here will be selectable but fail to install, so either search only --source winget or carry the parsed source through.

Useful? React with 👍 / 👎.

if ($LASTEXITCODE -ne 0) { return ,@() }
}
finally {
try { [Console]::OutputEncoding = $originalEncoding } catch {}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

$lines = ($out -join "`n") -split '\r?\n'
$dashIndex = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match '^-{3,}') {
$dashIndex = $i
break
}
}

if ($dashIndex -ge 0) {
for ($i = $dashIndex + 1; $i -lt $lines.Count; $i++) {
$l = $lines[$i].Trim()
if ([string]::IsNullOrWhiteSpace($l)) { continue }

$cols = @($l -split '\s{2,}')
if ($cols.Count -ge 2) {
$name = $cols[0].Trim()
$id = $cols[1].Trim()
if ($name -and $id -and ($id -notmatch '\s')) {
$results.Add([pscustomobject]@{
Name = $name
Id = $id
})
}
}
}
}
}
}
catch {
Write-Warning "Find-WinUtilPackageManagerApps: Search failed for manager '$ManagerPreference': $_"
return ,@()
}

return ,($results.ToArray())
}
63 changes: 27 additions & 36 deletions functions/private/Invoke-WinUtilCurrentSystem.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Function Invoke-WinUtilCurrentSystem {
)
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()
foreach ($app in $sync.configs.applicationsHashtable.GetEnumerator()) {
$packageId = ($app.Value.choco -split ";")[-1].Trim()
if ($packageId -ne "na" -and $packageId -in $apps) {
Write-Output $_.Key
Write-Output $app.Key
}
}
}
Expand All @@ -36,15 +36,15 @@ Function Invoke-WinUtilCurrentSystem {
}
$installedProgramText = $installedProgramOutput -join "`n"

$sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
$packageId = (($_.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
foreach ($app in $sync.configs.applicationsHashtable.GetEnumerator()) {
$packageId = (($app.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
if ([string]::IsNullOrWhiteSpace($packageId) -or $packageId -eq "na") {
return
continue
}

$packagePattern = "(?im)[^\S\r\n]{2,}$([regex]::Escape($packageId))(?=[^\S\r\n]{2,}|$)"
if ($installedProgramText -match $packagePattern) {
Write-Output $_.Key
Write-Output $app.Key
}
}
}
Expand All @@ -53,27 +53,26 @@ Function Invoke-WinUtilCurrentSystem {

if (!(Test-Path 'HKU:\')) {$null = (New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_USERS)}

$sync.configs.tweaks | Get-Member -MemberType NoteProperty | ForEach-Object {

$Config = $psitem.Name
$entry = $sync.configs.tweaks.$Config
foreach ($prop in $sync.configs.tweaks.PSObject.Properties) {
$Config = $prop.Name
$entry = $prop.Value
$registryKeys = $entry.registry
$serviceKeys = $entry.service
$entryType = $entry.Type

if (($registryKeys -or $serviceKeys) -and $entryType -ne "Combobox") {
$Values = @()
$allMatch = $true

if ($entryType -eq "Toggle") {
if (-not (Get-WinUtilToggleStatus $Config)) {
$values += $False
$allMatch = $false
}
} else {
$registryMatchCount = 0
$registryTotal = 0

Foreach ($tweaks in $registryKeys) {
Foreach ($tweak in $tweaks) {
foreach ($tweaks in $registryKeys) {
foreach ($tweak in $tweaks) {
$registryTotal++
$regstate = $null

Expand All @@ -83,15 +82,9 @@ Function Invoke-WinUtilCurrentSystem {

if ($null -eq $regstate) {
switch ($tweak.DefaultState) {
"true" {
$regstate = $tweak.Value
}
"false" {
$regstate = $tweak.OriginalValue
}
default {
$regstate = $tweak.OriginalValue
}
"true" { $regstate = $tweak.Value }
"false" { $regstate = $tweak.OriginalValue }
default { $regstate = $tweak.OriginalValue }
}
}

Expand All @@ -102,25 +95,23 @@ Function Invoke-WinUtilCurrentSystem {
}

if ($registryTotal -gt 0 -and $registryMatchCount -ne $registryTotal) {
$values += $False
$allMatch = $false
}
}

Foreach ($tweaks in $serviceKeys) {
Foreach ($tweak in $tweaks) {
$Service = Get-Service -Name $tweak.Name

if ($Service) {
$actualValue = $Service.StartType
$expectedValue = $tweak.StartupType
if ($expectedValue -ne $actualValue) {
$values += $False
}
foreach ($tweaks in $serviceKeys) {
foreach ($tweak in $tweaks) {
$Service = Get-Service -Name $tweak.Name -ErrorAction SilentlyContinue
$expectedType = if ($tweak.StartupType -eq "Disable") { "Disabled" } else { $tweak.StartupType }
if (-not $Service -or $expectedType -ne $Service.StartType) {
$allMatch = $false
break
}
}
if (-not $allMatch) { break }
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if ($values -notcontains $false) {
if ($allMatch) {
Write-Output $Config
}
}
Expand Down
Loading