What is this?

This knowledgebase contains questions and answers about PRTG Network Monitor and network monitoring in general.

Learn more

PRTG Network Monitor

Intuitive to Use. Easy to manage.
More than 500,000 users rely on Paessler PRTG every day. Find out how you can reduce cost, increase QoS and ease planning, as well.

Free Download

Top Tags


View all Tags

Monitoring Linux Distributions Incompatible With The SSH Disk Free Sensor

Votes:

2

Introduction

The following script allows you to get disk metrics using an EXE/Script sensor. It will connect to the server, execute the given command and simply return the corresponding disks. Note that you may need to modify the command it executes. By default, it will execute the following:

df -k | tail -n +2

...which is suitable for for AIX distributions. The tail command will omit the translated table header, making it look like this:

/dev/root       29316584 4593144  23211172   17% /
devtmpfs          469688       0    469688    0% /dev
tmpfs             474004       0    474004    0% /dev/shm
tmpfs             474004   47972    426032   11% /run
tmpfs               5120       4      5116    1% /run/lock
tmpfs             474004       0    474004    0% /sys/fs/cgroup
/dev/mmcblk0p6     64366   19974     44392   32% /boot
tmpfs              94804       0     94804    0% /run/user/1000

Requirements

  1. Configured Linux credentials in the given device
  2. Python installed on the target host
  3. PRTG can execute PowerShell scripts. Please have a look at our guide for installing PowerShell based sensors for installation details.

Parameters

ParameterDescription
ComputerNameThe Linux host you want to connect to (can be set to %host)
UsernameThe Linux user you want to use (can be set to %linuxuser)
PasswordThe password of the above user (can be set to %linuxpassword)
CommandThe command you want to execute, including parameters. Or use the configured one (remember to base64 encode it)
IncludesOnly include these mounts. Example
@('/root','/etc')
AutoUpdateFingerPrintSet this when calling the script to automatically update the SSH fingerprints of known devices. Careful, though!

Version History

DateVersionNotes
April 12th, 20181.1- More generalistic approach
- Automated module setup
- Support for keyfiles
- Better debug output
July 23rd, 20151.0Initial Release

Script

# ___ ___ _____ ___
#| _ \ _ \_   _/ __|
#|  _/   / | || (_ |
#|_| |_|_\ |_| \___|
#    NETWORK MONITOR
#-------------------
# Description: This sensor will parse through the volumes mounted on the target device 
# Parameters:
# -Computername:    The linux host you want to connect to
# -Username         Your linux username
# -Password         Your linux password
# -Command          The line to execute on your host
# -Includes         Only include these drives if you don't want all of them. Use the exact filesystem path!
# # # # # # # # # # # # # 
# Comments:
# The comment used here is base64 encoded, since it's turning the output of df into a nice JSON object array, making it easier to evaluate the output:
# df -Ph | awk '/^\// {print $1"\t"$2"\t"$4}' | python -c 'import json, fileinput; print json.dumps({"diskarray":[dict(zip(("mount", "spacetotal", "spaceavail"), l.split())) for l in fileinput.input()]}, indent=2)'
# Note that it requires python installed on the target host. Courtesy of user "dawg" via stackoverflow (https://stackoverflow.com/a/35212442)
# # # # # # # # # # # # # # 
# Note: If the SHA1 fingerprint of the server changes, please execute it with the following parameters: 
# -ComputerName <your-host> -UserName <username> -Password <password> -command "echo PRTG needs fingerprint update..." -UpdateFingerPrint  
# ------------------
# # # # # # # # # # # # 
# Version History
 # April 12th, 2018 - more generalistic approach, automated module setup, support for keyfiles, better debug output
# July 23rd, 2015   - Initial Release
# # # # # # # # # # # # 
# (c) 2017 Stephan Linke | Paessler AG

