mirror of
https://github.com/ChrisTitusTech/winutil
synced 2026-06-04 14:17: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
303 lines
16 KiB
PowerShell
303 lines
16 KiB
PowerShell
function Find-TweaksByNameOrDescription {
|
|
<#
|
|
.SYNOPSIS
|
|
Searches through the Tweaks on the Tweaks Tab and hides all entries that do not match the search string
|
|
|
|
.DESCRIPTION
|
|
Filters tweak entries by name or description using literal string matching (no wildcard expansion).
|
|
Respects collapsed category state and handles null $sync gracefully.
|
|
Safe for rapid keystroke events; no terminal spam on error conditions.
|
|
|
|
.PARAMETER SearchString
|
|
The string to be searched for. Wildcards are treated as literal characters.
|
|
|
|
.NOTES
|
|
- Uses module-scope $sync (resolved via global/script fallback if needed)
|
|
- Performs literal matching (no wildcard expansion)
|
|
- Safely handles missing UI elements and null properties
|
|
- Protected by try/catch to prevent UI thread crashes
|
|
- PowerShell 5.1 compatible (no ternary operators, no advanced language features)
|
|
#>
|
|
param(
|
|
[Parameter(Mandatory = $false)]
|
|
[string]$SearchString = ""
|
|
)
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# 1. RESOLVE $SYNC WITH MULTI-LEVEL FALLBACK
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
if ($null -eq $Sync) {
|
|
$Sync = $global:sync
|
|
if ($null -eq $Sync) {
|
|
$Sync = $script:sync
|
|
}
|
|
}
|
|
|
|
# Validate that $Sync exists and has required structure
|
|
if ($null -eq $Sync) {
|
|
# Silent return - function called on every keystroke; no warning spam
|
|
return
|
|
}
|
|
|
|
if ($null -eq $Sync.Form) {
|
|
# Silent return - form not yet initialized
|
|
return
|
|
}
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# 2. GET REFERENCE TO TWEAKS PANEL
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
$tweaksPanel = $null
|
|
try {
|
|
$tweaksPanel = $Sync.Form.FindName("tweakspanel")
|
|
}
|
|
catch {
|
|
# Silent return - panel not found or disposed
|
|
return
|
|
}
|
|
|
|
if ($null -eq $tweaksPanel) {
|
|
# Silent return - panel doesn't exist
|
|
return
|
|
}
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# 3. HANDLE EMPTY/WHITESPACE SEARCH STRING - RESET TO DEFAULT STATE
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
if ([string]::IsNullOrWhiteSpace($SearchString)) {
|
|
try {
|
|
$tweaksPanel.Children | ForEach-Object {
|
|
$categoryBorder = $_
|
|
|
|
# Safely set visibility
|
|
if ($null -ne $categoryBorder) {
|
|
$categoryBorder.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
|
|
# Process each category
|
|
if ($categoryBorder -is [Windows.Controls.Border]) {
|
|
$dockPanel = $null
|
|
if ($null -ne $categoryBorder.Child) {
|
|
$dockPanel = $categoryBorder.Child
|
|
}
|
|
|
|
if ($dockPanel -is [Windows.Controls.DockPanel]) {
|
|
$itemsControl = $null
|
|
$itemsControl = $dockPanel.Children | Where-Object { $_ -is [Windows.Controls.ItemsControl] } | Select-Object -First 1
|
|
|
|
if ($null -ne $itemsControl) {
|
|
# Show all items in the category
|
|
foreach ($item in $itemsControl.Items) {
|
|
if ($null -ne $item) {
|
|
# Check if it's a category label (first Label in the ItemsControl)
|
|
if ($item -is [Windows.Controls.Label]) {
|
|
$item.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
elseif ($item -is [Windows.Controls.DockPanel] -or $item -is [Windows.Controls.StackPanel]) {
|
|
# Show all checkbox containers
|
|
$item.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
# Silent catch - UI element may be disposed
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# 4. PERFORM LITERAL SEARCH (NO WILDCARD EXPANSION)
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
try {
|
|
# Normalize search term once for the entire operation
|
|
$searchTerm = $SearchString
|
|
if ($null -eq $searchTerm) {
|
|
$searchTerm = ""
|
|
}
|
|
|
|
# Iterate through all categories
|
|
$tweaksPanel.Children | ForEach-Object {
|
|
$categoryBorder = $_
|
|
$categoryHasMatch = $false
|
|
|
|
if ($categoryBorder -is [Windows.Controls.Border]) {
|
|
$dockPanel = $null
|
|
if ($null -ne $categoryBorder.Child) {
|
|
$dockPanel = $categoryBorder.Child
|
|
}
|
|
|
|
if ($dockPanel -is [Windows.Controls.DockPanel]) {
|
|
$itemsControl = $null
|
|
$itemsControl = $dockPanel.Children | Where-Object { $_ -is [Windows.Controls.ItemsControl] } | Select-Object -First 1
|
|
|
|
if ($null -ne $itemsControl) {
|
|
$categoryLabel = $null
|
|
|
|
# Process all items (checkboxes, labels, panels) in the ItemsControl
|
|
for ($i = 0; $i -lt $itemsControl.Items.Count; $i++) {
|
|
$item = $itemsControl.Items[$i]
|
|
|
|
if ($null -eq $item) {
|
|
continue
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Check if this is a category label (usually first Label)
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
if ($item -is [Windows.Controls.Label]) {
|
|
$categoryLabel = $item
|
|
# Initially hide category label; show it only if matches found
|
|
$item.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Check if this is a DockPanel containing a tweak checkbox
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
elseif ($item -is [Windows.Controls.DockPanel]) {
|
|
$checkbox = $null
|
|
$label = $null
|
|
|
|
# Safely extract checkbox and label
|
|
$checkbox = $item.Children | Where-Object { $_ -is [Windows.Controls.CheckBox] } | Select-Object -First 1
|
|
$label = $item.Children | Where-Object { $_ -is [Windows.Controls.Label] } | Select-Object -First 1
|
|
|
|
# Check if tweak matches search criteria
|
|
$itemMatches = $false
|
|
|
|
if ($null -ne $label) {
|
|
$labelContent = $label.Content
|
|
$labelToolTip = $label.ToolTip
|
|
|
|
# Safely null-check properties
|
|
if ($null -eq $labelContent) {
|
|
$labelContent = ""
|
|
}
|
|
if ($null -eq $labelToolTip) {
|
|
$labelToolTip = ""
|
|
}
|
|
|
|
# Convert to string and perform LITERAL matching
|
|
$labelContentStr = [string]$labelContent
|
|
$labelToolTipStr = [string]$labelToolTip
|
|
|
|
# Use IndexOf for literal matching (no wildcard interpretation)
|
|
$contentMatch = $labelContentStr.IndexOf($searchTerm, [System.StringComparison]::OrdinalIgnoreCase) -ge 0
|
|
$toolTipMatch = $labelToolTipStr.IndexOf($searchTerm, [System.StringComparison]::OrdinalIgnoreCase) -ge 0
|
|
|
|
if ($contentMatch -or $toolTipMatch) {
|
|
$itemMatches = $true
|
|
}
|
|
}
|
|
|
|
# Set visibility based on match result
|
|
if ($itemMatches) {
|
|
$item.Visibility = [Windows.Visibility]::Visible
|
|
$categoryHasMatch = $true
|
|
}
|
|
else {
|
|
$item.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Check if this is a StackPanel containing a tweak checkbox
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
elseif ($item -is [Windows.Controls.StackPanel]) {
|
|
$checkbox = $null
|
|
$checkbox = $item.Children | Where-Object { $_ -is [Windows.Controls.CheckBox] } | Select-Object -First 1
|
|
|
|
$itemMatches = $false
|
|
|
|
if ($null -ne $checkbox) {
|
|
$checkboxContent = $checkbox.Content
|
|
$checkboxToolTip = $checkbox.ToolTip
|
|
|
|
# Safely null-check properties
|
|
if ($null -eq $checkboxContent) {
|
|
$checkboxContent = ""
|
|
}
|
|
if ($null -eq $checkboxToolTip) {
|
|
$checkboxToolTip = ""
|
|
}
|
|
|
|
# Convert to string and perform LITERAL matching
|
|
$checkboxContentStr = [string]$checkboxContent
|
|
$checkboxToolTipStr = [string]$checkboxToolTip
|
|
|
|
# Use IndexOf for literal matching (no wildcard interpretation)
|
|
$contentMatch = $checkboxContentStr.IndexOf($searchTerm, [System.StringComparison]::OrdinalIgnoreCase) -ge 0
|
|
$toolTipMatch = $checkboxToolTipStr.IndexOf($searchTerm, [System.StringComparison]::OrdinalIgnoreCase) -ge 0
|
|
|
|
if ($contentMatch -or $toolTipMatch) {
|
|
$itemMatches = $true
|
|
}
|
|
}
|
|
|
|
# Set visibility based on match result
|
|
if ($itemMatches) {
|
|
$item.Visibility = [Windows.Visibility]::Visible
|
|
$categoryHasMatch = $true
|
|
}
|
|
else {
|
|
$item.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Update category label visibility and expanded/collapsed state
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
if ($categoryHasMatch) {
|
|
# Show category label
|
|
if ($null -ne $categoryLabel) {
|
|
$categoryLabel.Visibility = [Windows.Visibility]::Visible
|
|
|
|
# Update category label to expanded state (change "+" to "-")
|
|
$labelContent = $categoryLabel.Content
|
|
if ($null -ne $labelContent) {
|
|
$labelStr = [string]$labelContent
|
|
|
|
# Safe string replacement without -replace regex
|
|
if ($labelStr.StartsWith("+ ")) {
|
|
$expandedLabel = "- " + $labelStr.Substring(2)
|
|
$categoryLabel.Content = $expandedLabel
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────
|
|
# Set category border visibility based on whether it has matches
|
|
# ────────────────────────────────────────────────────────────────
|
|
|
|
if ($categoryHasMatch) {
|
|
$categoryBorder.Visibility = [Windows.Visibility]::Visible
|
|
}
|
|
else {
|
|
$categoryBorder.Visibility = [Windows.Visibility]::Collapsed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
# Silent catch - UI elements may be disposed or in unexpected state
|
|
# Do not log to terminal as this function is called on every keystroke
|
|
}
|
|
}
|