<# Mini Snaffler - search for potentially sensitive files in low-priv. Scan local paths or UNC shares. Console: show line number, pattern, and preview starting at the pattern. CSV: store full matched lines. ASCII only (no accents, no unicode). With console colors. #> param ( [string[]]$Roots = @( "$env:USERPROFILE", "C:\Users\Public" "\\10.0.0.115\" ), [string]$OutputPath = ".\InterestingFiles.csv" ) # Extensions to scan $Extensions = @( ".txt",".log",".ini",".cfg",".config",".xml", ".csv",".xls",".xlsx",".doc",".docx", ".ps1",".bat",".cmd",".vbs", ".kdbx",".rdp" ) # Patterns in FILE NAME (more complete, but not too noisy) $NamePatterns = @( # generic credentials "password","passwd","pass","pwd","mdp", "credential","credentials","cred","creds", "auth","login","logon","signin", # secrets and keys "secret","secrets","key","keys", "apikey","api-key", "token","accesstoken","access-token","sessionid","jwt", # config and env "config","configuration","settings","env",".env", "appsettings","connectionstring","connstr", # db connections "db","database","dbpass","dbuser","connection","conn", # ssh / certificates / vpn "ssh","id_rsa","id_dsa","id_ecdsa", ".pem",".ppk",".pfx",".p12",".cer",".crt", "keystore","truststore","jks", "vpn","openvpn",".ovpn","wireguard","wg.conf", # remote access "rdp",".rdp","remote","vnc","teamviewer","anydesk", # password managers / vaults "keepass","kdbx","vault","secretstore", # cloud stuff "aws","azure","gcp","s3","bucket","accesskey","secretkey" ) # Patterns in FILE CONTENT $ContentPatterns = @( "password","mot de passe","passwd", "pwd","login", "username","user id", "api key","apikey","token", "secret","client_secret", "vpn","psk","shared key" ) # Max file size (in MB) $MaxFileSizeMB = 20 $results = @() Write-Host "[INFO] Scan start" -ForegroundColor Cyan Write-Host (" Roots : " + ($Roots -join ', ')) -ForegroundColor Cyan Write-Host (" Output : " + $OutputPath) -ForegroundColor Cyan foreach ($root in $Roots) { if (-not (Test-Path $root)) { Write-Host "[WARN] Root path not found: $root" -ForegroundColor Red continue } Write-Host "`n[SCAN] Scanning $root ..." -ForegroundColor Yellow try { Get-ChildItem -Path $root -Recurse -File -ErrorAction SilentlyContinue | Where-Object { $Extensions -contains $_.Extension.ToLower() } | ForEach-Object { $file = $_ $sizeMB = [math]::Round($file.Length / 1MB, 2) if ($sizeMB -gt $MaxFileSizeMB) { return } $matchName = $false $matchContent = $false $matchDetails = @() # ------------- Name match (OPTION B: filename only) ------------- $filename = $file.Name foreach ($pat in $NamePatterns) { if ($filename -like ("*" + $pat + "*")) { $matchName = $true $matchDetails += "Name match: " + $pat } } # ------------- Content match ------------- try { $contentMatches = Select-String -Path $file.FullName -Pattern $ContentPatterns -SimpleMatch -ErrorAction SilentlyContinue if ($contentMatches) { $matchContent = $true $contentMatches | Select-Object -First 3 | ForEach-Object { $foundPattern = $_.Pattern $lineNum = $_.LineNumber $fullLine = $_.Line.Trim() # locate pattern in text (case-insensitive) $lowerLine = $fullLine.ToLower() $lowerPat = $foundPattern.ToLower() $idx = $lowerLine.IndexOf($lowerPat) # preview starting at the pattern $snippet = $fullLine if ($idx -ge 0) { $snippet = $fullLine.Substring($idx) } # 40-char preview if ($snippet.Length -gt 40) { $preview = $snippet.Substring(0,40) + "..." } else { $preview = $snippet } # Console: line number, pattern, preview Write-Host (" Line " + $lineNum + " - " + $foundPattern + " - " + $preview) -ForegroundColor DarkYellow # CSV: store full line $matchDetails += ("Content match [" + $foundPattern + "] Line " + $lineNum + " : " + $fullLine) } } } catch { # ignore read errors } # If no match => skip file if (-not ($matchName -or $matchContent)) { return } # name-only info if ($matchName -and -not $matchContent) { $matchDetails += "Name-only match. No content match." } # ----- Store result ----- $results += [PSCustomObject]@{ Path = $file.FullName Name = $file.Name SizeMB = $sizeMB LastWriteTime = $file.LastWriteTime MatchName = $matchName MatchContent = $matchContent Details = ($matchDetails -join " | ") } # ----- Final console output per file ----- if ($matchContent) { Write-Host "[FOUND] $($file.FullName) (content match)" -ForegroundColor Green } elseif ($matchName) { Write-Host "[FOUND] $($file.FullName) (filename match)" -ForegroundColor DarkGreen } } } catch { Write-Host "[WARN] Error while scanning $root : $_" -ForegroundColor Red } } # ----------- Export CSV ----------- if ($results.Count -gt 0) { $results | Sort-Object SizeMB -Descending | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $OutputPath Write-Host "`n[OK] Scan done. Results saved to $OutputPath" -ForegroundColor Green } else { Write-Host "`n[OK] Scan done. No interesting file found." -ForegroundColor Green }