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 & Search History
|
||||||
- [ ] Browser history - Edge, Chrome, Firefox artifacts
|
- [ ] Browser history - Edge, Chrome, Firefox artifacts
|
||||||
- [x] Typed URLs - URLs manually typed in browsers
|
- [x] Typed URLs - URLs manually typed in browsers
|
||||||
- [ ] Search terms - Windows Search history
|
- [x] Search terms - Windows Search history (Get-SearchHistory.ps1)
|
||||||
|
|
||||||
### File Access
|
### File Access
|
||||||
- [ ] LNK files - Shortcut files showing file access
|
- [ ] LNK files - Shortcut files showing file access
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
- [ ] Shell Bags - Folder access history
|
- [ ] Shell Bags - Folder access history
|
||||||
|
|
||||||
### System Information
|
### System Information
|
||||||
- [ ] Computer name - System identification
|
- [x] Computer name - System identification (Get-Info.ps1, winfetch.ps1)
|
||||||
- [ ] Timezone - System timezone settings
|
- [x] Timezone - System timezone settings (Get-Info.ps1)
|
||||||
- [ ] Last shutdown time
|
- [x] Last shutdown time (Get-Info.ps1 - shows Last Boot)
|
||||||
- [ ] Installed programs - Software inventory
|
- [ ] Installed programs - Software inventory
|
||||||
- [ ] System uptime history
|
- [x] System uptime history (Get-Info.ps1, winfetch.ps1)
|
||||||
|
|
||||||
### Persistence Mechanisms
|
### Persistence Mechanisms
|
||||||
- [ ] Run/RunOnce keys - Programs that auto-start
|
- [ ] 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