From 6360523d734b03e13706e817daadb00ca8a7e6b4 Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Tue, 9 Sep 2025 21:54:32 +0300 Subject: [PATCH 1/8] :sparkles: Wildcard patterns and .searchignore No need to iterate over all the filesystem as a pattern like `D:\*\.git\` will do. Patterns are now defined in a .searchignore file --- .searchignore | 22 +++++ README.md | 6 ++ Windows-Search-Exceptions.ps1 | 162 ++++++++++++++++++++++++++++++++++ Windows-Search.ps1 | 91 ------------------- 4 files changed, 190 insertions(+), 91 deletions(-) create mode 100644 .searchignore create mode 100644 Windows-Search-Exceptions.ps1 delete mode 100644 Windows-Search.ps1 diff --git a/.searchignore b/.searchignore new file mode 100644 index 0000000..dd79b91 --- /dev/null +++ b/.searchignore @@ -0,0 +1,22 @@ +# Drive letters required, wildcards accepted + +C:\*\.git\ +D:\*\.git\ +E:\*\.git\ + +C:\*\node_modules\ +D:\*\node_modules\ +E:\*\node_modules\ + +C:\*\FileHistory\ +D:\*\FileHistory\ +E:\*\FileHistory\ + +# Windows Backups can also be in the root of the drive +C:\FileHistory\ +D:\FileHistory\ +E:\FileHistory\ + +; Valid comment line +// Another comment line +# Empty lines are also ignored diff --git a/README.md b/README.md index 953ca06..ba3a9cc 100644 --- a/README.md +++ b/README.md @@ -58,3 +58,9 @@ This script helps ensure your development files remain visible and searchable in This script modifies sensitive keys of the Windows Registry and should be used with caution. Ensure you have a backup or system restore point before proceeding. Use at your own risk — the author is not responsible for any damage or data loss resulting from its use. + +## TODO + +- [ ] #todo schtasks solution to run once as SYSTEM +- [ ] #todo Add warning that Group Policy setting will not fix parent folders of .git +- [ ] #todo Is Rebuild index necessary? I see that it added Start Menu, Users minus AppData... diff --git a/Windows-Search-Exceptions.ps1 b/Windows-Search-Exceptions.ps1 new file mode 100644 index 0000000..7f96227 --- /dev/null +++ b/Windows-Search-Exceptions.ps1 @@ -0,0 +1,162 @@ +# Windows Search Indexing - Wildcard Exclusions + +# Configure Windows Search to exclude specific folders via wildcard patterns. +# For fixing a Windows bug that excludes repo parent folders instead of just .git\ + +####################################################### +# WARNING! This script will RESET EXISTING EXCLUSIONS.# +####################################################### + +# Exclusion patterns are defined in `.searchignore` file, see repo. +# Backup your registry before running this script. + +# Usage: +# 1. Start from a clean slate, no indexed locations. +# 2. Edit the provided `.searchignore` file with your wildcard patterns, one per line. +# Make sure to include eg. D:\*\.git\ to fix the bug that excludes parent repos. +# 3. Install PsExec from Sysinternals: https://learn.microsoft.com/en-us/sysinternals/downloads/psexec +# choco install psexec +# 4. In an elevated command prompt: +# psexec -i -s powershell.exe -File ".\Windows-Search-Exceptions.ps1" +# 5. This should add the rules. You may add your indexed locations now. +# Git repos and your other wildcard patterns won't be excluded anymore. + +# The script will: +# - Stop the Windows Search service +# - Reset existing exclusions +# - Add exclusions from the `.searchignore` file +# - Restart the Windows Search service + +if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -ne "NT AUTHORITY\SYSTEM") { + Write-Warning "This script must be run as SYSTEM to modify registry permissions. + Use PsExec: psexec -i -s powershell.exe -File $($MyInvocation.MyCommand.Path)" + exit 1 +} + +function Stop-SearchService { + Stop-Service WSearch -Force + Write-Host "Search service stopped" +} + +function Start-SearchService { + Start-Service WSearch + Write-Host "Search service started" +} + +function Get-RootGuid { + $roots = Get-ChildItem -Path $searchRoots -ErrorAction SilentlyContinue + foreach ($root in $roots) { + $props = Get-ItemProperty -Path $root.PSPath -ErrorAction SilentlyContinue + if ($props.URL -match "file:///$volumeLetter\\[([0-9a-fA-F\-]{36})\]\\") { + return $matches[1] + } + } + Write-Host "Warning: using default GUID" -ForegroundColor Yellow + return $defaultGuid +} + +function Reset-Exclusions { + $subKeys = Get-ChildItem -Path $registryBase + foreach ($subKey in $subKeys) { + Remove-Item -Path $subKey.PSPath -Recurse -Force + } + Write-Host "Exclusions reset" +} + +function Initialize-DefaultSearch { + param ( + [String]$path, + [String]$url, + [Int]$isDefault + ) + $subKeyPath = Join-Path $registryBase $counter + New-Item -Path $subKeyPath -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Container" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Default" -PropertyType DWord -Value $isDefault -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Include" -PropertyType DWord -Value 1 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "NoContent" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Policy" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Suppress" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "URL" -PropertyType String -Value $url -Force | Out-Null + $global:counter++ + Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null + Write-Host "Included folder $counter : $path" -ForegroundColor Green +} + +function Set-SearchExclusions { + param ( + [String]$Path + ) + # This function reads exclusion patterns from a `.searchignore` file + # and creates corresponding registry entries for each pattern. + + # --- Configuration --- + # Define the path to the .searchignore file. + # $PSScriptRoot is an automatic variable that contains the full path + # of the script's parent directory. + $ignoreFilePath = Join-Path $PSScriptRoot ".searchignore" + + # --- Pre-flight Check --- + # Check if the .searchignore file actually exists before we try to read it. + if (-not (Test-Path $ignoreFilePath)) { + Write-Error "The .searchignore file was not found at $ignoreFilePath" + # Stop the function if the file is missing. + return + } + + # --- Processing --- + # Read all patterns from the .searchignore file into an array. + $patterns = Get-Content -Path $ignoreFilePath + + # Iterate over each pattern (which is one line from the file). + foreach ($pattern in $patterns) { + # Skip any empty or whitespace-only lines in the file + # Comment with # or ; or // at the begining of the line + if ($pattern -match '^\s*(#|;|//)') { + continue + } + + # The subKeyPath is created by joining the base registry path and the current counter. + $subKeyPath = Join-Path $registryBase $counter + + # Construct the URL as requested: "file:///" followed by the pattern from the file. + $url = "file:///$volumeLetter$pattern" + + # Create the new registry key for the current pattern. + # Write-Host $subKeyPath $url -ForegroundColor Magenta # DEBUG + New-Item -Path $subKeyPath -Force | Out-Null + + # Set all the required registry properties for this key. + New-ItemProperty -Path $subKeyPath -Name "Container" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Default" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Include" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "NoContent" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Policy" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "Suppress" -PropertyType DWord -Value 0 -Force | Out-Null + New-ItemProperty -Path $subKeyPath -Name "URL" -PropertyType String -Value $url -Force | Out-Null + + # Increment the global counter for the next item. + $global:counter++ + + # Update the master ItemCount in the parent registry key. + # Write-Host $global:counter -ForegroundColor Magenta + # DEBUG + Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null + + # Provide feedback to the console that the pattern was processed. + Write-Host "Added pattern $counter : $pattern" -ForegroundColor Green + } +} + +$registryBase = "HKLM:\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\WorkingSetRules" +$searchRoots = "HKLM:\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\SearchRoots" +$volumeLetter = "C:\" +$defaultGuid = "98da7f83-099d-4591-afed-be354bdaf82b" +$guid = Get-RootGuid +$global:counter = 0 # Key with last number that exists in Registry, not incremented by 1 + +Stop-SearchService +Reset-Exclusions +Initialize-DefaultSearch -path "$volumeLetter" -url "file:///$volumeLetter[$guid]\" -isDefault 0 +Set-SearchExclusions -Path "$volumeLetter" +Start-SearchService diff --git a/Windows-Search.ps1 b/Windows-Search.ps1 deleted file mode 100644 index 5d4ece1..0000000 --- a/Windows-Search.ps1 +++ /dev/null @@ -1,91 +0,0 @@ -function Service-Stop { - Stop-Service WSearch -Force - Write-Host "Search service stopped" -} - -function Service-Start { - Start-Service WSearch - Write-Host "Search service started" -} - -function Get-Root-Guid { - $roots = Get-ChildItem -Path $searchRoots -ErrorAction SilentlyContinue - foreach ($root in $roots) { - $props = Get-ItemProperty -Path $root.PSPath -ErrorAction SilentlyContinue - if ($props.URL -match "file:///$volumeLetter\\[([0-9a-fA-F\-]{36})\]\\") { - return $matches[1] - } - } - Write-Host "Warning: using default GUID" -ForegroundColor Yellow - return $defaultGuid -} - -function Clean-Init { - $subKeys = Get-ChildItem -Path $registryBase - foreach ($subKey in $subKeys) { - Remove-Item -Path $subKey.PSPath -Recurse -Force - } - Write-Host "Exclusions reset" -} - -function Default-Search { - param ( - [String]$path, - [String]$url, - [Int]$isDefault - ) - $subKeyPath = Join-Path $registryBase $counter - New-Item -Path $subKeyPath -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Container" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Default" -PropertyType DWord -Value $isDefault -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Include" -PropertyType DWord -Value 1 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "NoContent" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Policy" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Suppress" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "URL" -PropertyType String -Value $url -Force | Out-Null - $global:counter++ - Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null - Write-Host "Included folder $counter : $path" -ForegroundColor Green -} - -function Recur-Search { - param ( - [String]$path - ) - $folders = Get-ChildItem -Path $path -Directory -Force -ErrorAction SilentlyContinue - foreach ($folder in $folders) { - if ($folder.Name.StartsWith(".")) { - $subKeyPath = Join-Path $registryBase $counter - $relativePath = $folder.FullName.Substring(3) - $url = "file:///$volumeLetter[$guid]\$relativePath\" - New-Item -Path $subKeyPath -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Container" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Default" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Include" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "NoContent" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Policy" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "Suppress" -PropertyType DWord -Value 0 -Force | Out-Null - New-ItemProperty -Path $subKeyPath -Name "URL" -PropertyType String -Value $url -Force | Out-Null - $global:counter++ - Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null - Write-Host "Excluded folder $counter : $($folder.FullName)" -ForegroundColor Green - } else { - Recur-Search -path $folder.FullName - } - } -} - -$registryBase = "HKLM:\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\WorkingSetRules" -$searchRoots = "HKLM:\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\SearchRoots" -$volumeLetter = "E:\" -$defaultGuid = "98da7f83-099d-4591-afed-be354bdaf82b" -$guid = Get-Root-Guid -$global:counter = 0 - -Service-Stop -Clean-Init -#Default-Search -path "Microsoft Outlook" -url "csc://{S-1-5-21-2626148534-851844826-3743222949-1001}/" -isDefault 1 -#Default-Search -path "Microsoft Outlook" -url "mapi16://{S-1-5-21-2626148534-851844826-3743222949-1001}/" -isDefault 0 -Default-Search -path "$volumeLetter" -url "file:///$volumeLetter[$guid]\" -isDefault 0 -Recur-Search -path "$volumeLetter" -Service-Start From a2182e44345d3f32a54ba8678625ae274615a0b7 Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Mon, 15 Sep 2025 02:05:06 +0300 Subject: [PATCH 2/8] :heavy_minus_sign: Drop PsExec requirement Use Task Scheduler to run as SYSTEM --- Windows-Search-Exceptions.ps1 | 50 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/Windows-Search-Exceptions.ps1 b/Windows-Search-Exceptions.ps1 index 7f96227..ab7d285 100644 --- a/Windows-Search-Exceptions.ps1 +++ b/Windows-Search-Exceptions.ps1 @@ -11,14 +11,11 @@ # Backup your registry before running this script. # Usage: -# 1. Start from a clean slate, no indexed locations. +# 1. Start from a clean slate, no indexed locations. Backup your registry now. # 2. Edit the provided `.searchignore` file with your wildcard patterns, one per line. -# Make sure to include eg. D:\*\.git\ to fix the bug that excludes parent repos. -# 3. Install PsExec from Sysinternals: https://learn.microsoft.com/en-us/sysinternals/downloads/psexec -# choco install psexec -# 4. In an elevated command prompt: -# psexec -i -s powershell.exe -File ".\Windows-Search-Exceptions.ps1" -# 5. This should add the rules. You may add your indexed locations now. +# Make sure to include eg. `D:\*\.git\` to fix the bug that excludes parent repos. +# 3. In an elevated Powershell prompt run the script ".\Windows-Search-Exceptions.ps1" +# 4. This should add the rules. You may add your indexed locations now. # Git repos and your other wildcard patterns won't be excluded anymore. # The script will: @@ -27,12 +24,32 @@ # - Add exclusions from the `.searchignore` file # - Restart the Windows Search service +# Register script to be run as a scheduled task with SYSTEM permissions +# Necessary for modifying the protected Registry keys for Windows Search exclusions if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -ne "NT AUTHORITY\SYSTEM") { - Write-Warning "This script must be run as SYSTEM to modify registry permissions. - Use PsExec: psexec -i -s powershell.exe -File $($MyInvocation.MyCommand.Path)" - exit 1 + $taskName = ".searchignore Script" + $taskDescription = "Sets the registry keys for Windows Search exclusions from a .searchignore file in the script folder" + + Write-Warning "Script needs SYSTEM permissions to modify protected registry keys." + Write-Warning "Registering scheduled task to run as SYSTEM..." + + # Set start time in the past so it only runs on demand + $startTime = $((Get-Date).AddHours(-4).ToString("HH:mm")) + $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`"" + $trigger = New-ScheduledTaskTrigger -Once -At $startTime + Register-ScheduledTask -TaskName $taskName -Description $taskDescription -Action $action -Trigger $trigger -User "SYSTEM" -Force | Out-Null + + Write-Host "Invoking this script as scheduled task..." + Start-ScheduledTask -TaskName $taskName + + Write-Host "Cleaning up scheduled task..." + Unregister-ScheduledTask -TaskName $taskName -Confirm:$false + + exit } +# Below will only run as SYSTEM account + function Stop-SearchService { Stop-Service WSearch -Force Write-Host "Search service stopped" @@ -84,9 +101,6 @@ function Initialize-DefaultSearch { } function Set-SearchExclusions { - param ( - [String]$Path - ) # This function reads exclusion patterns from a `.searchignore` file # and creates corresponding registry entries for each pattern. @@ -111,8 +125,8 @@ function Set-SearchExclusions { # Iterate over each pattern (which is one line from the file). foreach ($pattern in $patterns) { # Skip any empty or whitespace-only lines in the file - # Comment with # or ; or // at the begining of the line - if ($pattern -match '^\s*(#|;|//)') { + # Comment with # or ; at the begining of the line + if ($pattern -match '^\s*(#|;|$)') { continue } @@ -120,7 +134,7 @@ function Set-SearchExclusions { $subKeyPath = Join-Path $registryBase $counter # Construct the URL as requested: "file:///" followed by the pattern from the file. - $url = "file:///$volumeLetter$pattern" + $url = "file:///$pattern" # Create the new registry key for the current pattern. # Write-Host $subKeyPath $url -ForegroundColor Magenta # DEBUG @@ -139,8 +153,6 @@ function Set-SearchExclusions { $global:counter++ # Update the master ItemCount in the parent registry key. - # Write-Host $global:counter -ForegroundColor Magenta - # DEBUG Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null # Provide feedback to the console that the pattern was processed. @@ -158,5 +170,5 @@ $global:counter = 0 # Key with last number that exists in Registry, not incremen Stop-SearchService Reset-Exclusions Initialize-DefaultSearch -path "$volumeLetter" -url "file:///$volumeLetter[$guid]\" -isDefault 0 -Set-SearchExclusions -Path "$volumeLetter" +Set-SearchExclusions Start-SearchService From 6c268ad2f9a13ce344999e831b658b7e89ada37d Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Mon, 15 Sep 2025 02:10:15 +0300 Subject: [PATCH 3/8] :wrench: Update .searchignore example file Only allow comment lines with # or ; like .ini --- .searchignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.searchignore b/.searchignore index dd79b91..8e6520d 100644 --- a/.searchignore +++ b/.searchignore @@ -1,5 +1,6 @@ # Drive letters required, wildcards accepted +# Final backslash indicates a folder C:\*\.git\ D:\*\.git\ E:\*\.git\ @@ -17,6 +18,5 @@ C:\FileHistory\ D:\FileHistory\ E:\FileHistory\ -; Valid comment line -// Another comment line +; Another valid comment line # Empty lines are also ignored From bc1459e94bbdf295c63324cb1c3b19be895d9a62 Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Mon, 15 Sep 2025 02:14:49 +0300 Subject: [PATCH 4/8] :memo: Update README --- README.md | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index ba3a9cc..3a7c6bc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Windows-Search-Full-Index + A PowerShell script to prevent Windows from excluding folders to being indexed. ## Overview @@ -10,45 +11,39 @@ This can be problematic for developers who use the repository folder as their wo ## Workaround -Fortunately, there's a workaround. If a `.git` or `.svn` folder is **already present** in the list of excluded folders, then **the parent folder will no longer be automatically excluded**. -But manually adding each of these hidden folders to the exclusion list is tedious. -This script was created to automate the process: it recursively scans the selected volume and adds **every folder starting with a dot (`.`)** to the Windows Search exclusion list. - ---- +Fortunately, there's a workaround. If a `.git` or `.svn` folder is **already present** in the list of excluded folders, then **the parent folder will no longer be automatically excluded.** -## Usage Instructions +This script automates the process of adding these exclusion patterns to Windows Search. You can specify them using wildcards such as `D:\*\.git\` in a `.searchignore` file located in the same folder as the script. -The inclusion/exclusion list is stored in a **protected key** of the Windows Registry. -Therefore, running the script as Administrator is required — but not sufficient. You must also: +Note that setting exclusion patterns using Local Group Policy **will not fix the bug** in Windows Search. It has to be done like this script does it. -### 1. Grant Registry Permissions +--- -In `regedit`, navigate to: +## Usage -``` -Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\WorkingSetRules -``` +1. Start from a clean slate, no indexed locations. Backup your registry now. +2. Edit the provided `.searchignore` file with your wildcard patterns, one per line. + Make sure to include eg. `D:\*\.git\` to fix the bug that excludes parent repos. +3. Run the script as Administrator + ```powershell + # From an elevated prompt + .\Windows-Search-Exceptions.ps1 + ``` -Right-click → **Permissions** → Grant **Full Control** to the **Administrators** group. +This should add the rules. You may add your indexed locations now. +Git repos and your other wildcard patterns won't be excluded anymore. -### 2. Configure Volume +## How it works -Open `Windows-Search.ps1` in Notepad and edit the line: +Running from an elevated prompt the script has permission to register a scheduled task that will run it as the SYSTEM account. +This is necessary because the inclusion/exclusion list is stored in a **protected key** of the Windows Registry: -```powershell -$volumeLetter = "E:\" ``` - -Change the drive letter if necessary. - -### 3. Run the Script - -Open **PowerShell as Administrator** and execute: - -```powershell -.\Windows-Search.ps1 +Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Search\CrawlScopeManager\Windows\SystemIndex\WorkingSetRules ``` +The task is run on-demand as SYSTEM and sets the required data under the `WorkingSetRules` key in the registry, based on the lines in `.searchignore`. + --- ## Disclaimer @@ -61,6 +56,6 @@ Use at your own risk — the author is not responsible for any damage or data lo ## TODO -- [ ] #todo schtasks solution to run once as SYSTEM -- [ ] #todo Add warning that Group Policy setting will not fix parent folders of .git +- [ ] #todo Request elevation +- [ ] #todo ConfirmImpact High - [ ] #todo Is Rebuild index necessary? I see that it added Start Menu, Users minus AppData... From a1f4d14f3fa4bca904aed06e26aea3113e16732c Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Mon, 15 Sep 2025 02:22:27 +0300 Subject: [PATCH 5/8] :truck: Rename script --- Windows-Search-Exceptions.ps1 => Windows-Search-Exclusions.ps1 | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Windows-Search-Exceptions.ps1 => Windows-Search-Exclusions.ps1 (100%) diff --git a/Windows-Search-Exceptions.ps1 b/Windows-Search-Exclusions.ps1 similarity index 100% rename from Windows-Search-Exceptions.ps1 rename to Windows-Search-Exclusions.ps1 From 9834302ffd618565f43aa6424ce29ee108f0c6ed Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Wed, 1 Oct 2025 11:08:11 +0300 Subject: [PATCH 6/8] :technologist: Add unused Edit-Exclusions function --- Windows-Search-Exclusions.ps1 | 37 ++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/Windows-Search-Exclusions.ps1 b/Windows-Search-Exclusions.ps1 index ab7d285..729f366 100644 --- a/Windows-Search-Exclusions.ps1 +++ b/Windows-Search-Exclusions.ps1 @@ -8,17 +8,19 @@ ####################################################### # Exclusion patterns are defined in `.searchignore` file, see repo. -# Backup your registry before running this script. +# Backup your registry before running this script! + +# Usage -# Usage: # 1. Start from a clean slate, no indexed locations. Backup your registry now. # 2. Edit the provided `.searchignore` file with your wildcard patterns, one per line. # Make sure to include eg. `D:\*\.git\` to fix the bug that excludes parent repos. # 3. In an elevated Powershell prompt run the script ".\Windows-Search-Exceptions.ps1" # 4. This should add the rules. You may add your indexed locations now. -# Git repos and your other wildcard patterns won't be excluded anymore. +# Git repos won't be excluded anymore, and your other wildcard patterns will work. # The script will: + # - Stop the Windows Search service # - Reset existing exclusions # - Add exclusions from the `.searchignore` file @@ -80,6 +82,35 @@ function Reset-Exclusions { Write-Host "Exclusions reset" } +function Edit-Exclusions { # Not used + # Get all the numbered subkeys under the base registry path. + $subKeys = Get-ChildItem -Path $registryBase -ErrorAction SilentlyContinue + + # Check if there are any subkeys to process. + if (-not $subKeys) { + Write-Host "No exclusions found to clean" + return + } + + foreach ($subKey in $subKeys) { + # Try to get the 'URL' string value from the current subkey. + # -ErrorAction SilentlyContinue prevents errors if the 'URL' value doesn't exist. + $urlValue = Get-ItemProperty -Path $subKey.PSPath -Name "URL" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty "URL" + + # The condition to check before removing the item. + # We use -notlike with a wildcard (*) to check if the URL value does NOT start with "file:///D:\". + # This condition is also true if $urlValue is null (the URL property doesn't exist). + if (-not ($urlValue -like "file:///[CD]:\*")) { + Write-Host "Removing key: $($subKey)" -ForegroundColor Red + Remove-Item -Path $subKey.PSPath -Recurse -Force + } + else { + Write-Host "Skipping $($urlValue)" -ForegroundColor Gray + } + } + Write-Host "Exclusion cleanup complete" -ForegroundColor Green +} + function Initialize-DefaultSearch { param ( [String]$path, From 04dbd574c0b4b63b8f3e3b9924453ed5ef035efc Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Wed, 1 Oct 2025 11:25:15 +0300 Subject: [PATCH 7/8] :passport_control: Request elevation Needs admin permission to set scheduled task --- Windows-Search-Exclusions.ps1 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Windows-Search-Exclusions.ps1 b/Windows-Search-Exclusions.ps1 index 729f366..984a54d 100644 --- a/Windows-Search-Exclusions.ps1 +++ b/Windows-Search-Exclusions.ps1 @@ -29,6 +29,16 @@ # Register script to be run as a scheduled task with SYSTEM permissions # Necessary for modifying the protected Registry keys for Windows Search exclusions if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -ne "NT AUTHORITY\SYSTEM") { + # Self-elevate the script if required + # Solution from https://stackoverflow.com/a/64576446 + if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { + if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { + $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments + Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine + Exit + } + } + $taskName = ".searchignore Script" $taskDescription = "Sets the registry keys for Windows Search exclusions from a .searchignore file in the script folder" @@ -163,14 +173,14 @@ function Set-SearchExclusions { # The subKeyPath is created by joining the base registry path and the current counter. $subKeyPath = Join-Path $registryBase $counter - + # Construct the URL as requested: "file:///" followed by the pattern from the file. $url = "file:///$pattern" # Create the new registry key for the current pattern. # Write-Host $subKeyPath $url -ForegroundColor Magenta # DEBUG New-Item -Path $subKeyPath -Force | Out-Null - + # Set all the required registry properties for this key. New-ItemProperty -Path $subKeyPath -Name "Container" -PropertyType DWord -Value 0 -Force | Out-Null New-ItemProperty -Path $subKeyPath -Name "Default" -PropertyType DWord -Value 0 -Force | Out-Null @@ -179,13 +189,13 @@ function Set-SearchExclusions { New-ItemProperty -Path $subKeyPath -Name "Policy" -PropertyType DWord -Value 0 -Force | Out-Null New-ItemProperty -Path $subKeyPath -Name "Suppress" -PropertyType DWord -Value 0 -Force | Out-Null New-ItemProperty -Path $subKeyPath -Name "URL" -PropertyType String -Value $url -Force | Out-Null - + # Increment the global counter for the next item. $global:counter++ - + # Update the master ItemCount in the parent registry key. Set-ItemProperty -Path $registryBase -Name "ItemCount" -Value $global:counter -Force | Out-Null - + # Provide feedback to the console that the pattern was processed. Write-Host "Added pattern $counter : $pattern" -ForegroundColor Green } From de578a47d83c960fa332f2a7ea0d36cf38bc8efb Mon Sep 17 00:00:00 2001 From: akaleeroy Date: Wed, 1 Oct 2025 22:24:26 +0300 Subject: [PATCH 8/8] :memo: Clean up README --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 3a7c6bc..12e1cfb 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,3 @@ This script helps ensure your development files remain visible and searchable in This script modifies sensitive keys of the Windows Registry and should be used with caution. Ensure you have a backup or system restore point before proceeding. Use at your own risk — the author is not responsible for any damage or data loss resulting from its use. - -## TODO - -- [ ] #todo Request elevation -- [ ] #todo ConfirmImpact High -- [ ] #todo Is Rebuild index necessary? I see that it added Start Menu, Users minus AppData...