A hard drive rarely dies without warning. Long before the final, irrecoverable failure, a drive usually drops hints: a creeping count of reallocated sectors, a wear indicator inching toward its limit, an operational status that quietly slips from healthy to predictive failure. The trouble is that nobody watches for these hints by hand. Days pass, the warning signs accumulate unread, and then one morning the drive simply does not come back. A daily health check script is the unblinking eye that watches when no human will, turning silent early symptoms into a timely alert.
The value of doing this on a schedule, rather than occasionally and manually, is exactly that it removes human forgetfulness from the equation. A person might remember to open a disk utility once a month if prompted by a vague unease; a scheduled script checks every single day without being asked, and it does so the same way every time. Trending a drive's health and temperature over days lets an administrator schedule a replacement during a maintenance window instead of scrambling after an outage. The whole point is to convert an unpredictable emergency into a routine, planned task.
What a Drive Actually Reports About Its Own Health
Modern drives keep an internal scorecard of their own condition, and Windows exposes a readable summary of it. The most direct way to see this from PowerShell is a single command that lists each physical disk along with its health and operational status. The friendly name identifies the disk in human terms, the health status reports a simple verdict of healthy, warning, or unhealthy, and the operational status gives a finer reading such as ok, lost communication, in maintenance, or predictive failure.
Get-PhysicalDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus
That summary verdict is the headline, but underneath it lies more detailed telemetry worth reading on its own. A companion command pulls the reliability counters for a specific disk, exposing wear, error counts, and temperature where the drive reports them. For a solid-state drive in particular, the wear indicator is the number to watch: it climbs as a percentage toward the point where the estimated write endurance is exhausted, so a rising value is a direct countdown to end of life.
Get-StorageReliabilityCounter -PhysicalDisk (Get-PhysicalDisk -FriendlyName "<DiskName>")
These two readings complement each other. The health status answers the blunt question of whether the drive is in trouble right now, while the reliability counters reveal how close it is creeping toward trouble, even while it still reports itself healthy. A good daily check looks at both, because a drive can pass the simple verdict while its wear or error counters are quietly telling a more worrying story.
Building the Core of the Daily Check
The heart of a useful script is a filter that flags anything not in perfect health. Rather than printing the status of every disk and trusting a human to scan the list, the script asks only for the disks whose health is anything other than healthy. If that filtered set is empty, all is well and the script can exit quietly; if it contains anything, those are exactly the disks that demand attention.
$unhealthy = Get-PhysicalDisk | Where-Object { $_.HealthStatus -ne 'Healthy' }
if ($unhealthy) {
$unhealthy | Format-Table FriendlyName, HealthStatus, OperationalStatus
Write-Warning "One or more disks report a non-healthy status."
exit 1
}
The closing exit code is more important than it looks. By exiting with a nonzero code when a problem is found and a zero code otherwise, the script speaks a language that monitoring systems and the task scheduler understand natively. An automated monitor can trigger a notification, a follow-up repair, or a ticket purely on the basis of that nonzero exit, with no need to parse text. This makes the script a clean building block in a larger automation rather than a standalone curiosity.
For solid-state drives the check can go deeper by inspecting wear and error counters against thresholds. A more advanced version pulls the reliability counters for each drive and raises a warning when write errors appear at all, since for an SSD any write error is a cause for concern, or when the wear percentage climbs past a chosen ceiling. Setting that ceiling well below a hundred percent gives ample warning before the endurance limit is actually reached, leaving time to order and install a replacement.
Adding the Free-Space Dimension to Disk Health
Physical health is only half the story; a drive that is mechanically sound but nearly full is its own kind of failure waiting to happen. A system whose system volume runs out of space behaves erratically, refuses updates, and can corrupt files mid-write. A complete daily check therefore also watches free space, and the logical-disk information exposed through the system's management interface makes this straightforward to compute for every volume.
$threshold = 10
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
if ($_.Size -gt 0) {
$percentFree = [math]::Round(($_.FreeSpace / $_.Size) * 100, 1)
if ($percentFree -lt $threshold) {
Write-Warning "Drive $($_.DeviceID) has only $percentFree% free."
}
}
}
The logic is simple arithmetic, but the discipline of checking it daily is what gives it power. Free space tends to erode slowly and then suddenly, as a runaway log file or a forgotten cache balloons over a few days. A daily glance catches the erosion while there is still time to act, rather than discovering the problem only when an application crashes because it cannot write. The chosen threshold of ten percent free is a common starting point, generous enough to leave breathing room yet tight enough not to cry wolf.
It is worth noting which command to prefer for these queries. The modern management interface command is the recommended choice for reliability and for working across machines, while the older equivalent it replaces is legacy and best avoided in new scripts. Building the daily check on the current command keeps it robust and ready to extend to remote machines later without rewriting its core.
Turning the Script into a Scheduled, Hands-Off Task
A health check that must be launched by hand is barely better than no check at all, so the final step is to register it as a scheduled task that runs on its own. The task scheduler can run a PowerShell script on a daily trigger, and registering it from PowerShell itself keeps the whole setup reproducible and easy to deploy across machines. The task is built from an action that invokes the script, a trigger that fires on schedule, and a principal that defines the privileges it runs with.
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"C:\Scripts\disk_health.ps1`""
$trigger = New-ScheduledTaskTrigger -Daily -At 9:00AM
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" `
-LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "DiskHealthDaily" `
-Action $action -Trigger $trigger -Principal $principal `
-Description "Daily disk health and free-space check"
Two details in that registration carry real weight. Running the task with the highest privileges under a service account matters because some health queries fail without elevation, leaving disks reporting an unknown status simply for lack of access rather than because anything is wrong. Choosing a daily trigger at a fixed morning time means the check has run and its results are waiting before the working day begins, so any overnight deterioration is known by the time it could matter.
Because the script and its task are both defined in code, the same setup can be pushed onto many machines identically, and a fleet of computers can all be brought under the same daily watch. Storing the script in a known folder and registering the task the same way everywhere removes the drift that creeps in when each machine is configured by hand. The result is uniform coverage rather than a patchwork of partially monitored systems.
Delivering the Alert So Someone Actually Sees It
A check that detects a failing drive but tells no one is only half a solution. The findings have to reach a human or a system that will act on them, and how the alert is delivered matters as much as how the problem is detected. The simplest route, suitable for a single workstation, is a visible notification on screen, so that whoever sits at the machine learns of a worrying disk the next time they look. A short popup summarizing which disk is in trouble and why turns an entry buried in a log into something impossible to miss.
On managed fleets the alert usually travels further than the local screen. Because the script signals trouble through its exit code, a monitoring system that runs it can react to a nonzero result by raising a ticket, sending a message, or kicking off a follow-up routine, all without anyone reading the script's text output. This is the cleanest integration, since the monitoring layer handles routing and escalation while the script concerns itself only with the diagnosis. The same exit-code convention that makes the check a good building block also makes its alerts easy to wire into whatever notification channel an organization already uses.
For setups without a full monitoring system, the script can take delivery into its own hands. It might write a prominent entry to the system event log, where existing tooling already watches for problems, or compose a brief message summarizing the unhealthy disks and send it through an available channel. Whichever path is chosen, the guiding principle is that the alert should land where the responsible person is actually looking, not merely where it is convenient to write it. A warning that arrives in an unwatched location is functionally the same as no warning at all, so the delivery method deserves as much thought as the detection logic itself.
Recording Results So Trends Become Visible
A single day's reading is a snapshot; the real diagnostic power comes from a series of them over time. For that reason a mature daily check does not merely alert when something is wrong, it also writes its findings to a dated log so that a history accumulates. A drive whose wear ticks up a fraction each week, or whose error count creeps from zero to a handful, reveals a trajectory that no single reading could, and that trajectory is what justifies a proactive replacement.
The log need not be elaborate. Appending a timestamped line summarizing each disk's health, wear, and free space to a text file is enough to build a record that an administrator can skim once a month or feed into a larger reporting system. The key is consistency of format, so that the history is easy to read back and, if desired, easy to parse for charting. Over weeks, that quiet accumulation of dated entries turns vague suspicion into hard evidence about which drive to retire and when.
This logging habit also guards against a subtle failure of automation itself. A scheduled task can silently stop running because of a permissions change, a moved script, or a broken disk, and an administrator who relies on alerts alone might mistake silence for good health. A growing log file is positive proof that the check is alive and working, and a log that stops growing is itself a signal that the monitoring needs attention. The record serves the data and the watcher at the same time.
The Quiet Discipline Behind a Daily Disk Check
The deeper lesson of a daily health check is that the cheapest moment to deal with a failing drive is long before it fails, and the only way to find that moment is to look every day. Drives broadcast their decline in small signals that are trivial to read with a command and trivial to ignore without one. A script that reads those signals on a fixed schedule converts an invisible, creeping risk into a visible, actionable one, which is the entire difference between a planned swap and a frantic recovery.
A well-built check covers all three faces of disk trouble at once: the blunt health verdict, the finer wear and error telemetry, and the often-overlooked matter of free space. It speaks in exit codes so automation can act on it, runs with the privileges it needs so its readings are trustworthy, and logs its findings so that trends emerge from the noise. None of these pieces is complicated, but together they form a reliable early-warning system that asks nothing of the administrator day to day.
That, finally, is the appeal of automating the dull but vital task of watching disks. The script does not tire, does not forget, and does not need to be reminded. It simply checks, every morning, and stays silent until the day it has something worth saying. When that day comes, the warning arrives with enough lead time to act calmly, and a potential disaster is reduced to a line item on a maintenance schedule. The modest effort of setting it up is repaid many times over the first time it catches a drive on its way out.