SNMP and PowerShell

From vwiki
Revision as of 23:31, 19 November 2012 by Sstrutt (talk | contribs) (→‎Overview: Added Win2008 needs .NET 3.5 note)
Jump to navigation Jump to search

Overview

This page covers using PowerShell as an SNMP client, so that you can poll/probe/interrogate SNMP servers (be they servers, network devices, UPS's, etc).

All of the scripts below utilises the #SNMP (SharpSNMP) Suite for .NET/Mono. Its an open source SNMP library that supports .NET 3.5 and 4.0, which means that you can use it with PowerShell. The library has a wide range of functionality and the scripts below just cover what I consider to be the core of what you might want to do with PowerShell.

You don't need to use /n's NetCmdlets, or run the Net-SNMP executables, as other examples on the web do.

In order to make the library available for PowerShell to use...

  1. Download the latest BigDipper binary from http://sharpsnmplib.codeplex.com/releases/view/78947 and extract
  2. Copy the SharpSnmpLib.dll file to somewhere you can find it
    • EG in a folder /lib/LexTmSharpSNMP/ under where you run your scripts from

Windows 2008 Server doesn't have .NET 3.5 or 4 installed by default, therefore it needs to be installed. To do so...

  1. Go into Server Manager | Roles
  2. Select Add roles to start the wizard
  3. Select/tick the Application Server role, and then Add required feature
  4. Complete the wizard

You can then load the assembly into your PowerShell session by something like...

[reflection.assembly]::LoadFrom( (Resolve-Path ".\lib\LexTmSharpSNMP\SharpSnmpLib.dll") )

All of the scripts below use SNMP v2, which is a bit more efficient than v1. Though note that it is not secure, data (including community strings) are passed across the network unencrypted - if you need to be secure, you need to use SNMP v3 (which isn't covered below - sorry).

Generic Objects

In order to use the library you need to be able to create generic objects, which doesn't work in PowerShell v1. Its meant to be fixed in v2, but I've not got it to work (probably because I don't actually understand what they are really. So I've used this workaround by Lee Holmes.

The function below is Lee Holmes' work wrapped into a function...

function New-GenericObject {
    # Creates an object of a generic type - see http://www.leeholmes.com/blog/2006/08/18/creating-generic-types-in-powershell/

    param(
        [string] $typeName = $(throw Please specify a generic type name),
        [string[]] $typeParameters = $(throw Please specify the type parameters),
        [object[]] $constructorParameters
        )

    ## Create the generic type name
    $genericTypeName = $typeName + ` + $typeParameters.Count
    $genericType = [Type] $genericTypeName

    if(-not $genericType)
        {
        throw Could not find generic type $genericTypeName
        }

    ## Bind the type arguments to it
    [type[]] $typedParameters = $typeParameters
    $closedType = $genericType.MakeGenericType($typedParameters)
    if(-not $closedType)
        {
        throw Could not make closed type $genericType
        }

    ## Create the closed version of the generic type
    ,[Activator]::CreateInstance($closedType, $constructorParameters)
}

SNMP Get

The basic polling and probing method in SNMP.

function Invoke-SNMPget ([string]$sIP, $sOIDs, [string]$Community = "public", [int]$UDPport = 161, [int]$TimeOut=3000) {
    # $OIDs can be a single OID string, or an array of OID strings
    # $TimeOut is in msec, 0 or -1 for infinite

    # Create OID variable list
    $vList = New-GenericObject System.Collections.Generic.List Lextm.SharpSnmpLib.Variable
    foreach ($sOID in $sOIDs) {
        $oid = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($sOID)
        $vList.Add($oid)
    }
    
    # Create endpoint for SNMP server
    $ip = [System.Net.IPAddress]::Parse($sIP)
    $svr = New-Object System.Net.IpEndPoint ($ip, 161)
    
    # Use SNMP v2
    $ver = [Lextm.SharpSnmpLib.VersionCode]::V2
    
    # Perform SNMP Get
    try {
        $msg = [Lextm.SharpSnmpLib.Messaging.Messenger]::Get($ver, $svr, $Community, $vList, $TimeOut)
    } catch {
        Write-Host "SNMP Get error: $_"
        Return $null
    }
    
    $res = @()
    foreach ($var in $msg) {
        $line = "" | Select OID, Data
        $line.OID = $var.Id.ToString()
        $line.Data = $var.Data.ToString()
        $res += $line
    }
    
    $res
}

SNMP Walk

Used to get the results for a portion of the devices' MIB tree

function Invoke-SnmpWalk ([string]$sIP, $sOIDstart, [string]$Community = "public", [int]$UDPport = 161, [int]$TimeOut=3000) {
    # $sOIDstart
    # $TimeOut is in msec, 0 or -1 for infinite

    # Create OID object
    $oid = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($sOIDstart)
    
    # Create list for results
    $results = New-GenericObject System.Collections.Generic.List Lextm.SharpSnmpLib.Variable
    
    # Create endpoint for SNMP server
    $ip = [System.Net.IPAddress]::Parse($sIP)
    $svr = New-Object System.Net.IpEndPoint ($ip, 161)
    
    # Use SNMP v2 and walk mode WithinSubTree (as opposed to Default)
    $ver = [Lextm.SharpSnmpLib.VersionCode]::V2
    $walkMode = [Lextm.SharpSnmpLib.Messaging.WalkMode]::WithinSubtree
    
    # Perform SNMP Get
    try {
        [Lextm.SharpSnmpLib.Messaging.Messenger]::Walk($ver, $svr, $Community, $oid, $results, $TimeOut, $walkMode)
    } catch {
        Write-Host "SNMP Walk error: $_"
        Return $null
    }
    
    $res = @()
    foreach ($var in $results) {
        $line = "" | Select OID, Data
        $line.OID = $var.Id.ToString()
        $line.Data = $var.Data.ToString()
        $res += $line
    }
    
    $res
}

Example Usage

If you saved the Generic Objects workaround script, the SNMP DLL file, and the above functions in lib sub-folder to where your running your PowerShell from, then you could perform queries as follows...

Windows PowerShell
Copyright (C) 2009 Microsoft Corporation. All rights reserved.

PS C:\Users\simon> cd .\Documents\Scripts
PS C:\Users\simon\Documents\Scripts> . .\lib\New-GenericObject.ps1
PS C:\Users\simon\Documents\Scripts> [reflection.assembly]::LoadFrom( (Resolve-Path ".\lib\LexTmSharpSNMP\SharpSnmpLib.dll") )

GAC    Version        Location
---    -------        --------
False  v2.0.50727     C:\Users\simon\Documents\Scripts\lib\LexTmSharpSNMP\SharpSnmpLib.dll

PS C:\Users\simon\Documents\Scripts> . .\lib\SNMP-Funcs.ps1
PS C:\Users\simon\Documents\Scripts> Invoke-SnmpGet "192.168.10.201" ".1.3.6.1.2.1.1.5.0"

OID                                                         Data
---                                                         ----
.1.3.6.1.2.1.1.5.0                                          TEST-SVR-01


PS C:\Users\simon\Documents\Scripts> Invoke-SnmpGet "192.168.10.201" ".1.3.6.1.2.1.1.4.0"

OID                                                         Data
---                                                         ----
.1.3.6.1.2.1.1.4.0                                          Tinker box

PS C:\Users\simon\Documents\Scripts> Invoke-SnmpWalk "192.168.10.201" ".1.3.6.1.2.1.1"
0

OID                                                         Data
---                                                         ----
.1.3.6.1.2.1.1.1.0                                          Hardware: AMD64 Family 16 Model 2 Stepping 3 AT/AT COMPA...
.1.3.6.1.2.1.1.2.0                                          .1.3.6.1.4.1.311.1.1.3.1.2
.1.3.6.1.2.1.1.3.0                                          287291086 (33.06:01:50.8600000)
.1.3.6.1.2.1.1.4.0                                          Tinker box
.1.3.6.1.2.1.1.5.0                                          TEST-SVR-01
.1.3.6.1.2.1.1.6.0
.1.3.6.1.2.1.1.7.0                                          76