ControlUp Disk Monitor Log Analyzer 24 Hours

This script will analyze the log file of today created by ControlUp Disk Monitor and created a CSV output
Version 2.3.23
Created on 2025-03-30
Modified on 2025-03-30
Created by Chris Twiest
Downloads: 8

The Script Copy Script Copied to clipboard
#Requires -Version 5.1

<#
.SYNOPSIS
    Extracts and processes Disk I/O activity from a log file and exports the top entries to CSV.
.DESCRIPTION
    - Reads the DiskIoActivityTracker log file.
    - Filters lines that start with "Timestamp".
    - Extracts relevant information using regex.
    - Sorts by TransferSizeMB in descending order and selects the top results.
    - Exports the results to a user-specified CSV file.
.PARAMETER CsvFilePath
    Full path to the output CSV file where results will be stored.
.PARAMETER Top
    Maximum number of files shown in the table and CSV.
.EXAMPLE
    .\DiskIoParser.ps1  -CsvFilePath "C:\Output\Top50Results.csv"
.AUTHOR
    Chris Twiest and Guy Leech
.NOTES
    Modification History

    2025/03/05    Chris Twiest  Initial release
    2025/03/14    Guy Leech     Optimised. Added -raw and -daysback
#>

[CmdletBinding(DefaultParameterSetName='csv')]

param (
    [Parameter(Mandatory = $true, ParameterSetName = 'csv' , HelpMessage = "Show amount of files")]
    [int]$Top,

    [Parameter(Mandatory = $true, ParameterSetName = 'csv' , HelpMessage = "Enter the full path to the CSV output file")]
    [string]$CsvFilePath ,

    [Parameter(Mandatory = $false, ParameterSetName = 'raw')]
    [switch]$raw
)

try
{
    [int]$outputWidth = 400
    if( ( $PSWindow = (Get-Host).UI.RawUI ) -and ( $WideDimensions = $PSWindow.BufferSize ) )
    {
        $WideDimensions.Width = $outputWidth
        $PSWindow.BufferSize = $WideDimensions
    }
}
catch
{
    ## nothing much we can do but not fatal, just output possibly wrapping prematurely
}

$LogDirectory = Join-Path -Path ([Environment]::GetFolderPath( [Environment+SpecialFolder]::CommonApplicationData )) -ChildPath 'ControlUp\DiskMonitor'
$LogFilePattern = "ActivitiesSummary*"
$TodayStart = (Get-Date).Date  # Midnight today
$TodayEnd = $TodayStart.AddDays(1).AddSeconds(-1)  # Last second of today
$daysBack = 7 #If there are logs found older then 7 days it will clean them up
$CutoffDate = (Get-Date).AddDays( -$daysBack) 

# Get all matching log files
$LogFiles = Get-ChildItem -Path $LogDirectory -Filter $LogFilePattern -File 

# Filter only logs that were created today
$TodaysLogFiles = $LogFiles | Where-Object { $_.LastWriteTime -ge $TodayStart -and $_.LastWriteTime -le $TodayEnd } | Sort-Object LastWriteTime -Descending

Write-Verbose -Message "Start date is $($CutoffDate.ToString('G'))"
# Filter and delete files older than 7 days
$OldLogFiles = $LogFiles | Where-Object { $_.CreationTime -lt $CutoffDate }
if ($OldLogFiles) {
    Write-Output "INFO: Deleting $(($OldLogFiles).Count) log file(s) older than 7 days..."
    $OldLogFiles | ForEach-Object {
        Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
        Write-Output "Deleted: $($_.FullName)"
    }
}

# Check if there are logs created specifically today
if (-Not $TodaysLogFiles) {
    Write-Error "ERROR: No log files created today ($TodayStart - $TodayEnd) found in $LogDirectory"
    exit 1
}

$LogFilePath = $TodaysLogFiles.FullName

# Get the system drive letter
$systemDrive = $env:SystemDrive

# Get the free space on the system drive
$drive = Get-PSDrive -Name ($systemDrive -replace ':', '')

# Calculate and display the free space in GB
$freeSpaceGB = [math]::Round($drive.Free / 1GB, 2)

# Process log file
try {
    Write-Output "Reading log file: $LogFilePath"

    # Initialize a list to store results efficiently
    $Results = @( [IO.File]::ReadLines( $LogFilePath ) | Where-Object { $_ -match 'Timestamp:(.*?), Interval:(\d+), Process Id:(\d+), ProcessName:(.*?), UserName:(.*?), FileName:(.*?), TransferSize \(MB\):([\d,\.]+)' } | ForEach-Object {
          [PSCustomObject]@{
                Timestamp      = $( if( $timestamp = $matches[1] -as [datetime] ) { $timestamp } else { [datetime]$matches[1] })
                Interval       = [int]$matches[2]
                ProcessId      = [int]$matches[3]
                ProcessName    = $matches[4].Trim()
                UserName       = $matches[5].Trim()
                FileName       = $matches[6].Trim()
                TransferSizeMB = [math]::Round(($matches[7] -replace ",", ".") -as [double], 2)
                FreespaceGB    = $freeSpaceGB
          }
    })

    if( $Results.Count -eq 0 ) {
        Throw "No results read from $LogFilePath"
    }

    if( $raw ) {
        $Results
    }
    else {
        # Sort and select top results
        $TopResults = $Results | Sort-Object -Property TransferSizeMB -Descending | Select-Object -First $Top

        # Output results
        $TopResults |  Where-Object {$_.Filename -notlike "*pagefile.sys"} | Select-Object Timestamp, ProcessName, UserName, TransferSizeMB, FileName | Format-Table

        # Export to CSV
        $TopResults |  Where-Object {$_.Filename -notlike "*pagefile.sys"} | Export-Csv -Path $CsvFilePath -NoTypeInformation -Force

        Write-Output "Top $Top results exported to: $CsvFilePath"
    }

} catch {
    Write-Error "ERROR: An error occurred while processing the log file: $_"
    exit 1
}