0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ipCidrRouteTableのsnmpwalk結果をPowerShellで処理しテーブル形式で出力する

Last updated at Posted at 2020-07-02

1. はじめに

SNMPエージェントのソフトウェアの開発に利用されるフリーのSNMPパッケージで、
代表的なものとしてはNet-SNMPがあります。

http://net-snmp.sourceforge.net/

この記事では、
Net-SNMPに付属しているsnmpwalkコマンドを使って、ルーティング情報が格納されている

ipCidrRouteTable(.1.3.6.1.2.1.4.24.4)
ipCidrRouteEntry(.1.3.6.1.2.1.4.24.4.1)

のsnmpwalk結果をPowerShellのスクリプトで処理し、テーブル形式での出力を得る処理の作成例を紹介します。

テーブル形式での出力結果は、下記のような形式です。

取得結果例1(テーブル形式)

PowerShell
Destination         Netmask             NextHop             ifIndex   Type      Proto     Tos       Age       Info
10.1.15.0           255.255.255.0       0.0.0.0             99        local     local     0         169996    .0.0
10.1.15.254         255.255.255.255     0.0.0.0             99        local     local     0         169996    .0.0
10.15.0.0           255.255.255.0       0.0.0.0             99        local     local     0         169996    .0.0
10.15.0.254         255.255.255.255     0.0.0.0             99        local     local     0         169996    .0.0
10.15.10.0          255.255.255.0       0.0.0.0             99        local     local     0         169996    .0.0
10.15.10.254        255.255.255.255     0.0.0.0             99        local     local     0         169996    .0.0
10.20.25.0          255.255.255.0       0.0.0.0             10501     remote    ospf      0         0         .0.0
10.20.25.254        255.255.255.255     0.0.0.0             20567     local     local     0         170000    .0.0
10.16.0.0           255.255.255.0       0.0.0.0             99        local     local     0         169996    .0.0
10.16.0.254         255.255.255.255     0.0.0.0             99        local     local     0         169996    .0.0

取得結果例2(csv形式)

PowerShell
Destination;Netmask;NextHop;ifIndex;Type;Proto;Tos;Age;Info
10.1.15.0;255.255.255.0;0.0.0.0;99;local;local;0;169996;.0.0
10.1.15.254;255.255.255.255;0.0.0.0;99;local;local;0;169996;.0.0
10.15.0.0;255.255.255.0;0.0.0.0;99;local;local;0;169996;.0.0
10.15.0.254;255.255.255.255;0.0.0.0;99;local;local;0;169996;.0.0
10.15.10.0;255.255.255.0;0.0.0.0;99;local;local;0;169996;.0.0
10.15.10.254;255.255.255.255;0.0.0.0;99;local;local;0;169996;.0.0
10.20.25.0;255.255.255.0;0.0.0.0;10501;remote;ospf;0;0;.0.0
10.20.25.254;255.255.255.255;0.0.0.0;20567;local;local;0;170000;.0.0
10.16.0.0;255.255.255.0;0.0.0.0;99;local;local;0;169996;.0.0
10.16.0.254;255.255.255.255;0.0.0.0;99;local;local;0;169996;.0.0

完成例

PowerShellスクリプトの完成例は以下にも配置しています。

ちなみに、GUI版のほとんどのSNMPマネージャ製品では、簡単にメニュー等から選択するだけで表形式でみることができます。

しかし、SNMPマネージャのデバッグ時や、障害が発生していてSNMPマネージャが利用できない場合などは、
直接、対象のNW機器に対してsnmpwalkしたいときがありますよね。

snmpwalkを利用すれば、引数で指定したOID配下のMIBを再帰的にgetnextするので、下記のように格納順に結果が得られますが、同一レコードをグループ化して見たいときは、表計算ソフトに張り付けたりする作業が必要となるなど、いろいろと不便です。

