Function/GetHddSmart.ps1

function GetHddSmart
{
param ($OsVersion)
    function ConvertTo-Hex ( $DEC ) {
        '{0:x2}' -f [int]$DEC
    }
    function ConvertTo-Dec ( $HEX ) {
        [Convert]::ToInt32( $HEX, 16 )
    }
    function Get-AttributeDescription ( $Value ) {
        switch ($Value) {
            '01' { 'Raw Read Error Rate' }
            '02' { 'Throughput Performance' }
            '03' { 'Spin-Up Time' }
            '04' { 'Number of Spin-Up Times (Start/Stop Count)' }
            '05' { 'Reallocated Sector Count' }
            '07' { 'Seek Error Rate' }
            '08' { 'Seek Time Performance' }
            '09' { 'Power On Hours Count (Power-on Time)' }
            '0a' { 'Spin Retry Count' }
            '0b' { 'Calibration Retry Count (Recalibration Retries)' }
            '0c' { 'Power Cycle Count' }
            'aa' { 'Available Reserved Space' }
            'ab' { 'Program Fail Count' }
            'ac' { 'Erase Fail Count' }
            'ae' { 'Unexpected power loss count' }
            'b7' { 'SATA Downshift Error Count' }
            'b8' { 'End-to-End Error' }
            'bb' { 'Reported Uncorrected Sector Count (UNC Error)' }
            'bc' { 'Command Timeout' }
            'bd' { 'High Fly Writes' }
            'be' { 'Airflow Temperature' }
            'bf' { 'G-Sensor Shock Count (Mechanical Shock)' }
            'c0' { 'Power Off Retract Count (Emergency Retry Count)' }
            'c1' { 'Load/Unload Cycle Count' }
            'c2' { 'Temperature' }
            'c3' { 'Hardware ECC Recovered' }
            'c4' { 'Reallocated Event Count' }
            'c5' { 'Current Pending Sector Count' }
            'c6' { 'Offline Uncorrectable Sector Count' }
            'c7' { 'UltraDMA CRC Error Count' }
            'c8' { 'Write Error Rate (MultiZone Error Rate)' }
            'c9' { 'Soft Read Error Rate' }
            'cb' { 'Run Out Cancel' }
            'c�' { 'Data Address Mark Error' }
            'dc' { 'Disk Shift' }
            'e1' { 'Load/Unload Cycle Count' }
            'e2' { 'Load ''In''-time' }
            'e3' { 'Torque Amplification Count' }
            'e4' { 'Power-Off Retract Cycle' }
            'e8' { 'Endurance Remaining' }
            'e9' { 'Media Wearout Indicator' }
            'f0' { 'Head Flying Hours' }
            'f1' { 'Total LBAs Written' }
            'f2' { 'Total LBAs Read' }
            'f9' { 'NAND Writes (1GiB)' }
            'fe' { 'Free Fall Protection' }
            default { $Value }
        }
    }

$PnpDev=@{}
$hdddev=$Win32_DiskDrive | Select-Object Model,Size,MediaType,InterfaceType,FirmwareRevision,SerialNumber,PNPDeviceID,Index
$hdddev | foreach {
    $PnpDev.Add($($_.pnpdeviceid -replace "\\","\\"),$_)
}
$AllHddSmart=@()
$PnpDev.Keys | foreach {
    $PnpDevid=$_
    $TmpFailData=$MSStorageDriver_FailurePredictData | Where-Object  {$_.InstanceName -Match $PnpDevid}
    $TmpFailStat=$MSStorageDriver_FailurePredictStatus | Where-Object  {$_.InstanceName -Match $PnpDevid}
    if ($TmpFailStat)
    {
        $PnpDev[$PnpDevid] | Add-Member -MemberType NoteProperty -Name  PredictFailure -Value $TmpFailStat.PredictFailure
    }
    else
    {
        $PnpDev[$PnpDevid] | Add-Member -MemberType NoteProperty -Name  PredictFailure -Value 'Unknown'
    }
    if ($TmpFailData)
    {
        $Disk=$TmpFailData
        $i = 0
        #$Report = @()
        $pByte = $null
                foreach ( $Byte in $Disk.VendorSpecific ) {
                    $i++
                    if (( $i - 3 ) % 12 -eq 0 ) 
                    {
                        if ( $Byte -eq 0) { break }
                        $Attribute = '{0:x2}' -f [int]$Byte
                    } 
                    else 
                    {
                        $post = ConvertTo-Hex $pByte
                        $pref = ConvertTo-Hex $Byte
                        $Value = ConvertTo-Dec "$pref$post"
                        if (( $i - 3 ) % 12 -eq 6 ) 
                        {
                            if ( $Attribute -eq '09' ) { [int]$Value = $Value / 24 }
                            $PnpDev[$PnpDevid] | Add-Member -MemberType NoteProperty -Name $(Get-AttributeDescription $Attribute) -Value $Value -Force
                        }
                    }
                    $pByte = $Byte
                }
        
    }
    else
    {
        $PnpDev[$PnpDevid] | Add-Member -MemberType NoteProperty -Name SmartStatus -Value 'Unknown' 
    }
    $HddSmart=$PnpDev[$PnpDevid]
    $WarningThreshold=@{
    "Temperature"=48,54
    "Reallocated Sector Count"=1,10
    "Reallocated Event Count"=1,10
    "Offline Uncorrectable Sector Count"=1,10
    "Current Pending Sector Count"=1,10
    }
    $CriticalThreshold=@{
    "Temperature"=55
    "Reallocated Sector Count"=11
    "Reallocated Event Count"=11
    "Offline Uncorrectable Sector Count"=11
    "Current Pending Sector Count"=11
    }
        $HddWarning=$False
        $HddCritical=$False
        $HddSmart | Get-Member | foreach {
            $Property=$_.name
            if (!$HddCritical)
            {
                if ($WarningThreshold[$Property])
                {
                    $MinWarningThreshold=$WarningThreshold[$Property][0]
                    $MaxWarningThreshold=$WarningThreshold[$Property][1]
                        if ($HddSmart.$Property -le $MaxWarningThreshold -and $HddSmart.$Property -ge $MinWarningThreshold)
                        {
                            $HddWarning=$true
                            $Cause=$($Property -replace " ")+" "+[string]$($HddSmart.$Property)
                            if ($HddSmart.$Property -ge $WarningEventCount)
                            {
                                $RootCause=$Cause
                                $WarningEventCount=$HddSmart.$Property
                            }
                            Write-Verbose "Smart Warning $cause"
                            
                        }
                }
            }
            if ($CriticalThreshold[$Property])
            {
                $MinCriticalThreshold=$CriticalThreshold[$Property]
                    if($HddSmart.$Property -ge $MinCriticalThreshold)
                    {
                        $HddCritical=$true
                        $Cause=$($Property -replace " ")+" "+[string]$($HddSmart.$Property)
                        if ($HddSmart.$Property -ge  $CriticalEventCount)
                        {
                            $RootCause=$Cause    
                            $CriticalEventCount=$HddSmart.$Property
                        }
                        Write-Verbose "Smart Critical $cause" 
                        
                    } 
            }
              
            
        #End Foreach
        }
    if ($HddSmart.smartstatus -ne "Unknown")
    {
        if ($HddWarning)
        {
            $HddSmart | Add-Member -MemberType NoteProperty -Name SmartStatus -Value "Warning:$RootCause" 
        }
        elseif($HddCritical -or $HddSmart.PredictFailure)
        {
            $HddSmart | Add-Member -MemberType NoteProperty -Name SmartStatus -Value "Critical:$RootCause"   
        }
        else
        {
            $HddSmart | Add-Member -MemberType NoteProperty -Name SmartStatus -Value "Ok"   
        }
    }
$AllHddSmart+=$HddSmart
#End Foreach
}

if ([version]$OsVersion -ge [version]"6.2")
{
    #https://msdn.microsoft.com/en-us/library/windows/desktop/hh830532(v=vs.85)#methods
    $BusTypeHashTable=@{
    "0"="Unknown"
    "1"="SCSI"
    "2"="ATAPI"
    "3"="ATA"
    "4"="IEEE 1394"
    "5"="SSA"
    "6"="FibreChannel"
    "7"="USB"
    "8"="RAID"
    "9"="iSCSI"
    "10"="SAS"
    "11"="SATA"
    "12"="SD"
    "13"="MMC"
    "15"="FileBackedVirtual"
    "16"="StorageSpaces"
    }
    $MediaTypeHashTable=@{
    "0"="Unknown"
    "3"="HDD"
    "4"="SSD"
    "5"="SCM"
    }

    Write-Verbose "$ComputerName Windows 8 or later detected"
    if ($credential -eq $null)
    {
        $MSFT_PhysicalDisk=Get-WmiObject -Class MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage -ComputerName $computername -ErrorAction SilentlyContinue
    }
    else
    {
       $MSFT_PhysicalDisk= Get-WmiObject -Class MSFT_PhysicalDisk -Namespace root\Microsoft\Windows\Storage -ComputerName $computername -Credential $credential -ErrorAction SilentlyContinue
    }
    
    if ($MSFT_PhysicalDisk -ne $null)
    {
        $AllHddSmart | foreach {
            $HddSmart=$_
            $MsftDisk=$MSFT_PhysicalDisk | Where-Object  {$_.DeviceId -eq $HddSmart.index} 
            $InterfaceType=$BusTypeHashTable["$($MsftDisk.bustype)"]
            $MediaType=$MediaTypeHashTable["$($MsftDisk.mediatype)"]
            if ($InterfaceType -ne $null)
            {
                $HddSmart.InterfaceType=$InterfaceType
            }
           
            $HddSmart | Add-Member -MemberType NoteProperty -Name Type -Value $MediaType
            
        }    
        $AllHddSmart
    }
    else
    {
        $AllHddSmart | foreach {
            $_ | Add-Member -MemberType NoteProperty -Name Type -Value "Unknown"
            $_
        }
    }
}
else
{
    $AllHddSmart | foreach {
        $_ | Add-Member -MemberType NoteProperty -Name Type -Value "Unknown"
        $_
    }
}


}