365 lines
8.5 KiB
PowerShell
Executable File
365 lines
8.5 KiB
PowerShell
Executable File
# By MH 2020, MIT-License
|
|
# TODO: Logging (Sucess, Error), Windows-Support
|
|
|
|
param (
|
|
[switch]$smart_disco,
|
|
[switch]$smart_check,
|
|
[switch]$smart_with_external
|
|
)
|
|
|
|
|
|
### Misc Helper Functions
|
|
|
|
function Get-IsUSBDrive {
|
|
param (
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]$DeviceFile
|
|
)
|
|
|
|
$x = lsblk -d $DeviceFile -o SUBSYSTEMS | Out-String -stream | Select-String usb
|
|
$x.Matches.Length -gt 0
|
|
}
|
|
|
|
|
|
### Smart-Helper Functions
|
|
|
|
|
|
class SmartDev {
|
|
[String]$DeviceFile
|
|
[String]$Name
|
|
[String]$Type
|
|
}
|
|
|
|
|
|
# First letter lower-case for compat with zabbix-expected Json
|
|
class SmartDiscoEntry {
|
|
[String]$name
|
|
[String]$type
|
|
[String]$model
|
|
[String]$sn
|
|
[int]$rotations
|
|
[int]$lbs
|
|
[int]$isExternal
|
|
[int]$isSSD
|
|
}
|
|
|
|
|
|
class SmartInfoEntry {
|
|
[String]$Name
|
|
[String]$DeviceFile
|
|
[String]$Health
|
|
[int]$PowerOnHours
|
|
[int]$PowerCycleCount
|
|
[double]$Temperature
|
|
}
|
|
|
|
|
|
function Get-SmartDevsFromScan {
|
|
|
|
$Res=@()
|
|
|
|
foreach ($ln in (smartctl -n standby --scan | Out-String -stream)) {
|
|
$Obj = New-Object SmartDev
|
|
$parts=(-Split $ln)
|
|
$Obj.DeviceFile=$parts[0]
|
|
$Obj.Name=($parts[0] -Split "/")[2]
|
|
$Obj.Type=(($ln -Split ",")[1] -Split " ")[1]
|
|
$Res += $Obj
|
|
}
|
|
|
|
return $Res
|
|
}
|
|
|
|
function Get-SmartDisco {
|
|
|
|
$Res = @()
|
|
|
|
foreach ($dev in Get-SmartDevsFromScan) {
|
|
$isUSB=Get-IsUSBDrive -DeviceFile $dev.DeviceFile
|
|
|
|
|
|
$model = ""
|
|
|
|
# TODO Support SSD
|
|
$isSSD=0
|
|
if ( $isUSB -eq $False ) {
|
|
$j = smartctl -n standby -a $dev.DeviceFile --json | ConvertFrom-Json
|
|
|
|
$model = $j.model_name
|
|
$sn = $j.serial_number
|
|
$rotrate = $j.rotation_rate
|
|
$lbs = $j.logical_block_size
|
|
}
|
|
else {
|
|
$model = $null
|
|
$sn = $null
|
|
$rotrate = $null
|
|
$lbs = $null
|
|
}
|
|
|
|
$Obj=New-Object SmartDiscoEntry
|
|
$Obj.name=$dev.Name
|
|
$Obj.type=$dev.Type
|
|
$Obj.model=$model
|
|
$Obj.sn=$sn
|
|
$Obj.rotations=$rotrate
|
|
$Obj.lbs=$lbs
|
|
$Obj.isExternal=$isUSB ? 1 : 0
|
|
$Obj.isSSD=$isSSD
|
|
$Res += $Obj
|
|
}
|
|
|
|
|
|
return $Res
|
|
}
|
|
|
|
|
|
|
|
function Get-SmartInfo {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[SmartDev]$device
|
|
)
|
|
|
|
$Res = New-Object SmartInfoEntry
|
|
$Res.DeviceFile = $device.DeviceFile
|
|
$Res.Name = $device.Name
|
|
|
|
smartctl -s on $device.DeviceFile | out-null
|
|
|
|
$st=$(smartctl -n standby -q errorsonly -H $device.DeviceFile)
|
|
|
|
if ( $st.Trim.Length -eq 0 ) {
|
|
$st = "OK"
|
|
}
|
|
|
|
|
|
$j=smartctl -n standby -a $device.DeviceFile --json | ConvertFrom-Json
|
|
|
|
$Res.Health = $st
|
|
$Res.PowerOnHours = $j.power_on_time.hours
|
|
$Res.PowerCycleCount = $j.power_cycle_count
|
|
$Res.Temperature = $j.temperature.current
|
|
|
|
return $Res
|
|
}
|
|
|
|
|
|
function Get-SmartInfos {
|
|
|
|
param (
|
|
[bool]$withExternalDevs
|
|
)
|
|
|
|
$Res = @()
|
|
|
|
foreach ($dev in Get-SmartDevsFromScan) {
|
|
$isUSB=Get-IsUSBDrive -DeviceFile $dev.DeviceFile
|
|
|
|
if ( $isUSB -And -Not $withExternalDevs ) {
|
|
continue
|
|
}
|
|
|
|
smartctl -s on $dev.DeviceFile | out-null
|
|
|
|
$si = Get-SmartInfo -device $dev
|
|
$Res += $si
|
|
}
|
|
|
|
return $Res
|
|
}
|
|
|
|
|
|
### Monitoring functions
|
|
|
|
function Send-SmartDiscoToZabbix {
|
|
$disco = Get-SmartDisco
|
|
|
|
$jsons=$disco | ConvertTo-Json -Compress
|
|
zabbix_sender -vv -k "8o_smartcheck.disco_devs" -o '$jsons' -c /etc/zabbix/zabbix_agentd.conf
|
|
}
|
|
|
|
|
|
function Send-SmartInfosToZabbix {
|
|
|
|
param (
|
|
[bool]$withExternalDevs
|
|
)
|
|
|
|
&{
|
|
foreach( $dev in Get-SmartInfos -withExternalDevs $withExternalDevs ) {
|
|
# Better solution?
|
|
$dn = $dev.Name
|
|
Write-Output "- 8o_smartcheck.[${dn}.health] $($dev.Health)"
|
|
Write-Output "- 8o_smartcheck.[${dn}.power_on_hours] $($dev.PowerOnHours)"
|
|
Write-Output "- 8o_smartcheck.[${dn}.power_cycle_count] $($dev.PowerCycleCount)"
|
|
Write-Output "- 8o_smartcheck.[${dn}.temperature] $($dev.Temperature)"
|
|
}
|
|
} | zabbix_sender -vv -i - -c /etc/zabbix/zabbix_agentd.conf
|
|
}
|
|
|
|
|
|
$exitcode=0
|
|
|
|
if ( $smart_disco ) {
|
|
Write-Output "Doing SMART-Disco "
|
|
Send-SmartDiscoToZabbix
|
|
}
|
|
|
|
if ( $smart_check ) {
|
|
Write-Output "Doing SMART-Check withExternal: ${smart_with_external} "
|
|
Send-SmartInfosToZabbix -withExternalDevs $smart_with_external
|
|
}
|
|
|
|
Write-Output "Done"
|
|
|
|
exit $exitcode
|
|
|
|
and here is the original Bash-version:
|
|
|
|
#!/bin/bash
|
|
|
|
# By MH 2020, MIT-License
|
|
|
|
|
|
_smart_is_usb()
|
|
{
|
|
rem=$(lsblk -d "$1" -o SUBSYSTEMS | grep "usb" | wc -l)
|
|
if [[ "${rem}" == "0" ]]; then
|
|
echo 0
|
|
else
|
|
echo 1
|
|
fi
|
|
}
|
|
|
|
_smart_getval()
|
|
{
|
|
echo -e "$1" | grep -i "^${2} = " | cut -d "=" -f 2 | cut -d '"' -f 2
|
|
}
|
|
|
|
_smart_getval_i()
|
|
{
|
|
res=$(echo -e "$1" | grep -i "^${2} = " | cut -d "=" -f 2 | cut -d ' ' -f 2 | tr -d ";")
|
|
if [[ "$res" == "" ]]; then
|
|
res=0
|
|
fi
|
|
echo "${res}"
|
|
}
|
|
|
|
|
|
smart_disco() {
|
|
c=0
|
|
devs=""
|
|
while read ln; do
|
|
dev=$(echo ${ln} | cut -d " " -f 1 | sed -e "s/\/dev\///g")
|
|
typ=$(echo ${ln} | cut -d " " -f 3)
|
|
|
|
|
|
# Removable
|
|
# rem=$(lsblk -d /dev/${dev} -o SUBSYSTEMS | grep "usb" | wc -l)
|
|
rem=$(_smart_is_usb "/dev/${dev}")
|
|
|
|
if [[ "${rem}" == "0" ]]; then
|
|
smart="$(smartctl -n standby -a /dev/${dev} --json=g)"
|
|
model="$(_smart_getval "${smart}" "json.model_name")"
|
|
sn="$(_smart_getval "${smart}" "json.serial_number")"
|
|
rot="$(_smart_getval_i "${smart}" "json.rotation_rate")"
|
|
lbs="$(_smart_getval_i "${smart}" "json.logical_block_size")"
|
|
|
|
#SSD: TODO
|
|
isSSD=0
|
|
fi
|
|
|
|
if (( c == 1 )); then
|
|
devs="${devs},\n"
|
|
fi
|
|
c=1
|
|
|
|
devs="${devs} {\n"
|
|
|
|
if [[ "${rem}" == "0" ]]; then
|
|
devs="${devs} \"name\": \"${dev}\",\n"
|
|
devs="${devs} \"type\": \"${typ}\",\n"
|
|
devs="${devs} \"model\": \"${model}\",\n"
|
|
devs="${devs} \"sn\": \"${sn}\",\n"
|
|
devs="${devs} \"rotations\": ${rot},\n"
|
|
devs="${devs} \"lbs\": ${lbs},\n"
|
|
devs="${devs} \"isExternal\": ${rem},\n"
|
|
devs="${devs} \"isSSD\": ${isSSD}\n"
|
|
else
|
|
devs="${devs} \"name\": \"${dev}\",\n"
|
|
devs="${devs} \"isExternal\": ${rem}\n"
|
|
fi
|
|
devs="${devs} }"
|
|
|
|
done < <(smartctl -n standby --scan)
|
|
|
|
|
|
|
|
json2="\n{"
|
|
json2="${json2} \"devices\": [\n"
|
|
json2="${json2} ${devs}\n"
|
|
json2="${json2} ]\n"
|
|
json2="${json2}}"
|
|
echo -e "$json2"
|
|
|
|
# Remove newline for use as parameter
|
|
sentval="$(echo -e $json2)"
|
|
|
|
#json=$(smartctl --json --scan)
|
|
#json=$(echo "${json}" | sed -e "s/\/dev\///g")
|
|
#echo $json
|
|
|
|
zabbix_sender -vv -k "8o_smartcheck.disco_devs" -o "${sentval}" -c /etc/zabbix/zabbix_agentd.conf 2>&1 | logger -t "zabbix-smart_disco"
|
|
}
|
|
|
|
|
|
smart_check() {
|
|
(for dev in $(smartctl --scan | sed -e "s/\/dev\///g" | cut -d " " -f 1 ); do
|
|
|
|
rem=$(_smart_is_usb "/dev/${dev}")
|
|
if [[ "${rem}" == "1" ]] && [[ "${SMART_WITH_EXTERNAL}" == "0" ]]; then
|
|
#echo "X" 1>&2
|
|
continue;
|
|
fi
|
|
|
|
smartctl -s on /dev/${dev} > /dev/null
|
|
status="$(smartctl -n standby -q errorsonly -H /dev/${dev})"
|
|
if [[ "${status}" == "" ]]; then
|
|
status="OK"
|
|
fi
|
|
|
|
smart="$(smartctl -n standby -a /dev/${dev} --json=g)"
|
|
|
|
poh="$(_smart_getval_i "${smart}" "json.power_on_time.hours")"
|
|
poc="$(_smart_getval_i "${smart}" "json.power_cycle_count")"
|
|
temp="$(_smart_getval_i "${smart}" "json.temperature.current")"
|
|
|
|
|
|
|
|
#zabbix_sender -vv -k "8o_smartcheck.[${dev}.health]" -o "${status}" -c /etc/zabbix/zabbix_agentd.conf \
|
|
# 2>&1 | logger -t "zabbix-smart_health"
|
|
|
|
echo "- 8o_smartcheck.[${dev}.health] ${status}"
|
|
echo "- 8o_smartcheck.[${dev}.power_on_hours] ${poh}"
|
|
echo "- 8o_smartcheck.[${dev}.power_cycle_count] ${poc}"
|
|
echo "- 8o_smartcheck.[${dev}.temperature] ${temp}"
|
|
|
|
#echo "8o_smartcheck.[${dev}.health]"
|
|
#echo ${dev}
|
|
done) | zabbix_sender -vv -i - -c /etc/zabbix/zabbix_agentd.conf 2>&1 | logger -t "zabbix-smart_health"
|
|
|
|
}
|
|
|
|
|
|
SMART_WITH_EXTERNAL=0
|
|
|
|
if [ "$1" == "--smart-with-external" ]; then
|
|
SMART_WITH_EXTERNAL=1
|
|
fi
|
|
|
|
if [ "$1" == "--disco" ]; then
|
|
smart_disco
|
|
else
|
|
smart_check
|
|
fi |