Как обращаться к SNMP серверу используя протокол через Powershell


25 февраля 2023


Используем Powershell с протоколом SNMP для запросов к устройству

Протокол SNMP (Simple Network Management Protocol) используется для удаленного управления и мониторинга сетевых устройств. Он часто реализован в сетевом оборудовании и принтерах. С помощью этого протокола, например, мы можем получать данные по загруженности канала, температуре устройства, состоянии картриджей и т.д. В этой статье будет рассмотрено как можно получить эти данные используя протокол SNMP в Powershell.

 

Как работать с SNMP в Powershell

В Windows есть базовая реализация протокола в следующем виде:

  1. SNMP сервер. В новых редакциях Windows он скрыт из списков для установки. Это может быть связано либо с тем, что он работает на WIM (а не CIM) и/или из-за того что он работает на SNMPv2;
  2. Модуль OlePrn.OleSNMP, который предназначен только для работы с ISNMP и версией SNMPv1.

Это не те варианты, которые можно использовать для подключения к устройствам.

Основные версии протокола SNMP, которые настраиваются на оборудовании, следующие:

  • v2 - не имеет шифрования и аутентификация посредственная. Аутентификация происходит по логину (называется "community string"), которая определит права. По умолчанию, на большинстве устройств и программ, community string равен 'public'.
  • v3 - имеет более серьезную аутентификацию и шифрование. Не поддерживает 'community string', как в предыдущем варианте.

Так как у Microsoft нет штатной поддержки модуля SNMP для Powershell в статье будут использоваться сторонняя реализация. Самый популярный такой модуль, написан на .NET - Lextm.SharpSnmpLib. Он поддерживает все версии SNMP. Есть так же отдельные модули, которые написаны на Powershell, но они так же используют Lextm.SharpSnmpLib.

В статье будет рассмотрен модуль .NET и Powershell. Опишу основные минусы и плюсы, что бы вы определились что больше подходит для вас:

  • Сторонние модули, которые пишутся на Powershell, редко обновляются. Т.е. если разработчик использовал сторонние модули (как в нашем случае), они могли обновится множество раз, тем самым расширив функционал или решив какие-то ошибки.
  • Модуль на .NET сложнее использовать. Это займет больше времени, чем с Powershell.
  • Разработчики Powershell реализуют только базовый функционал доступный в модуле .NET. Например, в Powershell, нет модулей поддерживающих v2 и v3 версию одновременно.

 

Модуль Powershell для работы с SNMP v2

Устанавливается модуль через репозиторий PowerShell Gallery.

Install-Module -Name SNMP

Если у вас есть проблемы с установкой, то вы можете скачать модуль со страницы PowerShell Gallery и распаковать архиватором.

У модуля есть следующие команды:

  • Get-SnmpData - получение данных по конкретному OID;
  • Invoke-SnmpWalk - если нужно пройтись по дереву OID;
  • Set-SnmpData - изменение данных на удаленном устройстве;

Многие программы позволяют не указывать OID при использовании процесса 'walk'. В случае этого модуля OID указывать нужно.

Пример работы команды:

Invoke-SnmpWalk -IP "192.168.2.140" -OID "1.3.6.1.2.1.1"

Получение поддерева значений SNMP v2 через walk в Powershell

У команд есть параметры 'Community', со значением по умолчанию 'Public' и 'UDPport', который по умолчанию равен 161.

Пример, где мы получаем значение по конкретному OID:

Get-SnmpData -IP "192.168.2.140" -OID "1.3.6.1.2.1.1.4.0"

(Get-SnmpData -IP "192.168.2.140" -OID "1.3.6.1.2.1.1.4.0").Data

Получение конкретного значения SNMP v2 в Powershell

 

Модуль Powershell с поддержкой SNMP v3

Модуль так же устанавливается через PowerShell Gallery.

Install-Module -Name SNMPv3

Либо вы можете его скачать по ссылке с репозитория.

У модуля так же есть 3 команды:

  • Invoke-SNMPv3Get - получение данных по одному OID;
  • Invoke-SNMPv3Set - изменение данных;
  • Invoke-SNMPv3Walk - обход по дереву OID.

Основное отличие версии 2 от 3 в аутентификации и шифровании. Изначальная настройка аутентификации и шифрования выполняется на сервере (устройстве). Модуль поддерживает следующие параметры:

  • UserName - имя пользователя. Единственный обязательный параметр;
  • AuthSecert - пароль;
  • AuthType - алгоритм хэширования пароля. Доступные значения: MD5, SHA1, SHA256, SHA384, SHA512, None (по умолчанию);
  • PrivSecret - пароль для шифрования;
  • PrivType - алгоритм шифрования. Доступные значения: AES128, AES192, AES256,DES,TripleDES,None (по умолчанию).

