Monitoring with PowerShell: Monitoring SMART status using SmartCTL.

Some time ago I wrote a blog about monitoring SMART status with CrystalDiskInfo. After bringing this script over to our production RMM environment everything seemed good. But when I looked a little deeper I found that the script failed on NVME drives. NVME drives handle SMART-Status different from ‘regular’ SATA drives.

This started me on a quest for a solution that also worked on NVME drives. I’ve decided to use SmartMonTools as it has the same benefits as crystaldiskmark – It’s portable, does not require an installation, and is small enough to be downloaded on demand.

The script is fairly straightforward, it downloads the utility from a host, extracts the utility and runs an update for SmartCTL so it can fill in the data correctly. After this for each HDD in the system it will run a compare to the thresholds you’ve setup.

I’ve also had a request for disk monitoring on specifically the available spare count. The script can be edited to monitor this too – that way you can decide your own thresholds over what the manufacturer said is default for the disk.

The script

############ Thresholds #############
$PowerOnTime = 35063 #about 4 years constant runtime.
$PowerCycles = 4000 #4000 times of turning drive on and off
$Temperature = 60 #60 degrees celcius
############ End Thresholds #########
$DownloadURL = "https://cyberdrain.com/wp-content/uploads/2020/02/Smartmontools.zip"
$DownloadLocation = "$($Env:ProgramData)\SmartmonTools"
try {
    $TestDownloadLocation = Test-Path $DownloadLocation
    if (!$TestDownloadLocation) { new-item $DownloadLocation -ItemType Directory -force }
    $TestDownloadLocationZip = Test-Path "$DownloadLocation\Smartmontools.zip"
    if (!$TestDownloadLocationZip) { Invoke-WebRequest -UseBasicParsing -Uri $DownloadURL -OutFile "$($DownloadLocation)\Smartmontools.zip" }
    $TestDownloadLocationExe = Test-Path "$DownloadLocation\smartctl.exe"
    if (!$TestDownloadLocationExe) { Expand-Archive "$($DownloadLocation)\Smartmontools.zip" -DestinationPath $DownloadLocation -Force }
}
catch {
    write-host "The download and extraction of SMARTCTL failed. Error: $($_.Exception.Message)"
    exit 1
}
#update the smartmontools database
start-process -filepath "$DownloadLocation\update-smart-drivedb.exe" -ArgumentList "/S" -Wait
#find all connected HDDs
$HDDs = (& "$DownloadLocation\smartctl.exe" --scan -j | ConvertFrom-Json).devices
$HDDInfo = foreach ($HDD in $HDDs) {
    (& "$DownloadLocation\smartctl.exe" -t short -a -j $HDD.name) | convertfrom-json
}
$DiskHealth = @{}
#Checking SMART status
$SmartFailed = $HDDInfo | Where-Object { $_.Smart_Status.Passed -ne $true }
if ($SmartFailed) { $DiskHealth.add('SmartErrors',"Smart Failed for disks: $($SmartFailed.serial_number)") }
#checking Temp Status
$TempFailed = $HDDInfo | Where-Object { $_.temperature.current -ge $Temperature }
if ($TempFailed) { $DiskHealth.add('TempErrors',"Temperature failed for disks: $($TempFailed.serial_number)") }
#Checking Power Cycle Count status
$PCCFailed = $HDDInfo | Where-Object { $_.Power_Cycle_Count -ge $PowerCycles }
if ($PCCFailed ) { $DiskHealth.add('PCCErrors',"Power Cycle Count Failed for disks: $($PCCFailed.serial_number)") }
#Checking Power on Time Status
$POTFailed = $HDDInfo | Where-Object { $_.Power_on_time.hours -ge $PowerOnTime }
if ($POTFailed) { $DiskHealth.add('POTErrors',"Power on Time for disks failed : $($POTFailed.serial_number)") }

if (!$DiskHealth) { $DiskHealth = "Healthy" }

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

3 thoughts on “Monitoring with PowerShell: Monitoring SMART status using SmartCTL.

  1. Remco

    Hi,

    For some reason it doesn’t work on my Microsoft Surface laptop, when i run “smartctl.exe -t short -a -j /dev/sda” it shows the information.

    But when i run this “smartctl.exe -t short -a -j /dev/sda | Where-Object { $_.smart_status.Passed -ne $true }” it shows ALL the values, even when i change $true to $false.

    I have a NVME drive, but i don’t think this script as idiot proof as it could be. I don’t know what the problem is yet, but just inform you.

    Reply
    1. Kelvin Tegelaar Post author

      I’ll have to check that out, could you send me the entire printout of “smartctl.exe -t short -a -j /dev/sda” and remove your serial numbers? I’ll be able to see where it fails exactly. 🙂 It could also be that your hard drive is not in the SmartCTL database yet. I’ll be able to evaluate that based on the output.

      Reply
  2. NAC

    Can you spot what I’m doing wrong? I’ve copied it character by character. Thank you in advance!

    At C:\hd.ps1:23 char:12
    + $HDDs = (& "$DownloadLocation\smartctl.exe” –scan -j | ConvertF …
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks (“&”) to pass it as part of a string.
    At C:\hd.ps1:23 char:17
    + $HDDs = (& "$DownloadLocation\smartctl.exe” –scan -j | ConvertF …
    + ~
    Missing closing ‘)’ in expression.
    At C:\hd.ps1:23 char:35
    + … $DownloadLocation\smartctl.exe” –scan -j | ConvertFrom-Json).devices
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Unexpected token ‘\smartctl.exe” –scan -j | ConvertFrom-Json).devices
    $HDDInfo = foreach ($HDD in $HDDs) {
    (& “$DownloadLocation\smartctl.exe” -t short -a -j $HDD.name) | convertfrom-json
    }
    $DiskHealth = @{}
    #Checking SMART status
    $SmartFailed = $HDDInfo | Where-Object { $_.Smart_Status.Passed -ne $true }
    if ($SmartFailed) { $DiskHealth.add(‘SmartErrors’,”Smart’ in expression or statement.
    At C:\hd.ps1:41 char:43
    + if (!$DiskHealth) { $DiskHealth = “Healthy” }
    + ~~~
    The string is missing the terminator: “.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : AmpersandNotAllowed

    Reply

Leave a Reply

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.