PowerShell
PS D:\PS_convert_ipCidrRouteTable> snmpwalk -On -c public -v2c 10.15.10.254 .1.3.6.1.2.1.4.24.4.1
.1.3.6.1.2.1.4.24.4.1.1.10.1.15.0.255.255.255.0.0.0.0.0.0 = IpAddress: 10.1.15.0
.1.3.6.1.2.1.4.24.4.1.1.10.1.15.254.255.255.255.255.0.0.0.0.0 = IpAddress: 10.1.15.254
(中略)
.1.3.6.1.2.1.4.24.4.1.2.10.1.15.0.255.255.255.0.0.0.0.0.0 = IpAddress: 255.255.255.0
.1.3.6.1.2.1.4.24.4.1.2.10.1.15.254.255.255.255.255.0.0.0.0.0 = IpAddress: 255.255.255.255
(中略)
.1.3.6.1.2.1.4.24.4.1.3.10.1.15.0.255.255.255.0.0.0.0.0.0 = INTEGER: 0
.1.3.6.1.2.1.4.24.4.1.3.10.1.15.254.255.255.255.255.0.0.0.0.0 = INTEGER: 0
(中略)
.1.3.6.1.2.1.4.24.4.1.4.10.1.15.0.255.255.255.0.0.0.0.0.0 = IpAddress: 0.0.0.0
.1.3.6.1.2.1.4.24.4.1.4.10.1.15.254.255.255.255.255.0.0.0.0.0 = IpAddress: 0.0.0.0
(中略)

そこで、snmpwalkの実行結果をPowerShellのスクリプトで処理し、テーブル形式で出力してみることにします。

pythonやrubyなどでは、snmp用のライブラリが用意されています。

PowerShellでも、外部のDLLやクラスライブラリを利用すれば、もう少し簡単に処理できるかもしれませんが、今回は、snmpwalkの実行結果を利用して、PowerShellスクリプト単体で処理することにしました。

2. PowerShellスクリプトの作成

2つのクラスと2つのハッシュテーブルを用意します。

2-1. IfValuesクラス

IfValuesクラスは、ipCidrRouteEntry(.1.3.6.1.2.1.4.24.4.1) 配下のMIBの

  • OID
  • パターンマッチで使用するためのOIDを正規表現化したもの
  • 対象OIDの名前
  • 読み込み時の検証で使用するカウンタ
  • 初期化用のInitメソッド

などをとりまとめたオブジェクト用のクラスです。

PS_convert_ipCidrRouteTable.ps1
class IfValues {
    [string] $OID
    [string] $OIDRegular
    [string] $Name
    [int]    $count

    Init($oid, $name) {
        $this.Name = $name
        $this.OID = $oid
        $this.OIDRegular = "^" + $this.OID.Replace("." ,"\.")
        $this.count = 0
    }
}

2-2. RouteTableクラス

RouteTableクラスは、ipCidrRouteEntry(.1.3.6.1.2.1.4.24.4.1) 配下のMIBの
各項目と型を定義したクラスです。1つの宛先の情報をとりまとめたもの(1レコード)に相当します。

snmpwalkの実行結果は文字列ですが、値の前に型情報も含まれているので、
INTEGER32はint型、IpAddress型やOID型はstring 型で読み込むことにします。

実行結果は複数の宛先から構成されますので、実行時にはこのオブジェクトの配列を用意することになります。

PS_convert_ipCidrRouteTable.ps1
class RouteTable {
    [string] $ipCidrRouteOID
    [string] $ipCidrRouteDest
    [string] $ipCidrRouteMask
    [int] $ipCidrRouteTos
    [string] $ipCidrRouteNextHop
    [int] $ipCidrRouteIfIndex

    [int] $ipCidrRouteType
    [string] $ipCidrRouteTypeName

    [int] $ipCidrRouteProto
    [string] $ipCidrRouteProtoName

    [int] $ipCidrRouteAge
    [string] $ipCidrRouteInfo
    [int] $ipCidrRouteNextHopAS
    [int] $ipCidrRouteMetric1
    [int] $ipCidrRouteMetric2
    [int] $ipCidrRouteMetric3
    [int] $ipCidrRouteMetric4
    [int] $ipCidrRouteMetric5
    [int] $ipCidrRouteStatus
}

2-3. 各OID用のIfIndexオブジェクトの生成

クラスの定義が終わったので、ipCidrRouteEntry(.1.3.6.1.2.1.4.24.4.1) 配下用のオブジェクトを生成します。

PS_convert_ipCidrRouteTable.ps1
$ipCidrRouteOID = New-Object IfValues
$ipCidrRouteOID.Init(".1.3.6.1.2.1.4.24.4.", "ipCidrRouteOID")

$ipCidrRouteDest = New-Object IfValues
$ipCidrRouteDest.Init(".1.3.6.1.2.1.4.24.4.1.1.", "ipCidrRouteDest")