В примере ниже будет использоваться шифрование AES128 и хэширование MD5. Если вы создали другие учетные данные - используйте их. Пример прохода по дереву.

Invoke-SNMPv3Walk -UserName 'privUser' -Target '192.168.2.140' -AuthSecret 'AuthPassword' -PrivSecret 'CryptoPassword' -OID '1.3.6.1.2.1.1' -AuthType 'MD5' -PrivType AES128

Получение поддерева значения SNMP v3 через walk в Powershell

Получение одного значения.

Invoke-SNMPv3Get -UserName 'privUser' -Target '192.168.2.140' -AuthSecret 'AuthPassword' -PrivSecret 'CryptoPassword' -OID '1.3.6.1.2.1.1.6.0' -AuthType 'MD5' -PrivType AES128

Получение конкретного значения SNMP v3 в Powershell

Если вы захотите изменить данные, то это можно сделать так:

Invoke-SNMPv3Set -UserName 'privUser' -Target '192.168.2.140' -AuthSecret 'AuthPassword' -PrivSecret 'CryptoPassword' -OID '1.3.6.1.2.1.1.9.1.3.1' -AuthType 'MD5' -PrivType AES128 -Value 'TestValue' -Type String
 

 

Использование модуля Lextm.SharpSnmpLib

Использовать модуль .NET можно несколькими способами. Установка выполняется через репозиторий NuGet. Вы можете установить или скачать его со страницы https://www.nuget.org/packages/Lextm.SharpSnmpLib/ . В примере ниже я скачал модуль с расширением 'nupkg'  и разархивировал его.

В каталоге, который появится после разархивации, будет другой каталог с названием 'lib'. В зависимости от вашей версии .NET вам нужно будет сделать дальнейший выбор. В моем случае это путь 'lextm.sharpsnmplib.12.5.1\lib\net471\SharpSnmpLib.dll'.

dll файл импортируется в сессию Powershell следующим образом.

Add-Type -LiteralPath "G:\lextm.sharpsnmplib.12.5.1\lib\net471\SharpSnmpLib.dll"

Вне зависимости от того, какую версию SNMP вы будете реализовывать, у них будут одинаковые переменные.

# Порт SNMP
[int]$UDPport = 161
# дерево или конечный OID
[string[]]$OID = '1.3.6.1.2.1.1.4.0'
# создаем массив из объектов с OID
$variableList = New-Object Collections.Generic.List[Lextm.SharpSnmpLib.Variable]
$variableList.Add([Lextm.SharpSnmpLib.Variable]::new([Lextm.SharpSnmpLib.ObjectIdentifier]::new($OID)))
# время, которое будем ожидать ответ
[int]$TimeOut = 3000
# IP адрес SNMP сервера и создание объекта
[Net.IPAddress]$IP = '192.168.2.140'
$endpoint = New-Object Net.IpEndPoint $IP, $UDPport

v2

Для версии v2 мы так же должны указать 'Community string'. По умолчанию, на большинстве устройств, используется 'public'.

[string]$Community = 'public'
# версия SNMP
[Lextm.SharpSnmpLib.VersionCode]$Version = 'V2'

Используя созданные переменные, получим данные конкретного OID.

# получение данных
$message = [Lextm.SharpSnmpLib.Messaging.Messenger]::Get(
    $Version,
    $endpoint,
    $Community,
    $variableList,
    $TimeOut
)
# преобразуем значение в строку
$message.Data.ToString()

Обращение к SNMP v2 через Lextm.SharpSnmpLib в Powershell

Для обхода по дереву используется метод 'Walk'. Он не может работать с массивом из 'OID', поэтому нужно переопределить переменную. Результат работы метода записывается в переменную $results. 

# дерево или конечный OID
[Lextm.SharpSnmpLib.ObjectIdentifier]$OID = '1.3.6.1.2.1.1'
# режим обхода по дереву
$WalkMode = [Lextm.SharpSnmpLib.Messaging.WalkMode]::WithinSubtree
# куда будет записан результат работы команды
$results = New-Object Collections.Generic.List[Lextm.SharpSnmpLib.Variable]
$message = [Lextm.SharpSnmpLib.Messaging.Messenger]::Walk(
  $Version,
  $endpoint,
  $Community,
  $OID,
  $results,
  $TimeOut,
  $WalkMode
)

