Wrapper-smartctl.ps1

#!/usr/bin/env powershell
#requires -Version 3

<#PSScriptInfo
    .TITLE smartctl-Wrapper
    .DESCRIPTION List S.M.A.R.T values with smartctl.
    .VERSION 1.1.1
    .GUID 0ab53c0d-988a-4e5e-aa37-6b3c021b4a7b
    .AUTHOR Velocet [GitHub], markekraus [GitHub]
    .COMPANYNAME
    .COPYRIGHT (c) 2016 Velocet, Icon by Iconic [useiconic.com]
    .TAGS smartctl smart wrapper S.M.A.R.T
    .LICENSEURI https://github.com/Velocet/PowerShell/blob/master/LICENSE
    .PROJECTURI https://github.com/velocet/PowerShell/blob/master/Velocet/Scripts/Wrapper-smartctl.ps1
    .ICONURI https://github.com/Velocet/PowerShell/raw/master/Velocet/Scripts/Wrapper-smartctl.png
    .EXTERNALMODULEDEPENDENCIES
    .REQUIREDSCRIPTS
    .EXTERNALSCRIPTDEPENDENCIES
    .RELEASENOTES 1.1.1 [2016-10-17] [Git Sux Edition] Typos, Logo cleaned
    1.1.0 [2016-10-16] Merged pull request, see GitHub (thx Mark!)
    1.0.0 [2016-10-08] Initial version
    Based on: http://stackoverflow.com/a/28570708/6813931/
#>


function Get-SMART {
  <#
      .SYNOPSIS
      Get the S.M.A.R.T values for the given device (eg. HDD, SSD, etc.).
      .DESCRIPTION
      Output the S.M.A.R.T values with the help of smartctl for the given device. For further information refer to the smartmontools homepage.
      Could and should be used in conjunction with Invoke-SMARTScan.
      .PARAMETER DeviceName
      Specifies the name of the device to query.
      .EXAMPLE
      Get-SMART /dev/sda | Format-Table
      Output the S.M.A.R.T values for /dev/sda as a nicely formatted table.
      .EXAMPLE
      Invoke-SMARTScan | Get-SMART | ft *
      >DeviceName ID Attribute Flag Value Worst Treshold Type Updated Failing Now Raw
      >---------- -- --------- ---- ----- ----- -------- ---- ------- ----------- ---
      >/dev/sda 1 Raw_Read_Error_Rate 0x002f 100 100 002 Pre-fail Always - 0
      >/dev/sda 5 Reallocated_Sector_Ct 0x0033 100 100 010 Pre-fail Always - 0
      >...
 
      Output the S.M.A.R.T values for all devices and prints it as a nice table.
      .INPUTS
      String
      .OUTPUTS
      PSObject
      .NOTES
      smartmontools (smartctl) needs to be installed in the standard path ($env:ProgramFiles) under Windows.
      smartmontools could be obtained via Chocolatey (choco install smartmontools) on Windows, from smartmontools.org or your preferred package manager on Linux/macOS.
 
      Values that should be monitored if looking for failing HDDs (does not apply to SSDs) are:
 
      ID Attribute
      -- ---------
      5 Reallocated Sectors Count
      187 Reported Uncorrectable Errors
      188 Command Timeout
      197 Current Pending Sector Count
      198 Uncorrectable Sector Count
      .LINK
      https://github.com/velocet/PowerShell/blob/master/Velocet/Scripts/Wrapper-smartctl.ps1
      .LINK
      https://smartmontools.org/
      .COMPONENT
      smartctl
  #>

  [OutputType([PSObject])]
  param
  (
    [Parameter(
        Mandatory,
        ValueFromPipeline,
        ValueFromPipelineByPropertyName,
        HelpMessage='Device Name (eg. /dev/sda)'
    )]
    [ValidateNotNullOrEmpty()]
    [Alias('Dev')]
    [string[]]$DeviceName
  )

  process {

    foreach ($Device in $DeviceName) {

      # Get the S.M.A.R.T values
      try {
        if ($env:OS -like 'Windows_NT') {
          $Drive = [string[]](& "$env:ProgramFiles\smartmontools\bin\smartctl.exe" -A $Device) | Select-Object -Skip 7
        } # Windows
        else {
          $Drive = [string[]](& smartctl -A $Device) | Select-Object -Skip 7
        } # Obscure other OS
      }
      catch [Management.Automation.CommandNotFoundException] {
        Write-Warning -Message 'Smartmontools not installed in the default directory!'
        Write-Warning -Message 'Install smartmontools from https://smartmontools.org/ or create a symbolic link if smartmontools is not installed in the default directory:'
        Write-Warning -Message 'PS> New-Item -ItemType SymbolicLink -Name "$env:ProgramFiles\smartmontools" -Target "PATH\TO\SMARTMONTOOLS"'
      } # Catch Windows Command Not Found Exception
      catch {
        Write-Warning -Message 'Smartmontools not installed or not accessible!'
      } # Catch Linux/macOS Command Not Found Exception

      foreach ($item in $Drive) {
        if ($item -Match '^\s*(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+(\d+)\s+([\d-]+)\s+([\w-]+)\s+(\w+)\s+([\w-]+)\s+(\d+)') {
          $obj = [PSCustomObject]@{
            'DeviceName'   = $Device
            'ID'          = $matches[1]
            'Attribute'   = $matches[2]
            'Flag'        = $matches[3]
            'Value'       = $matches[4]
            'Worst'       = $matches[5]
            'Treshold'    = $matches[6]
            'Type'        = $matches[7]
            'Updated'     = $matches[8]
            'Failing Now' = $matches[9]
            'Raw'         = $matches[10]
          }
          Write-Output -InputObject $obj
        } #End if
      } #End foreach Item
    } # End foreach Device
  } #End process
} #End function

