mirror of
https://github.com/ChrisTitusTech/winutil
synced 2026-06-05 14:37:27 +00:00
743f9e3783
* Refactor: Secure literal search and defensive scope handling * Refactor: Secure literal search for Tweaks Tab * Merge branch 'ChrisTitusTech:main' into fix-search-security
137 lines
5.7 KiB
PowerShell
137 lines
5.7 KiB
PowerShell
function Find-AppsByNameOrDescription {
|
|
<#
|
|
.SYNOPSIS
|
|
Searches through the Apps on the Install Tab and hides all entries that do not match the string
|
|
|
|
.DESCRIPTION
|
|
Filters application entries by name or description using literal string matching.
|
|
Respects collapsed category state and handles null $sync gracefully.
|
|
|
|
.PARAMETER SearchString
|
|
The string to be searched for. Wildcards are treated as literal characters.
|
|
|
|
.NOTES
|
|
- Uses module-scope $sync (no parameter needed; inherits from caller's scope)
|
|
- Performs literal matching (no wildcard expansion)
|
|
- Safely handles missing hashtable keys and null UI elements
|
|
- Protected by try/catch to prevent UI thread crashes
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$SearchString = ""
|
|
)
|
|
|
|
# Validate that $sync exists and has required structure
|
|
if ($null -eq $sync) {
|
|
Write-Warning "Find-AppsByNameOrDescription: Global `$sync not found. Aborting search."
|
|
return
|
|
}
|
|
|
|
if ($null -eq $sync.ItemsControl) {
|
|
Write-Warning "Find-AppsByNameOrDescription: `$sync.ItemsControl not initialized. Aborting search."
|
|
return
|
|
}
|
|
|
|
if ($null -eq $sync.configs -or $null -eq $sync.configs.applicationsHashtable) {
|
|
Write-Warning "Find-AppsByNameOrDescription: `$sync.configs.applicationsHashtable not initialized. Aborting search."
|
|
return
|
|
}
|
|
|
|
try {
|
|
# Reset the visibility if the search string is empty or the search is cleared
|
|
if ([string]::IsNullOrWhiteSpace($SearchString)) {
|
|
$sync.ItemsControl.Items | ForEach-Object {
|
|
# Each item is a StackPanel container
|
|
$_.Visibility = [Windows.Visibility]::Visible
|
|
|
|
if ($_.Children.Count -ge 2) {
|
|
$categoryLabel = $_.Children[0]
|
|
$wrapPanel = $_.Children[1]
|
|
|
|
# Keep category label visible
|
|
$categoryLabel.Visibility = [Windows.Visibility]::Visible
|
|
|
|
# Respect the collapsed state of categories (indicated by + prefix)
|
|
if ($categoryLabel.Content -like "+*") {
|
|
$wrapPanel.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
else {
|
|
$wrapPanel.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
|
|
# Show all apps within the category
|
|
$wrapPanel.Children | ForEach-Object {
|
|
$_.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
# Escape wildcard characters for literal matching
|
|
$escapedSearchString = [System.Management.Automation.WildcardPattern]::Escape($SearchString)
|
|
|
|
# Perform search
|
|
$sync.ItemsControl.Items | ForEach-Object {
|
|
# Each item is a StackPanel container with Children[0] = label, Children[1] = WrapPanel
|
|
if ($_.Children.Count -ge 2) {
|
|
$categoryLabel = $_.Children[0]
|
|
$wrapPanel = $_.Children[1]
|
|
$categoryHasMatch = $false
|
|
|
|
# Keep category label visible
|
|
$categoryLabel.Visibility = [Windows.Visibility]::Visible
|
|
|
|
# Search through apps in this category
|
|
$wrapPanel.Children | ForEach-Object {
|
|
# Safely retrieve app entry from hashtable
|
|
$appTag = $_.Tag
|
|
$appEntry = $null
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($appTag) -and $sync.configs.applicationsHashtable.ContainsKey($appTag)) {
|
|
$appEntry = $sync.configs.applicationsHashtable[$appTag]
|
|
}
|
|
|
|
# Check if app matches search criteria
|
|
if ($null -ne $appEntry) {
|
|
$contentMatch = $appEntry.Content -like "*$escapedSearchString*"
|
|
$descriptionMatch = $appEntry.Description -like "*$escapedSearchString*"
|
|
|
|
if ($contentMatch -or $descriptionMatch) {
|
|
# Show the App and mark that this category has a match
|
|
$_.Visibility = [Windows.Visibility]::Visible
|
|
$categoryHasMatch = $true
|
|
}
|
|
else {
|
|
$_.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
else {
|
|
# Hide app if no entry found (data integrity issue)
|
|
$_.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
|
|
# If category has matches, show the WrapPanel and update the category label to expanded state
|
|
if ($categoryHasMatch) {
|
|
$wrapPanel.Visibility = [Windows.Visibility]::Visible
|
|
$_.Visibility = [Windows.Visibility]::Visible
|
|
# Update category label to show expanded state (-)
|
|
if ($categoryLabel.Content -like "+*") {
|
|
$categoryLabel.Content = $categoryLabel.Content -replace "^\+ ", "- "
|
|
}
|
|
}
|
|
else {
|
|
# Hide the entire category container if no matches
|
|
$_.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-Warning "Find-AppsByNameOrDescription: An error occurred during search: $_"
|
|
# Fail gracefully - do not crash the UI thread
|
|
return
|
|
}
|
|
}
|