$results

Обращение к SNMP v2 через Lextm.SharpSnmpLib в Powershell c получение поддерева OID

Что бы каждое значение приняло понятный вид - его нужно перекодировать. Пример того, как это можно сделать.

$results2 = @()
foreach ($d in $results){$results2 +=[PSCustomObject]@{'ID'=$d.id.ToString();'Data'=$d.Data.ToString()}}
$results2

Преобразование закодированной строки в Powershell

v3

Для третей версии мы должны создать следующие переменные.

# версия SNMP
[Lextm.SharpSnmpLib.VersionCode]$Version = 'V3'
# пользователь
[String]$UserName = 'privUser'
# пароль для аутентификации
[Lextm.SharpSnmpLib.OctetString]$AuthSecret = 'AuthPassword'
# пароль для шифрования и расшифрования
[Lextm.SharpSnmpLib.OctetString]$PrivSecret = 'CryptoPassword'

Что бы  передать эти данные - мы должны зашифровать их специальным образом. Это так же делается через методы. В примере ниже мы используем 'MD5' и 'AES128'. Кроме этих методов так же доступны другие.

# Кроме MD5 может быть пустым/SHA1/SHA256/SHA384/SHA512
$Authentication = [Lextm.SharpSnmpLib.Security.MD5AuthenticationProvider]::new($AuthSecret)
# Кроме AES128 так же можно использовать DES/TripleDES/AES192/AES256
$Privacy = [Lextm.SharpSnmpLib.Security.AESPrivacyProvider]::new($PrivSecret, $Authentication)

# V3 требует обмена данными перед запросом согласно RFC
$Discovery = [Lextm.SharpSnmpLib.Messaging.Messenger]::GetNextDiscovery([Lextm.SharpSnmpLib.SnmpType]::GetRequestPdu)
$Report = $Discovery.GetResponse($Timeout, $endpoint)
$Context = if ([String]::IsNullOrWhiteSpace($Context)) {[String]::Empty} else {$Context}

Выполняем запрос и получаем зашифрованные данные.

$Request = [Lextm.SharpSnmpLib.Messaging.GetRequestMessage]::new(
    $Version,
    [Lextm.SharpSnmpLib.Messaging.Messenger]::NextMessageId,
    [Lextm.SharpSnmpLib.Messaging.Messenger]::NextRequestId,
    [Lextm.SharpSnmpLib.OctetString]::new($UserName),
    [Lextm.SharpSnmpLib.OctetString]::new($Context),
    $variableList,
    $Privacy,
    [Lextm.SharpSnmpLib.Messaging.Messenger]::MaxMessageSize,
    $Report
)
$Reply = [Lextm.SharpSnmpLib.Messaging.SnmpMessageExtension]::GetResponse($Request, $Timeout, $endpoint)
$Reply.Scope.Pdu.Variables

Обращение к SNMP v3 через Lextm.SharpSnmpLib в Powershell

Для обхода по дереву мы должны изменить переменную $Discovery и создать переменную, которая будет хранить результат работы. 

$Discovery = [Lextm.SharpSnmpLib.Messaging.Messenger]::GetNextDiscovery([Lextm.SharpSnmpLib.SnmpType]::GetBulkRequestPdu)
$Report = $Discovery.GetResponse($Timeout, $endpoint)
[Lextm.SharpSnmpLib.ObjectIdentifier]$OID = '1.3.6.1.2.1.1'
$Result = [System.Collections.Generic.List[Lextm.SharpSnmpLib.Variable]]::new()
[Lextm.SharpSnmpLib.Messaging.Messenger]::BulkWalk(
        $Version,
        $endpoint,
        [Lextm.SharpSnmpLib.OctetString]::new($UserName),
        [Lextm.SharpSnmpLib.OctetString]::new($Context),
        $OID,
        $Result,
        $Timeout,
        10,
        [Lextm.SharpSnmpLib.Messaging.WalkMode]::WithinSubtree,
        $Privacy,
        $Report
    ) | Out-Null

$Result

Обращение к SNMP v3 через Lextm.SharpSnmpLib в Powershell с поддеревом OID

...

Теги: #powershell #snmp


Каналы
Telegram FixMyPc Telegram Лента FixMyPC RSS Rss
Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, приобретённого опыта и лучшие практики в системном администрировании и программировании.