$ipCidrRouteMask = New-Object IfValues
$ipCidrRouteMask.Init(".1.3.6.1.2.1.4.24.4.1.2.", "ipCidrRouteMask")

$ipCidrRouteTos = New-Object IfValues
$ipCidrRouteTos.Init(".1.3.6.1.2.1.4.24.4.1.3.", "ipCidrRouteTos")

$ipCidrRouteNextHop = New-Object IfValues
$ipCidrRouteNextHop.Init(".1.3.6.1.2.1.4.24.4.1.4.", "ipCidrRouteNextHop")

$ipCidrRouteIfIndex = New-Object IfValues
$ipCidrRouteIfIndex.Init(".1.3.6.1.2.1.4.24.4.1.5.", "ipCidrRouteIfIndex")

$ipCidrRouteType = New-Object IfValues
$ipCidrRouteType.Init(".1.3.6.1.2.1.4.24.4.1.6.", "ipCidrRouteType")

$ipCidrRouteProto = New-Object IfValues
$ipCidrRouteProto.Init(".1.3.6.1.2.1.4.24.4.1.7.", "ipCidrRouteProto")

$ipCidrRouteAge = New-Object IfValues
$ipCidrRouteAge.Init(".1.3.6.1.2.1.4.24.4.1.8.", "ipCidrRouteAge")

$ipCidrRouteInfo = New-Object IfValues
$ipCidrRouteInfo.Init(".1.3.6.1.2.1.4.24.4.1.9.", "ipCidrRouteInfo")
...
...

2-4. typeとProtocolの定義値

ipCidrRouteType(1.3.6.1.2.1.4.24.4.1.6)
ipCidrRouteProto(1.3.6.1.2.1.4.24.4.1.7)

については、数値のまま結果を表示すると解りにくいので、

MIB定義ファイルに記載されている値をハッシュテーブルとして用意しておき、
取得した値からプロトコル名に変換できるようにしておきます。

今回のスクリプトでは-Onオプションに合わせて作っていますが、
snmpwalk実行時に、-Onオプションを指定しないという手もありますね。

PS_convert_ipCidrRouteTable.ps1
$typeTable = @{
    1 = "other"
    2 = "reject"
    3 = "local"
    4 = "remote"
}
PS_convert_ipCidrRouteTable.ps1
$protoTable = @{
    1 = "other"
    2 = "local"
    3 = "netmgmt"
    4 = "icmp"
    5 = "egp"
    6 = "ggp"
    7 = "hello"
    8 = "rip"
    9 = "isIs"
    10 = "esIs"
    11 = "ciscoIgrp"
    12 = "bbnSpfIgp"
    13 = "ospf"
    14 = "bgp"
    15 = "idpr"
    16 = "ciscoEigrp"
}

2-5. 読み込み処理

snmpwalk からパイプで渡された実行結果は、$input に格納されていますので、
foreach で1行ずつ読み込み、OID番号 が一致するフィールドに格納していきます。

$resultTable は、結果を格納するための RouteTable型 の配列です。

PS_convert_ipCidrRouteTable.ps1
$resultTable = @()

