Monitoring with PowerShell: Predict when disk is full

I’ve always liked predictive monitoring as it allows you to be as proactive as you can be – making small analysis on stuff like disk space can make a huge difference in how you respond to incidents but I rarely see this integrated into RMM systems – Often there are some reports on which you could extrapolate this data manually but that means you’ll only do it on demand and it will require your time.

This monitoring script creates a datapoint in a file each 30 minutes and when more than 15 data points have been collected it’ll start using the collected information to predict when the disk might be running out of space. Of course this works better over time when there are a lot of data points available. All the file really contains is a representation of how much disk space is available and compares that to the previous results.

You can use this script to help your clients replace or expand disks when required, or upgrade to different infrastructure if you need that. It only does this for drives that have a volume letter.

For the logic of it all I’ve borrowed some of the data from this blog, as my math skills are not as good as his. 😉

The Script

$Volumes = Get-Volume | Where-Object { $_.DriveLetter -ne $null -and $_.DriveType -eq "fixed" }
$SpaceMonitorPath = "C:\programdata\SpaceMonitor"
$null = new-item $SpaceMonitorPath -ItemType Directory -Force
foreach ($Volume in $Volumes) {
    if ($Volume.DriveLetter -eq 0) { continue } #fix for server 2012 recovery volume

    $Date = (get-date).ToShortDateString()
    $time = (get-date).ToShortTimeString()
    $LastWriteTime = (get-item "C:\programdata\SpaceMonitor\$($volume.DriveLetter).txt" -ErrorAction SilentlyContinue).LastWriteTime
    $Datapoints = get-content "$SpaceMonitorPath\$($volume.driveletter).txt" | convertfrom-csv -Delimiter ',' -Header "DriveLetter", "SizeUsed", "Date", "Time"
    if ($LastWriteTime -lt (get-date).AddMinutes(-30)) { 
        write-host "writing datapoint"
        $SizeUsed = $Volume.Size - $volume.SizeRemaining
        Add-Content "$SpaceMonitorPath\$($volume.driveletter).txt" -value "$($volume.DriveLetter),$([math]::round($sizeused /1gb,2)),$Date,$Time" -Force
    }
    if ($datapoints.count -gt 15) {
        $DaysInDP = ($datapoints.Date | Select-Object -Unique).count

        $tempnsumxy = 0;
        $sample = 0;
        $sumx = 0;
        $sumy = 0;
        $xsquaredsum = 0;
        foreach ($datapoint in $datapoints) {
            $sumx = $sumx + $sample;
            $sumy = $sumy + $datapoint.SizeUsed;
            $tempnsumxy = $tempnsumxy + ($sample * $datapoint.SizeUsed);

            $xsquared = $sample * $sample;
            $xsquaredsum = $xsquaredsum + $xsquared

            $sample ++
        }
        $nsumxy = $Datapoints.count * $tempnsumxy;
        $sumxy = $sumx * $sumy;
        $nsumsquaredx = $Datapoints.count * $xsquaredsum;
        $sumxsquared = $sumx * $sumx;
        $slope = ($nsumxy - $sumxy) / ($nsumsquaredx - $sumxsquared);
$slopesumx = $slope * $sumx;
        $trend = ($sumy - $slopesumx) / $Datapoints.count;
        $daysleft = [int]((($volume.Size / 1gb - $trend) / $slope) - $DaysInDP);
        $estimatedFullDate = If ($daysleft -like "-*") { "Disk is gaining space. Cannot calculate date" } else { (get-date).AddDays($daysleft) }
        [PSCustomObject]@{
            Driveletter         = $volume.DriveLetter
            EstimatedFullInDays = $daysleft
            EstimatedFullDate   = $estimatedFullDate
        }
    }
}

And that’s it! as always, Happy PowerShelling 🙂

8 Comments

  1. Andrew HUSSEY June 15, 2021 at 4:18 pm

    I have brought up with several RMM companies over the last few years that monitors on disk space aren’t as useful as they could be. Rather than an alert on a pre-defined percentage or amount what really needs to be watched is the rate of change. Looks like this should do it.

    At the risk of asking to be spoon fed – any chance on some pointers on how to deploy this (my preference – Datto RMM)

    TIA Kelvin

  2. Nigel Tatschner June 16, 2021 at 11:07 pm

    This is great, thanks for sharing.

    Also, I can tell you’re a developer because of the unneeded semicolons at the end of the line in powershell 😀 (no hate, just friendly banter)

  3. Brad Hawkins June 18, 2021 at 4:56 am

    Thanks for sharing, brilliant work as always, will be testing and implementing this for sure.
    One small modification suggestion, adjust line 10 to test if the file exists before trying to read it to prevent the ItemNotFoundException when first running the script.

    if (Test-Path -Path “$SpaceMonitorPath\$($volume.driveletter).txt”){$Datapoints = get-content “$SpaceMonitorPath\$($volume.driveletter).txt” | convertfrom-csv -Delimiter ‘,’ -Header “DriveLetter”, “SizeUsed”, “Date”, “Time”}

    1. Kelvin Tegelaar June 18, 2021 at 4:18 pm

      You could, but most RMM systems ignore errors anyway and it’ll write to the file no matter what, so it’s a little redundant 🙂

  4. Aslan June 18, 2021 at 4:10 pm

    Let me try to add something useful:
    1) You don’t need those fix for 2012 if use
    ” $_.DriveLetter -notin (‘0’,$null)”
    as a Where-Object condition. It’s also could be usefull to make something like this:
    $LettersToSkip = (“0″,$null,”Z”)
    $Volumes = Get-Volume | Where-Object {$_.DriveLetter -notin $LettersToSkip -and $_.DriveType -eq “fixed”}
    #Someone can add allways-full disks (like separated disk for pagefile) letters here.
    2) “$null = new-item $SpaceMonitorPath -ItemType Directory -Force”
    #I would check first if $SpaceMonitorPath exists. Or add “-erroraction silentlycontinue” at least to avoid errors about folder already exists.

    It’s always easy to say someone how to code =D Thanks for sharing! We are using Zabbix for monitoring those things. Anyway it could be useful, added to my bookmarks.

    1. Kelvin Tegelaar June 18, 2021 at 4:19 pm

      You could use -notin yes, but that would break PowerShell compatibility so I would not recommend that for your RMM system, the other option is redundant. 🙂

  5. uandit September 30, 2021 at 11:09 pm

    Very nice! Will do some testing soon. Thank you for sharing.

  6. JC Reyes October 6, 2021 at 7:23 pm

    Would this be something you set to run on a daily or weekly schedule?

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.