feat: Add search history extraction (Get-SearchHistory.ps1)
Extract Windows Search queries, typed paths, and Run dialog history from registry (WordWheelQuery, TypedPaths, RunMRU). Includes warnings about Windows 11 limitations - modern search without Microsoft account doesn't persist history due to cloud-first design. Update TODO.md.
This commit is contained in:
10
TODO.md
10
TODO.md
@@ -25,7 +25,7 @@
|
||||
### Browser & Search History
|
||||
- [ ] Browser history - Edge, Chrome, Firefox artifacts
|
||||
- [x] Typed URLs - URLs manually typed in browsers
|
||||
- [ ] Search terms - Windows Search history
|
||||
- [x] Search terms - Windows Search history (Get-SearchHistory.ps1)
|
||||
|
||||
### File Access
|
||||
- [ ] LNK files - Shortcut files showing file access
|
||||
@@ -33,11 +33,11 @@
|
||||
- [ ] Shell Bags - Folder access history
|
||||
|
||||
### System Information
|
||||
- [ ] Computer name - System identification
|
||||
- [ ] Timezone - System timezone settings
|
||||
- [ ] Last shutdown time
|
||||
- [x] Computer name - System identification (Get-Info.ps1, winfetch.ps1)
|
||||
- [x] Timezone - System timezone settings (Get-Info.ps1)
|
||||
- [x] Last shutdown time (Get-Info.ps1 - shows Last Boot)
|
||||
- [ ] Installed programs - Software inventory
|
||||
- [ ] System uptime history
|
||||
- [x] System uptime history (Get-Info.ps1, winfetch.ps1)
|
||||
|
||||
### Persistence Mechanisms
|
||||
- [ ] Run/RunOnce keys - Programs that auto-start
|
||||
|
||||
195
windows/Get-SearchHistory.ps1
Normal file
195
windows/Get-SearchHistory.ps1
Normal file
@@ -0,0 +1,195 @@
|
||||
# Get-SearchHistory.ps1
|
||||
# Extracts Windows Search history from WordWheelQuery registry
|
||||
|
||||
param(
|
||||
[int]$MaxResults = 50,
|
||||
[switch]$ShowAll
|
||||
)
|
||||
|
||||
Write-Host "=== Windows Search History ===" -ForegroundColor Cyan
|
||||
Write-Host "Search queries from Windows Search Bar and File Explorer`n"
|
||||
|
||||
Write-Host "Note: Windows 11 without Microsoft account may not persist search history" -ForegroundColor Yellow
|
||||
Write-Host "Modern search uses cloud sync and memory-only caching`n" -ForegroundColor Yellow
|
||||
|
||||
if ($ShowAll) {
|
||||
$MaxResults = [int]::MaxValue
|
||||
}
|
||||
|
||||
$foundAny = $false
|
||||
|
||||
# WordWheelQuery - Windows Search history
|
||||
Write-Host "--- WordWheelQuery (Search Bar / File Explorer) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
$wordWheelPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\WordWheelQuery"
|
||||
|
||||
if (Test-Path $wordWheelPath) {
|
||||
$props = Get-ItemProperty -Path $wordWheelPath -ErrorAction SilentlyContinue
|
||||
|
||||
# Get MRUListEx to determine order
|
||||
if ($props.MRUListEx) {
|
||||
$searches = @()
|
||||
|
||||
# Parse MRUListEx (4-byte integers)
|
||||
for ($i = 0; $i -lt $props.MRUListEx.Length - 4; $i += 4) {
|
||||
$index = [BitConverter]::ToInt32($props.MRUListEx, $i)
|
||||
if ($index -eq -1) { break } # End marker
|
||||
|
||||
# Get the search term from the indexed property
|
||||
$propName = "$index"
|
||||
if ($props.$propName) {
|
||||
# Convert binary data to Unicode string
|
||||
$searchTerm = [System.Text.Encoding]::Unicode.GetString($props.$propName)
|
||||
# Remove null terminators
|
||||
$searchTerm = $searchTerm -replace '\x00', ''
|
||||
|
||||
if ($searchTerm) {
|
||||
$searches += $searchTerm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($searches.Count -gt 0) {
|
||||
$foundAny = $true
|
||||
Write-Host "Registry: $wordWheelPath`n" -ForegroundColor Gray
|
||||
|
||||
$count = 0
|
||||
foreach ($search in ($searches | Select-Object -First $MaxResults)) {
|
||||
$count++
|
||||
Write-Host " $count. $search" -ForegroundColor Green
|
||||
}
|
||||
|
||||
if ($searches.Count -gt $MaxResults) {
|
||||
Write-Host "`n ... and $($searches.Count - $MaxResults) more" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Write-Host "`nTotal searches: $($searches.Count)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " No search history found" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host " No MRUListEx found" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host " Registry key not found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Error: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# TypedPaths - File Explorer address bar typed paths
|
||||
Write-Host "`n--- TypedPaths (File Explorer Address Bar) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
$typedPathsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\TypedPaths"
|
||||
|
||||
if (Test-Path $typedPathsPath) {
|
||||
$paths = Get-ItemProperty -Path $typedPathsPath -ErrorAction SilentlyContinue
|
||||
$pathList = @()
|
||||
|
||||
# TypedPaths stores as url1, url2, etc.
|
||||
for ($i = 1; $i -le 50; $i++) {
|
||||
$urlKey = "url$i"
|
||||
if ($paths.$urlKey) {
|
||||
$pathList += $paths.$urlKey
|
||||
}
|
||||
}
|
||||
|
||||
if ($pathList.Count -gt 0) {
|
||||
$foundAny = $true
|
||||
Write-Host "Registry: $typedPathsPath`n" -ForegroundColor Gray
|
||||
|
||||
$count = 0
|
||||
foreach ($path in ($pathList | Select-Object -First $MaxResults)) {
|
||||
$count++
|
||||
Write-Host " $count. $path" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "`nTotal typed paths: $($pathList.Count)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " No typed paths found" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host " Registry key not found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Error: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# RunMRU - Run dialog history
|
||||
Write-Host "`n--- RunMRU (Run Dialog History) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
$runMRUPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU"
|
||||
|
||||
if (Test-Path $runMRUPath) {
|
||||
$runProps = Get-ItemProperty -Path $runMRUPath -ErrorAction SilentlyContinue
|
||||
$runList = @()
|
||||
|
||||
# RunMRU uses letter keys (a, b, c, etc.) and MRUList for order
|
||||
if ($runProps.MRUList) {
|
||||
$mruOrder = $runProps.MRUList.ToCharArray()
|
||||
|
||||
foreach ($char in $mruOrder) {
|
||||
$key = [string]$char
|
||||
if ($runProps.$key) {
|
||||
# Remove \1 terminator if present
|
||||
$command = $runProps.$key -replace '\\1$', ''
|
||||
if ($command) {
|
||||
$runList += $command
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($runList.Count -gt 0) {
|
||||
$foundAny = $true
|
||||
Write-Host "Registry: $runMRUPath`n" -ForegroundColor Gray
|
||||
|
||||
$count = 0
|
||||
foreach ($cmd in ($runList | Select-Object -First $MaxResults)) {
|
||||
$count++
|
||||
Write-Host " $count. $cmd" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "`nTotal run commands: $($runList.Count)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " No run history found" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host " Registry key not found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Error: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# Recent searches in specific apps (if available)
|
||||
Write-Host "`n--- Cortana/Search App (if available) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
# Check for modern search database
|
||||
$searchPackage = Get-ChildItem "$env:LOCALAPPDATA\Packages" -Filter "Microsoft.Windows.Search_*" -Directory -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
|
||||
if ($searchPackage) {
|
||||
$searchCache = Join-Path $searchPackage.FullName "LocalState\DeviceSearchCache"
|
||||
|
||||
if (Test-Path $searchCache) {
|
||||
Write-Host " Search cache found: $searchCache" -ForegroundColor Cyan
|
||||
Write-Host " (Binary database - requires specialized tools to parse)" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " Search cache not found" -ForegroundColor Gray
|
||||
}
|
||||
} else {
|
||||
Write-Host " Modern search app not found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Error: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
if (-not $foundAny) {
|
||||
Write-Host "`nNo search history found" -ForegroundColor Gray
|
||||
Write-Host "This is common on Windows 11 without a Microsoft account" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host "`nNote: Search history shows user queries and typed paths" -ForegroundColor Cyan
|
||||
Write-Host "This can reveal file names, apps, and topics of interest" -ForegroundColor Cyan
|
||||
Write-Host "`nWindows 11 Limitation: Modern search without Microsoft account" -ForegroundColor Yellow
|
||||
Write-Host "does not persist history to registry (cloud-first design)" -ForegroundColor Yellow
|
||||
Write-Host "This works best on Windows 10 or systems with Microsoft accounts" -ForegroundColor Yellow
|
||||
Reference in New Issue
Block a user