Created
October 31, 2025 19:49
-
-
Save Tomamais/863253bf6b5ca9ec0500e6db54bfeea2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Reads a tab-separated .NET Core log file, displays it in a custom Windows Forms DataGridView, | |
| and provides a refresh button. Rows are color-coded based on the LogLevel. | |
| .NOTES | |
| This script requires a Windows OS environment to load the System.Windows.Forms and System.Drawing assemblies. | |
| #> | |
| param( | |
| [Parameter(Mandatory=$true)] | |
| [string]$LogFilePath | |
| ) | |
| # --- 1. Load Assemblies --- | |
| Add-Type -AssemblyName System.Windows.Forms | |
| Add-Type -AssemblyName System.Drawing | |
| Add-Type -AssemblyName System.Data # Needed for DataTable used for DataGridView source | |
| # --- 2. Helper Function: Read and Structure the Tab-Separated Log --- | |
| function Get-TabDelimitedLogs { | |
| param( | |
| [string]$Path | |
| ) | |
| try { | |
| # Define the exact headers to match the log format | |
| $Headers = "Timestamp", "HostName", "AppName", "LogLevel", "UserName", "Category", "Message" | |
| # Read the content and convert it into structured objects | |
| $LogObjects = Get-Content -Path $Path | | |
| ConvertFrom-Csv -Delimiter "`t" -Header $Headers | |
| # Process the objects: Convert Timestamp to proper DateTime for sorting | |
| $ProcessedLogs = $LogObjects | Select-Object ` | |
| @{Name='DateTime'; Expression={[datetime]::ParseExact($_.Timestamp, "yyyy-MM-dd h:mm:ss tt", [System.Globalization.CultureInfo]::InvariantCulture)}}, ` | |
| "HostName", "AppName", "LogLevel", "UserName", "Category", "Message" | |
| # Sort the objects by the new DateTime column (most recent first) | |
| return $ProcessedLogs | Sort-Object -Property DateTime -Descending | |
| } catch { | |
| Write-Error "Error parsing log file: $($_.Exception.Message)" | |
| Write-Host "Please ensure the log format and path are correct." -ForegroundColor Red | |
| return @() | |
| } | |
| } | |
| # --- 3. Core Function: Refresh Data and Apply Coloring/Sorting --- | |
| function Refresh-DataGridView { | |
| param( | |
| [Parameter(Mandatory=$true)] | |
| [System.Windows.Forms.DataGridView]$DataGridView, | |
| [Parameter(Mandatory=$true)] | |
| [string]$Path | |
| ) | |
| Write-Host "Refreshing data from $Path..." -ForegroundColor Yellow | |
| # Load the structured log objects | |
| $Logs = Get-TabDelimitedLogs -Path $Path | |
| if (-not $Logs) { | |
| $DataGridView.DataSource = $null | |
| return | |
| } | |
| # Convert PowerShell objects to a DataTable for better performance and DataGridView binding | |
| # This step is critical for enabling native filtering and sorting within the DataGridView control. | |
| $DataTable = New-Object System.Data.DataTable | |
| # Define columns based on the processed object properties | |
| $Logs[0].psobject.Properties | ForEach-Object { | |
| $DataTable.Columns.Add($_.Name, [System.Type]::GetType("System.String")) | |
| } | |
| # Fix the DateTime column to be a DateTime type for native sorting | |
| $DataTable.Columns["DateTime"].DataType = [System.DateTime] | |
| # Populate the DataTable | |
| foreach ($Log in $Logs) { | |
| $row = $DataTable.NewRow() | |
| $Log.psobject.Properties | ForEach-Object { | |
| $row.$($_.Name) = $_.Value | |
| } | |
| $DataTable.Rows.Add($row) | |
| } | |
| # Bind the DataTable to the DataGridView | |
| $DataGridView.DataSource = $DataTable | |
| # Configure the DataGridView for user interaction | |
| $DataGridView.AllowUserToOrderColumns = $true | |
| $DataGridView.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::FullRowSelect | |
| $DataGridView.ReadOnly = $true | |
| $DataGridView.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill | |
| $DataGridView.Columns["DateTime"].DefaultCellStyle.Format = "yyyy-MM-dd HH:mm:ss.fff" | |
| Write-Host "Refresh complete. $($Logs.Count) entries loaded." -ForegroundColor Green | |
| } | |
| # --- 4. Event Handler for Conditional Coloring --- | |
| # This function is executed for every cell being drawn in the DataGridView | |
| function LogLevel_CellFormatting { | |
| param( | |
| [Parameter(Mandatory=$true)]$sender, | |
| [Parameter(Mandatory=$true)]$e | |
| ) | |
| # Check if we are formatting the LogLevel column | |
| if ($sender.Columns[$e.ColumnIndex].Name -eq "LogLevel") { | |
| # Get the value of the LogLevel cell | |
| $LogLevel = $e.Value.ToString().ToUpper() | |
| # Apply coloring based on the log level | |
| switch ($LogLevel) { | |
| "ERROR" { | |
| $e.CellStyle.BackColor = [System.Drawing.Color]::FromArgb(255, 200, 200) # Light Red | |
| $e.CellStyle.ForeColor = [System.Drawing.Color]::Black | |
| } | |
| "CRITICAL" { | |
| $e.CellStyle.BackColor = [System.Drawing.Color]::Red | |
| $e.CellStyle.ForeColor = [System.Drawing.Color]::White | |
| } | |
| "WARNING" { | |
| $e.CellStyle.BackColor = [System.Drawing.Color]::LightYellow | |
| $e.CellStyle.ForeColor = [System.Drawing.Color]::DarkGoldenrod | |
| } | |
| "DEBUG" { | |
| $e.CellStyle.BackColor = [System.Drawing.Color]::LightGray | |
| $e.CellStyle.ForeColor = [System.Drawing.Color]::Black | |
| } | |
| "INFORMATION" { | |
| # Keep default or set a light background | |
| $e.CellStyle.BackColor = [System.Drawing.Color]::White | |
| } | |
| } | |
| } | |
| } | |
| # --- 5. Build and Show the Windows Form GUI --- | |
| # Create the main form | |
| $form = New-Object System.Windows.Forms.Form | |
| $form.Text = "Custom .NET Core Log Viewer - $LogFilePath" | |
| $form.Size = New-Object System.Drawing.Size(1200, 800) | |
| $form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen | |
| $form.WindowState = [System.Windows.Forms.FormWindowState]::Maximized | |
| # Create the DataGridView | |
| $dgv = New-Object System.Windows.Forms.DataGridView | |
| $dgv.Location = New-Object System.Drawing.Point(10, 50) | |
| $dgv.Size = New-Object System.Drawing.Size(1160, 680) # Initial size, will be anchored | |
| $dgv.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right -bor [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left | |
| # Hook up the cell formatting event handler | |
| $dgv.Add_CellFormatting({ LogLevel_CellFormatting -sender $dgv -e $_ }) | |
| # Create the Refresh Button | |
| $btnRefresh = New-Object System.Windows.Forms.Button | |
| $btnRefresh.Text = "Refresh Logs" | |
| $btnRefresh.Location = New-Object System.Drawing.Point(10, 10) | |
| $btnRefresh.Size = New-Object System.Drawing.Size(150, 30) | |
| $btnRefresh.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left | |
| # Set the button click action to call the Refresh function | |
| $btnRefresh.Add_Click({ Refresh-DataGridView -DataGridView $dgv -Path $LogFilePath }) | |
| # Add controls to the form | |
| $form.Controls.Add($dgv) | |
| $form.Controls.Add($btnRefresh) | |
| # Load data on initial startup | |
| Refresh-DataGridView -DataGridView $dgv -Path $LogFilePath | |
| # Show the form and start the PowerShell application message pump | |
| $form.ShowDialog() | Out-Null | |
| ``` | |
| ### 💡 How to Use This Advanced Script | |
| 1. **Save the Script:** Save the code block above as `CustomLogViewer.ps1`. | |
| 2. **Ensure Log Format is Correct:** Your log file **must** be tab-separated and follow this header order: | |
| ``` | |
| 2025-10-31 3:00:00 PM<TAB>HostName<TAB>AppName<TAB>LogLevel<TAB>UserName<TAB>Category<TAB>Message | |
| ``` | |
| *If your log file does not have this header line, the script assumes the first line is data.* | |
| 3. **Run the Script:** Open a PowerShell console and run it, specifying the path: | |
| ```powershell | |
| .\CustomLogViewer.ps1 -LogFilePath "C:\path\to\your\log.txt" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment