mercredi 21 mars 2018

Powershell et SNMP

Pour récupérer des informations SNMP avec Windows Powershell, j'utilise dans cet article SharpSnmpLib.dll. L'exemple proposé ici montre en particulier comment utiliser les commandes SnmpWalker et SnmpGet avec Windows Powershell.

Principe général du protocole SNMP


Le SNMP est un protocole client serveur utilisé pour transmettre l'état des services et applications d'un serveurs vers une console de surveillance. Le protocole SNMP se divise en deux principes de communication. Le mode Pull à l'initiative du client et le mode Push, à l'initiative du serveur. Dans le mode Pull le client va lire les informations mis à disposition par le serveur (snmpwalk, snmpget). Dans le mode Push, le client va écouté les informations envoyé par le serveur (snmptrap, snmptrapd).

Référence


J'ai testé un article très intéressant sur la façon de récupérer des informations SNMP en PowerShell. Si vous maitrisez un minimum l'anglais, je vous invite à le lire l'article en référence. Vous trouverez le lien du site ci-dessous. Par contre j'ai eu un peu de mal à récupérer le fichier "SharpSnmpLib.dll". Je vais donc ajouter un lien avec la source. L'exemple que je vous propose aujourd'hui est une donc une version légèrement remanier en français.

Site de référence : https://vwiki.co.uk/SNMP_and_PowerShell
Télécharger la Dll : SharpSnmpLib.dll

Exemple


Dans cet exemple j'utilise le mode SNMP Pull pour lire les information mis à disposition sur un système distant. Pour cet exemple, il faut créer un dossier "lib" au même niveau que le script, et y décompresser l'archive téléchargée ci-dessus.


 
############################################################
# Snmp : SharpSnmpLib v7.6
# Powershell : Version 2.0
############################################################

#Chemin courant.
$curpath = ""
if ($psISE) { $curpath = split-path -parent $psISE.CurrentFile.Fullpath }
else        { $curpath = Split-Path $MyInvocation.MyCommand.Path  }

#Chargement des librairies.
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Try   { [void][Reflection.Assembly]::LoadFile($curpath+"\lib\SharpSnmpLib.dll") }
Catch { write-host "SharpSnmpLib.dll manquant.";Return }

############################################################
# Fonctions SNMP
############################################################

#Fonction - Créer un type générique.
function Snmp-GenericObject ([string]$typeName,[string[]]$typeParams,[object[]]$constructorParams)
 {
   #Créer le nom du type générique.
   $genericTypeName = $typeName + "``" + $typeParams.Count
   $genericType = [Type] $genericTypeName
   if (!$genericType) { throw "Impossible de trouver le type générique $genericTypeName" }

   #Lier les parametres de type à celui-ci.
   [type[]] $typedParams = $typeParams
   $closedType = $genericType.MakeGenericType($typedParams)
   if (!$closedType) { throw "Impossible de finaliser le type $genericType" }

   #Créer la version final du type générique.
   ,[Activator]::CreateInstance($closedType, $constructorParams)
}

#Fonction - SnmpWalker.
function Snmp-Walker ([string]$sIP, $sOIDstart, [string]$Community = "public", [int]$UDPport = 161, [int]$TimeOut=3000)
 {
   #$TimeOut est en msec, 0 ou -1 pour infini.
   #Créer un objet OID.
   $oid = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($sOIDstart)
   
   #Créer la liste pour les résultats (compatible powershell v2).
   $results = Snmp-GenericObject System.Collections.Generic.List Lextm.SharpSnmpLib.Variable
   
   #Créer un point de terminaison pour le serveur SNMP.
   $ip = [System.Net.IPAddress]::Parse($sIP)
   $svr = New-Object System.Net.IpEndPoint ($ip, 161)

   #Utiliser SNMP v2 avec le mode "WithinSubTree".
   $ver = [Lextm.SharpSnmpLib.VersionCode]::V2
   $walkMode = [Lextm.SharpSnmpLib.Messaging.WalkMode]::WithinSubtree

   #Lancer le requête SNMP.
   Try   { $null = [Lextm.SharpSnmpLib.Messaging.Messenger]::Walk($ver, $svr, $Community, $oid, $results, $TimeOut, $walkMode) }
   Catch { Write-Host "Erreur SNMP : $_"; Return }

   #Dans cet exemple j'ai changé le format de sortie pour un tableau d'objet.
   $rtn = @()
   foreach ($var in $results)
    {
      $obj = New-Object System.Object
      $obj | Add-Member -type NoteProperty -name OID  -Value ([string]$var.Id)
      $obj | Add-Member -type NoteProperty -name Data -Value ([string]$var.Data)
      $rtn += $obj
    }
   #Résultats.
   $rtn
 }

#Fonction - GetSnmp.
function Snmp-Get ([string]$sIP, $sOIDs, [string]$Community = "public", [int]$UDPport = 161, [int]$TimeOut=3000)
 {
   #$TimeOut est en msec, 0 ou -1 pour infini.
   #Créer une liste de variables OID (compatible powershell v2).
   $vList = Snmp-GenericObject System.Collections.Generic.List Lextm.SharpSnmpLib.Variable
   foreach ($sOID in $sOIDs)
    {
      $oid = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($sOID)
      $vList.Add($oid)
    }
   
   #Créer un point de terminaison pour le serveur SNMP.
   $ip = [System.Net.IPAddress]::Parse($sIP)
   $svr = New-Object System.Net.IpEndPoint ($ip, 161)
   
   #Utiliser SNMP v2.<
   $ver = [Lextm.SharpSnmpLib.VersionCode]::V2
   
   #Lancer le requête SNMP.
   Try   { $msg = [Lextm.SharpSnmpLib.Messaging.Messenger]::Get($ver, $svr, $Community, $vList, $TimeOut) }
   Catch { Write-Host "SNMP Get error: $_"; Return }

   #Dans cet exemple j'ai changé le format de sortie pour un tableau d'objet.   
   $rtn = @()
   foreach ($var in $msg)
    {
      $obj = New-Object System.Object
      $obj | Add-Member -type NoteProperty -name OID  -Value ([string]$var.Id)
      $obj | Add-Member -type NoteProperty -name Data -Value ([string]$var.Data)
      $rtn += $obj
    }
   #Résultats.
   $rtn
 }

############################################################
# Zone de test.
#
# Usage :
# Snmp-Walker IP OIDSTART [Community] [Port] [Timeout]
# Snmp-Get    IP OID      [Community] [Port] [Timeout]
############################################################

#Snmp Walker.
#Remplacer l'adresse ip par une adresse valide.
Snmp-Walker "127.0.0.1" ".1.3.6.1.2.1" | Out-String
Snmp-Walker "127.0.0.1" ".1.3.6.1.2.1" | Out-GridView

#Snmp Get.
#Remplacer l'adresse ip par une adresse valide.
Snmp-Get "127.0.0.1" ".1.3.6.1.2.1.1.5.0" | Out-String
Snmp-Get "127.0.0.1" ".1.3.6.1.2.1.1.5.0" | Out-GridView

#Fin.