function Invoke-SMARTScan {
  <#
      .SYNOPSIS
      Scans for devices and prints each device name and protocol.
      .DESCRIPTION
      Output the name and type of the attached devices available to smartctl.
      .EXAMPLE
      Invoke-SMARTScan
      >DeviceName DeviceType
      >---------- ----------
      >/dev/sda ata
      >/dev/sdb scsi
      >/dev/sdc scsi
      >/dev/csmi0,0 ata
      Output a list of all devices with their name and type.
      .EXAMPLE
      Invoke-SMARTScan | Get-SMART | ft
      Output the S.M.A.R.T values for all devices as a nice table.
      .INPUTS
      None.
      .OUTPUTS
      PSObject.
      .NOTES
      smartmontools (smartctl) needs to be installed in the standard path ($env:ProgramFiles) under Windows.
      smartmontools could obtained via Chocolatey (choco install smartmontools) on Windows, from smartmontools.org or your preferred package manager on Linux/macOS.
      .LINK
      https://github.com/velocet/PowerShell/blob/master/Velocet/Scripts/Wrapper-smartctl.ps1
      .LINK
      https://smartmontools.org/
      .COMPONENT
      smartctl
  #>


  try {
    if ($env:OS -like 'Windows_NT') {
      $Scan = & "$env:ProgramFiles\smartmontools\bin\smartctl.exe" --scan
    } # Windows
    else {
      $Scan = & smartctl --scan
    } # Obscure other OS
  }
  catch [Management.Automation.CommandNotFoundException] {
    Write-Warning -Message 'Smartmontools not installed in the default directory!'
    Write-Warning -Message 'Install smartmontools from https://smartmontools.org/ or create a symbolic link if smartmontools is not installed in the default directory:'
    Write-Warning -Message 'PS> New-Item -ItemType SymbolicLink -Name "$env:ProgramFiles\smartmontools" -Target "PATH\TO\SMARTMONTOOLS"'
  } # Catch Windows Command Not Found Exception
  catch {
    Write-Warning -Message 'Smartmontools not installed or not accessible!'
  } # Catch Linux/macOS Command Not Found Exception

  foreach ($Device in $Scan) {
    $Device = $Device.Split()
    $obj = [PSCustomObject]@{
      'DeviceName' = $Device[0]
      'Type'       = $Device[2]
    }
    Write-Output -InputObject $obj
  } # End foreach Device
}