# Parameters
param(  
    [string]$Computername      = "", 
    [string]$Username          = "", 
    [string]$Password          = "",
    [string]$keyFile           = "",
    [string]$Command           = "ZGYgLVAgfCBhd2sgJy9eXC8vIHtwcmludCAkMSJcdCIkMiJcdCIkNH0nIHwgcHl0aG9uIC1jICdpbXBvcnQganNvbiwgZmlsZWlucHV0OyBwcmludCBqc29uLmR1bXBzKHsiZGlza2FycmF5IjpbZGljdCh6aXAoKCJtb3VudCIsICJzcGFjZXRvdGFsIiwgInNwYWNlYXZhaWwiKSwgbC5zcGxpdCgpKSkgZm9yIGwgaW4gZmlsZWlucHV0LmlucHV0KCldfSwgaW5kZW50PTIpJw==",
    [string]$Includes          = @(),
    [switch]$UpdateFingerPrint = $False
)
clear
#region modules
$requiredModules = @("Posh-SSH")
#endregion 

#region configuration
$numbers = @{
    2 = "two"
    3 = "three"
    4 = "four"
    5 = "five"
    6 = "six"
    7 = "seven"
    8 = "eight"
    9 = "nine"
}
if(($requiredModules.Count -lt 10) -and ($requiredModules.Count -gt 1)){ $requiredModulesCount = $numbers[$requiredModules.Count]}
if($requiredModules.Count -gt 9) { $requiredModulesCount = $requiredModules.Count }


# channels per volume
$resultTemplate = @"
            <result>
               <channel>{0} Free</channel>
               <value>{1}</value>
               <unit>BytesDisk</unit>
               <VolumeSize>KiloByte</VolumeSize>
               <float>0</float>
            </result>
            <result>
                <channel>{0} Used</channel>
                <value>{2}</value>
                <unit>BytesDisk</unit>
                <VolumeSize>KiloByte</VolumeSize>
                <float>0</float>
            </result>
            <result>
                <channel>{0} Used Percent</channel>
                <value>{3}</value>
                <unit>Percent</unit>
            </result>
"@
#endregion

#region function library
# This will connect to the given host and execute the df command. 

function This-ShowMessage([string]$type,$message){

    Write-Host ("[{0}] " -f (Get-Date)) -NoNewline; 

    switch ($type){
        "success"       { Write-Host "    success    "  -BackgroundColor Green      -ForegroundColor White -NoNewline; }
        "information"   { Write-Host "  information  "  -BackgroundColor DarkCyan   -ForegroundColor White -NoNewline; }
        "warning"       { Write-Host "    warning    "  -BackgroundColor DarkYellow -ForegroundColor White -NoNewline; }
        "error"         { Write-Host "     error     "  -BackgroundColor DarkRed    -ForegroundColor White -NoNewline; }
        default         { Write-Host "     notes     "  -BackgroundColor DarkGray   -ForegroundColor White -NoNewline; }
    }
    
    Write-Host (" {0}{1}" -f $message,$Global:blank) 
}

function This-Setup {

        $installed = 0;
        Switch($requiredModules.Count){
            {$_ -eq 1 } { This-ShowMessage -type information -message ([string]::Format("This sensor has one dependency: {0}", $requiredModules -join ", ")) }
            {$_ -gt 1 } { This-ShowMessage -type information -message ([string]::Format("This sensor has {0} dependencies: {1}", $requiredModulesCount, $requiredModules -join ", ")) }
        }

        foreach($requiredModule in $requiredModules){
            # Check if our module loaded properly
            This-ShowMessage -type information -message "Checking for module $($requiredModule)"
            if (Get-Module -ListAvailable -Name $requiredModule) { 
                try   { Import-Module $requiredModule  -Verbose:$false; This-ShowMessage -type success -message "$($requiredModule) loaded."; $installed++}
                catch { This-ShowMessage -type error -message "There was a problem loading $($requiredModule). Details of the error:`n$($_.Exception.Message)"}
            }
            else { 
                This-ShowMessage -type information "$($requiredModule) not installed yet. Installing now..."
                try   { Install-Module $requiredModule -Force -Verbose:$false; }
                catch { This-ShowMessage -type error -message "There was a problem installing $($requiredModule). Details of the error:`n$($_.Exception.Message)"} }
        }
        

        if($installed -eq $requiredModules.Count)
        { This-ShowMessage -type success -message "All dependencies loaded."} 
        else 
        { This-ShowMessage -type error -message "At least one dependency was not met. Exiting..."; This-Exit("At least one dependency was not met. Please run the sensor manually with the same parameters and check the error log.") }
    }

function This-Exit([string]$message){
Write-Host @"
<prtg>
<error>1</error>
<text>$($message)</text>
</prtg>
"@

}

function This-GetSSHCommandOutput(){
    
    # if we don't have a keyfile, use the password
    if($keyFile.Length -eq 0){
        # Generate credentials object for authentication
        $SecPasswd   = ConvertTo-SecureString $Password -AsPlainText -Force
        $Credentials = New-Object System.Management.Automation.PSCredential ($Username, $secpasswd)
    }
    # If AutoUpdateFingerprint is enabled, the script will always remove the fingerprint saved for the host.
    # It's recommended to set it to false and only call the script manually with 
    # -ComputerName <your-host> -UserName <username> -Password <password> -command "echo PRTG needs fingerprint update..." -UpdateFingerPrint
    if($UpdateFingerprint){ Remove-SSHTrustedHost $Computername }

    # Create new session and execute the command given
    if($keyFile.Length -ne 0){ 
        This-ShowMessage -type information -message "Using keyfile ($($keyFile))."; 
        $SessionId = (New-SSHSession -Computername $Computername -Acceptkey -KeyFile $keyFile).SessionId 
    }
    else { 
        This-ShowMessage -type information -message "Using username/password."; 
        $SessionId = (New-SSHSession -Computername $Computername -Credential $Credentials -Acceptkey).SessionId }
    
    # store output of the above command
    $Output    = (Invoke-SSHCommand -SSHSession $SshSessions[$SessionId] -Command ( [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Command))))
    
    # disconnect the host 
    $SshSessions[$SessionId].Disconnect();
    
    # remove from the session list
    Remove-SSHSession($SessionId)

    return ($Output.Output | ConvertFrom-Json)

}

# This will retrieve the volume table and output it into the proper XML format
function This-EvaluteCommandResult(){

    $Volumes = (This-GetSSHCommandOutput).diskarray
    
    This-ShowMessage information "Found $($Volumes.Count) volumes on $($Computername)."

    Foreach ($Volume in $Volumes){
        try{ 
           # $Bytes        = [System.Math]::Round(($Volume.spacetotal / $Multiplicator),2)
           # $FreeBytes    = [System.Math]::Round(($Volume.spaceavail / $Multiplicator),2)
            $Bytes     = [int32]$Volume.spacetotal * 1024
            $FreeBytes = [int32]$Volume.spaceavail * 1024
           
            $UsedBytes    = [System.Math]::Round(($Bytes - $FreeBytes),2)
            $FreePercent  = [System.Math]::Round(100-(($Volume.spaceavail / $Volume.spacetotal)*100),0)
            $Volume | Add-Member "FreeReadable" $FreeBytes
            $Volume | Add-Member "SizeReadable" $Bytes
            $Volume | Add-Member "UsedReadable" $UsedBytes
            $Volume | Add-Member "FreePercent" $FreePercent
        } catch{ Write-Host "Failed." }
    }

    # output the XML structure according to the includes list (or output everything, in case it's empty)
    Write-Host "<?xml version='1.0' encoding='UTF-8' ?><prtg>";
    Foreach ($Volume in $Volumes){
        # check the include list
        if($Includes.Length -eq 0){
            $placeholders = @($Volume.mount, $Volume.FreeReadable, $Volume.UsedReadable, $Volume.FreePercent)
            Write-Host ([string]::Format($resultTemplate, ($placeholders -replace ",",".")))
        }
        else{
            if($Includes.Contains($volume.mount)){
                $placeholders = @($Volume.mount, $Volume.FreeReadable, $Volume.UsedReadable, $Volume.FreePercent)
                Write-Host ([string]::Format($resultTemplate, ($placeholders -replace ",",".")))
            }            
        }
    } 
    Write-Host "</prtg>";
}