foreach ($line in $input) {
 #  Write-Output $line
    switch -Regex ($line) {
        $ipCidrRouteDest.OIDRegular {
            $line = $line.Replace($ipCidrRouteDest.OID, "")
            $flds = $line -split " = "
            if ($flds.Length -ge 2) {
                $resultTable += New-Object RouteTable
                $resultTable[$resultTable.Lenght - 1].ipCidrRouteOID = $flds[0].Replace($ipCidrRouteDest.OID, "")
                $resultTable[$resultTable.Lenght - 1].ipCidrRouteDest = $flds[1].Replace("IpAddress: ", "")
            }
            else {
                Write-Output "$ipCidrRouteDest.OID Check Error"
                return
            }
            break
        }
        $ipCidrRouteMask.OIDRegular {
            $line = $line.Replace($ipCidrRouteMask.OID, "")
            $flds = $line -split " = "
            if (($flds.Length -ge 2) -And ($flds[0] -eq $resultTable[$ipCidrRouteMask.count].ipCidrRouteOID)) {
                $resultTable[$ipCidrRouteMask.count].ipCidrRouteMask = $flds[1].Replace("IpAddress: ", "")
                $ipCidrRouteMask.count++
            }
            else {
                Write-Output "$ipCidrRouteMask.OID Check Error"
                return
            }
            break
        }
...
...

2-6. typeとprotocolから定義値を読み込む

typeprotocol については、

$resultTable[$i].ipCidrRouteType
$resultTable[$i].ipCidrRouteProto

に格納されている値から、ハッシュテーブルを参照して定義値を取得します。

取得結果は、それぞれ、

$resultTable[$i].ipCidrRouteTypeName
$resultTable[$i].ipCidrRouteProtoName

に格納しておきます。

PS_convert_ipCidrRouteTable.ps1
for ($i = 0; $i -lt $resultTable.Length; $i++) {
    $resultTable[$i].ipCidrRouteTypeName = $typeTable[$resultTable[$i].ipCidrRouteType]
}

for ($i = 0; $i -lt $resultTable.Length; $i++) {
    $resultTable[$i].ipCidrRouteProtoName = $protoTable[$resultTable[$i].ipCidrRouteProto]
}

2-7. 結果の表示処理

配列**$resultTable** の全レコード、各レコードを標準出力に書き出します。

$IFSの内容によって、出力幅を固定して出力したり、
デリミタ文字を指定してCSV形式での出力もできるようにしています。

PS_convert_ipCidrRouteTable.ps1
if ($IFS -eq "") {
    $format = "{0,-20}{1,-20}{2,-20}{3,-10}{4,-10}{5,-10}{6,-10}{7,-10}{8,-10}"
}
else {
    $format = "{0}$IFS{1}$IFS{2}$IFS{3}$IFS{4}$IFS{5}$IFS{6}$IFS{7}$IFS{8}"
}

Write-Output ($format -f `
    "Destination" `
  , "Netmask" `
  , "NextHop" `
  , "ifIndex" `
  , "Type" `
  , "Proto" `
  , "Tos" `
  , "Age" `
  , "Info" `
)

for ($i = 0; $i -lt $resultTable.Length; $i++) {
    Write-Output ($format -f `
      $resultTable[$i].ipCidrRouteDest `
    , $resultTable[$i].ipCidrRouteMask `
    , $resultTable[$i].ipCidrRouteNextHop `
    , $resultTable[$i].ipCidrRouteIfIndex `
    , $resultTable[$i].ipCidrRouteTypeName `
    , $resultTable[$i].ipCidrRouteProtoName `
    , $resultTable[$i].ipCidrRouteTos `
    , $resultTable[$i].ipCidrRouteAge `
    , $resultTable[$i].ipCidrRouteInfo `
    )
}

3. 実行例

実行する場合は、以下のような書式でsnmpwalkの実行結果を、PowerShellスクリプトに渡します。

書式

PowerShell
snmpwalk -On -v 2c -c <community> <target_ip> .1.3.6.1.2.1.4.24.4 | .\convert_ipCidrRouteTable.ps1 [IFS(delimiter)]

実行例1(テーブル形式)

PowerShell
snmpwalk -On -v 2c -c public 10.1.15.254 .1.3.6.1.2.1.4.24.4 | .\PS_convert_ipCidrRouteTable.ps1

実行例2(コンマ区切り(csv形式))

PowerShell
snmpwalk -On -v 2c -c public 10.1.15.254 .1.3.6.1.2.1.4.24.4 | .\PS_convert_ipCidrRouteTable.ps1 ";"

実行例3(タブ区切り)

PowerShell
snmpwalk -On -v 2c -c public 10.1.15.254 .1.3.6.1.2.1.4.24.4 | .\PS_convert_ipCidrRouteTable.ps1 "\t"

毎回、OIDを指定してsnmpwalkを実行するのが面倒なのであれば、
下記のようなスクリプト内でsnmpwalkとPS_convert_ipCidrRouteTable.ps1を実行すると良いでしょう。

main.ps1
param($target, $community, $IFS)

if (-Not($target)) {
    Write-Host "Usage :"$MyInvocation.MyCommand.Name"<target> <community>"
    exit
}

if (-Not($community)) {
    $community = "public"
}

if (-Not($IFS)) {
    $IFS = ""
}


$OID = ".1.3.6.1.2.1.4.24.4"
$walkResult = snmpwalk -On -v 2c -c $community $target $OID

if ($walkResult -eq $NULL) {
    Write-Output $walkResult
    exit
}

$walkResult | ./PS_convert_ipCidrRouteTable.ps1 $IFS

4. 関連記事

ifEntryのsnmpwalk結果をPowerShellで処理しテーブル形式で出力する

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?