Протокол SNMP (Simple Network Management Protocol) используется для удаленного управления и мониторинга сетевых устройств. Он часто реализован в сетевом оборудовании и принтерах. С помощью этого протокола, например, мы можем получать данные по загруженности канала, температуре устройства, состоянии картриджей и т.д. В этой статье будет рассмотрено как можно получить эти данные используя протокол SNMP в Powershell.
Как работать с SNMP в Powershell
В Windows есть базовая реализация протокола в следующем виде:
- SNMP сервер. В новых редакциях Windows он скрыт из списков для установки. Это может быть связано либо с тем, что он работает на WIM (а не CIM) и/или из-за того что он работает на SNMPv2;
- Модуль 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"
У команд есть параметры '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
Модуль 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
Получение одного значения.
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
Если вы захотите изменить данные, то это можно сделать так:
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()
Для обхода по дереву используется метод '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
Что бы каждое значение приняло понятный вид - его нужно перекодировать. Пример того, как это можно сделать.
$results2 = @()
foreach ($d in $results){$results2 +=[PSCustomObject]@{'ID'=$d.id.ToString();'Data'=$d.Data.ToString()}}
$results2
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
Для обхода по дереву мы должны изменить переменную $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
...
Подписывайтесь на наш Telegram канал
Теги: #powershell #snmp