This-Setup 
This-EvaluteCommandResult

The script is provided as is and may or may not work with your installation. If you need any further customizations for your environment, feel free to implement them. If you encounter any bugs, feel free to share them :)

df disk-metrics embedded linux ssh

Created on Nov 2, 2016 11:35:21 AM by  Stephan Linke [Paessler Support]

Last change on Apr 12, 2018 1:12:06 PM by  Stephan Linke [Paessler Support]



3 Replies

Votes:

0

As far as i understand with script not intended for SAN devices, only for Linux based PCs?

Created on Nov 29, 2018 12:30:47 PM



Votes:

0

That is correct, yes.


PRTG Scheduler | PRTGapi | Feature Requests | WMI Issues | SNMP Issues

Kind regards,
Stephan Linke, Tech Support Team

Created on Nov 29, 2018 1:04:47 PM by  Stephan Linke [Paessler Support]



Votes:

0

Hier eine Version für AIX, welche auch ohne Python funktioniert:

# ___ ___ _____ ___
#| _ \ _ \_   _/ __|
#|  _/   / | || (_ |
#|_| |_|_\ |_| \___|
#    NETWORK MONITOR
#-------------------
# Description: This sensor will parse through the volumes mounted on the target device 
# Parameters:
# -Computername:    The linux host you want to connect to
# -Username         Your linux username
# -Password         Your linux password
# -Command          The line to execute on your host
# -Includes         Only include these drives if you don't want all of them. Use the exact filesystem path!
# # # # # # # # # # # # # 
# Comments:
# The comment used here is base64 encoded, since it's turning the output of df into a nice JSON object array, making it easier to evaluate the output:
# df -Ph | awk '/^\// {print $1"\t"$2"\t"$4}' | python -c 'import json, fileinput; print json.dumps({"diskarray":[dict(zip(("mount", "spacetotal", "spaceavail"), l.split())) for l in fileinput.input()]}, indent=2)'
# Note that it requires python installed on the target host. Courtesy of user "dawg" via stackoverflow (https://stackoverflow.com/a/35212442)
# # # # # # # # # # # # # # 
# Note: If the SHA1 fingerprint of the server changes, please execute it with the following parameters: 
# -ComputerName <your-host> -UserName <username> -Password <password> -command "echo PRTG needs fingerprint update..." -UpdateFingerPrint  
# ------------------
# # # # # # # # # # # # 
# Version History
# Changes for AIX without Python
# April 12th, 2018 - more generalistic approach, automated module setup, support for keyfiles, better debug output
# July 23rd, 2015   - Initial Release
# # # # # # # # # # # # 
# (c) 2017 Stephan Linke | Paessler AG

# Parameters
param(  
    [string]$Computername      = "", 
    [string]$Username          = "", 
    [string]$Password          = "",
    [string]$keyFile           = "",
    [string]$Command           = "ZGYgLVAgLWM=",
    [string]$Command2           = "df -P -c",
    [string]$Includes          = @(),
    [switch]$UpdateFingerPrint = $False
)
clear
#region modules
$requiredModules = @("Posh-SSH")
#endregion 

#region configuration
$numbers = @{
    2 = "two"
    3 = "three"
    4 = "four"
    5 = "five"
    6 = "six"
    7 = "seven"
    8 = "eight"
    9 = "nine"
}
if(($requiredModules.Count -lt 10) -and ($requiredModules.Count -gt 1)){ $requiredModulesCount = $numbers[$requiredModules.Count]}
if($requiredModules.Count -gt 9) { $requiredModulesCount = $requiredModules.Count }


