A Windows desktop application for searching keywords across log files, text files, and Windows Event Logs. Built with WPF (.NET Framework 4.7.2) and licensed under the MIT License.
Log Search lets you drop a folder (or a .zip archive) onto the window, type a keyword, and find every matching line across all supported files in that directory β recursively through all subfolders.
π Supported file types: .log, .txt, .reg, .html, .json, .xml
βοΈ Additional capability: Automatically discovers and converts Windows Event Log files (.evtx) into searchable .xml using the Windows wevtutil command, so event log contents become searchable too.
| Feature | Description |
|---|---|
| π±οΈ Drag-and-drop input | Drop a folder or a .zip file onto the target area |
| π¦ Automatic ZIP extraction | Dropped .zip files are extracted to a sibling folder and searched |
| π Case-insensitive keyword search | Matches substrings across every line of every supported file |
| π Result grid | Displays the matched sentence, full file path, and line number for each hit |
| π±οΈ Double-click to open | Double-click any result to open the source file in Notepad |
| π Ctrl+C to copy | Copies the matched sentence text to the clipboard |
| β Enter key to search | Press Enter in the search box to trigger a search immediately |
| π§Ή Clear button | Clears the folder list, search text, and results in one click |
| π Progress indication | Shows a progress bar during EVTX conversion and file search |
| π§ EVTX-to-XML conversion | Converts .evtx files to .xml so their event data can be searched like any other text file |
| βΉοΈ About dialog | Shows build number, supported file types, and a liability disclaimer |
| β Help dialog | Provides guidance on ZIP extraction troubleshooting |
| π Dark theme UI | Clean dark interface (#121C27 background) designed for extended use |
This application was designed with a read-only, leave-no-trace philosophy:
- π« No data is saved. The application searches files in place and displays results in memory. It does not create databases, export files, or write search results anywhere on disk. Once you close the application, the results are gone.
- π No network activity. The application makes no network calls. It does not phone home, contact any server, or transmit any data externally.
- π No user data collection. No telemetry, no analytics, no usage tracking.
- πΎ No configuration files are written. User preferences, search history, and file paths are not persisted between sessions. Every launch starts fresh.
- π Files are never modified. The search engine reads files but never writes to them. Your source files remain untouched.
- π The only file the application creates is its own log file (see below), which contains diagnostic information about the application itself β not the contents of your files.
The application includes a self-contained diagnostic logger that activates automatically on startup.
%APPDATA%\SearchFilesTool\Application.log
- π Application startup β version, OS, architecture (32/64-bit), available memory
- π Search operations β when searches begin and complete
β οΈ Errors and exceptions β full exception type, message, stack trace, and inner exceptions
- On startup,
App.OnStartup()callsLogger.Initialize()before anything else runs - The logger creates the
%APPDATA%\SearchFilesTool\directory if it does not exist - It opens (or creates)
Application.logand writes a startup header with environment details - From that point on, all
Logger.Info(),Logger.Warn(), andLogger.Error()calls append timestamped entries to this file
The application registers three global exception handlers in App.xaml.cs so that even unexpected crashes produce a log entry:
| Handler | Catches | Behavior |
|---|---|---|
AppDomain.CurrentDomain.UnhandledException |
Crashes on non-UI threads | Logs the full exception. If the application is terminating, logs that fact as well. |
TaskScheduler.UnobservedTaskException |
Unobserved exceptions from async tasks | Logs the exception and marks it as observed to prevent the process from crashing. |
DispatcherUnhandledException |
Unhandled exceptions on the WPF UI thread | Logs the exception, shows a dialog to the user with the error message and the log file path, then marks it as handled so the application continues running. |
On every startup, the application deletes log files older than 7 days via Logger.CleanupOldLogs(7). This prevents the log from growing indefinitely.
All log writes are protected by a lock statement, so concurrent operations (search tasks, UI thread, exception handlers) can safely write to the same file without corruption.
App.xaml.cs Logger.cs evtxToXml.cs MainWindow.xaml / .cs
(Startup + crash (Diagnostics (EVTX conversion) (UI + search engine)
guards) logging)
| | | |
+-- OnStartup ------>+ | |
initializes | | |
logger, | | |
registers | | |
exception | | |
handlers | | |
| | +-- LogResult (data model)
| | | .Sentence
| | | .Path
| | | .LineNumber
| | |
| | +-- FolderListBox_Drop()
| | | (drag-and-drop handler,
| | | zip extraction)
| | |
| +<----- Search_Click() -----+
| | (EVTX conversion |
| | then file search) |
| | |
+<---------- Logger calls throughout -------------+
Technology: WPF (Windows Presentation Foundation) on .NET Framework 4.7.2, single-window architecture with code-behind (no MVVM framework).
SearchFilesTools-master/
βββ App.xaml # Application XAML definition
βββ App.xaml.cs # Startup logic & global exception handlers
βββ Logger.cs # Thread-safe diagnostic logger
βββ evtxToXml.cs # EVTX-to-XML conversion via wevtutil
βββ MainWindow.xaml # UI layout (dark theme)
βββ MainWindow.xaml.cs # UI logic & keyword search engine
βββ icon.png # Application icon (PNG)
βββ iconLogo.ico # Application icon (ICO)
βββ App.config # .NET Framework 4.7.2 runtime config
βββ packages.config # NuGet dependencies
βββ SearchFilesTool.csproj # MSBuild project file
βββ SearchFilesTool.sln # Visual Studio solution file
βββ Properties/
β βββ AssemblyInfo.cs # Assembly metadata (version, copyright)
β βββ Resources.resx # Resource definitions
β βββ Settings.settings # User settings
βββ .gitignore # Git ignore rules
βββ .gitattributes # Git line-ending normalization
βββ LICENSE.txt # MIT License
βββ README.md # This file
βββ BUGFIX_SUMMARY.md # Bug fix documentation
Here is what happens from the moment you drop a folder to the moment results appear:
You drag a folder or .zip file onto the drop zone (FolderListBox).
- If a folder: its path is stored in the ListBox.
- If a
.zip: the application extracts it to a sibling directory usingSystem.IO.Compression.ZipFile.ExtractToDirectory(). If that directory already exists, extraction is skipped. The resulting folder path is stored.
When you click Search (or press Enter), the application first scans the directory recursively for .evtx files.
For each .evtx file found (that does not already have a corresponding .xml file):
- Run
wevtutilβ The Windows command-line toolwevtutil query-eventsis invoked to dump the event log as XML. Output is streamed to a temporary file (64KB buffer) to avoid loading everything into memory at once. - Clean control characters β The raw XML output is read line-by-line and stripped of 13 control characters (
0x00through0x0F, excluding TAB0x09, LF0x0A, and CR0x0D) that would cause XML parsing failures. - Reformat with XmlReader/XmlWriter β The cleaned XML is parsed with
XmlReader(streaming, not DOM) and rewritten withXmlWriteras properly indented UTF-8 XML. This validates the structure and produces a clean file. - Save β The final
.xmlfile is saved next to the original.evtxwith the same name. - Cleanup β Temporary files are deleted. Garbage collection is forced between files to free memory.
- Large file guard β Files over 500MB are skipped.
After EVTX conversion completes (or is skipped), the main search runs asynchronously on a background thread via Task.Run():
- Enumerate files β
Directory.GetFiles()recursively lists every file in the directory. - Filter by extension β Only files ending in
.log,.txt,.reg,.html,.json, or.xmlare processed. - Read and scan β For each matching file:
- All lines are read into memory with
File.ReadAllLines(). - Each line is lowercased and checked with
string.Contains()against the lowercased keyword. - On a match, a
LogResultobject is created with the original sentence, the file path, and the 1-based line number.
- All lines are read into memory with
- Error tolerance β Per-file errors (out of memory, access denied, unreadable files) are caught and the file is skipped. The search continues with the remaining files.
- If no matches are found, a single placeholder result is shown: "Nothing was found under that keyword".
- Otherwise, all
LogResultobjects are bound to the ListView grid showing Sentence, File Path, and Line Number columns. - The result count is updated:
"Results Found: N". - Double-clicking a result launches Notepad pointing to that file. Ctrl+C copies the matched sentence to the clipboard.
| Requirement | Details |
|---|---|
| π₯οΈ OS | Windows (uses wevtutil for EVTX conversion, launches notepad.exe for file viewing) |
| βοΈ Runtime | .NET Framework 4.7.2 |
| π§ EVTX conversion | Requires wevtutil (included with Windows) |
MIT License. Copyright (c) 2023 IvanRosa. See LICENSE.txt for details.