# channels per volume
$resultTemplate = @"
            <result>
               <channel>{0} Free</channel>
               <value>{1}</value>
               <unit>BytesDisk</unit>
               <VolumeSize>KiloByte</VolumeSize>
               <float>0</float>
            </result>
            <result>
                <channel>{0} Used</channel>
                <value>{2}</value>
                <unit>BytesDisk</unit>
                <VolumeSize>KiloByte</VolumeSize>
                <float>0</float>
            </result>
            <result>
                <channel>{0} Used Percent</channel>
                <value>{3}</value>
                <unit>Percent</unit>
            </result>
"@
#endregion

#region function library
# This will connect to the given host and execute the df command. 

function This-ShowMessage([string]$type,$message){

    Write-Host ("[{0}] " -f (Get-Date)) -NoNewline; 

    switch ($type){
        "success"       { Write-Host "    success    "  -BackgroundColor Green      -ForegroundColor White -NoNewline; }
        "information"   { Write-Host "  information  "  -BackgroundColor DarkCyan   -ForegroundColor White -NoNewline; }
        "warning"       { Write-Host "    warning    "  -BackgroundColor DarkYellow -ForegroundColor White -NoNewline; }
        "error"         { Write-Host "     error     "  -BackgroundColor DarkRed    -ForegroundColor White -NoNewline; }
        default         { Write-Host "     notes     "  -BackgroundColor DarkGray   -ForegroundColor White -NoNewline; }
    }
    
    Write-Host (" {0}{1}" -f $message,$Global:blank) 
}

function This-Setup {

        $installed = 0;
        Switch($requiredModules.Count){
            {$_ -eq 1 } { This-ShowMessage -type information -message ([string]::Format("This sensor has one dependency: {0}", $requiredModules -join ", ")) }
            {$_ -gt 1 } { This-ShowMessage -type information -message ([string]::Format("This sensor has {0} dependencies: {1}", $requiredModulesCount, $requiredModules -join ", ")) }
        }

        foreach($requiredModule in $requiredModules){
            # Check if our module loaded properly
            This-ShowMessage -type information -message "Checking for module $($requiredModule)"
            if (Get-Module -ListAvailable -Name $requiredModule) { 
                try   { Import-Module $requiredModule  -Verbose:$false; This-ShowMessage -type success -message "$($requiredModule) loaded."; $installed++}
                catch { This-ShowMessage -type error -message "There was a problem loading $($requiredModule). Details of the error:`n$($_.Exception.Message)"}
            }
            else { 
                This-ShowMessage -type information "$($requiredModule) not installed yet. Installing now..."                
                try   { Install-Module $requiredModule -Force -Verbose:$false; }
                catch { This-ShowMessage -type error -message "There was a problem installing $($requiredModule). Details of the error:`n$($_.Exception.Message)"} }
        }
        

        if($installed -eq $requiredModules.Count)
        { This-ShowMessage -type success -message "All dependencies loaded."} 
        else 
        { This-ShowMessage -type error -message "At least one dependency was not met. Exiting..."; This-Exit("At least one dependency was not met. Please run the sensor manually with the same parameters and check the error log.") }
    }

function This-Exit([string]$message){
Write-Host @"
<prtg>
<error>1</error>
<text>$($message)</text>
</prtg>
"@

}

function This-GetSSHCommandOutput(){
    
    # if we don't have a keyfile, use the password
    if($keyFile.Length -eq 0){
        # Generate credentials object for authentication
        $SecPasswd   = ConvertTo-SecureString $Password -AsPlainText -Force
        $Credentials = New-Object System.Management.Automation.PSCredential ($Username, $secpasswd)
    }
    # If AutoUpdateFingerprint is enabled, the script will always remove the fingerprint saved for the host.
    # It's recommended to set it to false and only call the script manually with 
    # -ComputerName <your-host> -UserName <username> -Password <password> -command "echo PRTG needs fingerprint update..." -UpdateFingerPrint
    if($UpdateFingerprint){ Remove-SSHTrustedHost $Computername }

    # Create new session and execute the command given
    if($keyFile.Length -ne 0){ 
        This-ShowMessage -type information -message "Using keyfile ($($keyFile))."; 
        $SessionId = (New-SSHSession -Computername $Computername -Acceptkey -KeyFile $keyFile).SessionId 
    }
    else { 
        This-ShowMessage -type information -message "Using username/password."; 
        $SessionId = (New-SSHSession -Computername $Computername -Credential $Credentials -Acceptkey).SessionId }
    
    # store output of the above command
    $tmp_result    = $(Invoke-SSHCommand -SSHSession $SshSessions[$SessionId] -Command "df -P -c").Output
    
    # disconnect the host 
    $SshSessions[$SessionId].Disconnect();
    
    # remove from the session list
    Remove-SSHSession($SessionId)

    $tmp_result = $tmp_result -replace "512-blocks", "Blocks"
    $tmp_result = $tmp_result -replace "Mounted on", "mount"
    $tmp_result = $tmp_result -replace "%", ""
    
    $tmp_result | Set-Content -Path "output.txt"

    $Output = import-csv -Delimiter ":" "output.txt"

    $Output | Set-Content -Path "output.json"
    
    return ($Output)

}

# This will retrieve the volume table and output it into the proper XML format
function This-EvaluteCommandResult(){

    #$Volumes = (This-GetSSHCommandOutput).diskarray
    $Volumes = (This-GetSSHCommandOutput)
    
    This-ShowMessage information "Found $($Volumes.Count) volumes on $($Computername)."

    Foreach ($Volume in $Volumes){
        try{ 
  
            $Bytes     = [int32]$Volume.Blocks * 1024
            $FreeBytes = [int32]$Volume.Available * 1024
           
            $UsedBytes    = [int32]$Volume.Used * 1024
            $FreePercent  = $Volume.Capacity
            $Volume | Add-Member "FreeReadable" $FreeBytes
            $Volume | Add-Member "SizeReadable" $Bytes
            $Volume | Add-Member "UsedReadable" $UsedBytes
            $Volume | Add-Member "FreePercent" $FreePercent

        } catch{ 
		 Write-Host "Failed" 
	}
    }

    $Volumes = $Volumes | ? {$_.FreePercent -ne ""}

    # output the XML structure according to the includes list (or output everything, in case it's empty)

    
    Foreach ($Volume in $Volumes){
        # check the include list
        if($Includes.Length -eq 0){
            $placeholders = @($Volume.mount, $Volume.FreeReadable, $Volume.UsedReadable, $Volume.FreePercent)
	    $template_tmp = $template_tmp + ([string]::Format($resultTemplate, ($placeholders -replace ",","."))) 
            
        }
        else{
            if($Includes.Contains($volume.mount)){
                $placeholders = @($Volume.mount, $Volume.FreeReadable, $Volume.UsedReadable, $Volume.FreePercent)
                 $template_tmp = $template_tmp +  ([string]::Format($resultTemplate, ($placeholders -replace ",",".")))
            }            
        }
    } 
     Write-Host "<?xml version='1.0' encoding='UTF-8' ?><prtg>"
     Write-Host $template_tmp
     Write-Host "</prtg>"

}


Get-PackageProvider NuGet -ForceBootstrap
This-Setup
This-EvaluteCommandResult

Created on Jan 31, 2019 11:13:42 AM

Last change on Jan 31, 2019 12:35:57 PM by  Stephan Linke [Paessler Support]




Disclaimer: The information in the Paessler Knowledge Base comes without warranty of any kind. Use at your own risk. Before applying any instructions please exercise proper system administrator housekeeping. You must make sure that a proper backup of all your data is available.