LoginSignup
0
0

More than 1 year has passed since last update.

Aruba AP に telnet で接続して連続コマンド実行をする

Last updated at Posted at 2023-03-05

ちょっと必要になったのでメモ。

Cisco 機器の場合

Cisco のルータなどに纏めてコマンドを投げるときには適宜 sleep を挟みながら echo で投げれば良いのですが

for Cisco
#!/bin/sh

for CISCO_Cisco in 100.64.20.1 100.64.21.1 100.64.22.1 ; do
(
	sleep 1;\
	echo 'admin';\
	sleep 1;\
	echo 'Cisco123';\
	sleep 1;\
	echo 'enable';\
	echo 'Cisco123';\
	sleep 1;\
	echo 'ter len 0';\
	echo 'ter wid 0';\
	echo 'show run';\
	sleep 3;\
	echo 'show version';\
	sleep 1;\
	echo 'show clock';\
	sleep 1;\
	echo 'show tech';\
	sleep 60;\
	echo '!!! ALL DONE';\
	sleep 1;\
	echo 'exit';\
	sleep 1;\
) | (telnet $CISCO_Cisco | tee ${CISCO_Cisco}.log )&
done

コマンドを投げる部分を関数にしてバックグランドで実行、出力ログの最後に「ALL DONE」が入っていなければ再実行。とかしたら (for ループに適宜 sleep を挟まないと、えらいことになります) 100 台 show tech とかも休憩に行ってる間に終わらせることが出来ます。

Aruba の AP の場合

ところが同じ方法で Aruba AP の情報を収集しようとしたら改行の所に ^M と表示され、コマンドが実行されません。
ということで、Aruba の AP は改行コードが違うらしいので、printf で書いてあげましょう。

for Aruba IAP
#!/bin/sh

(
	sleep 1;\
	printf 'show_user\r';\
	sleep 3;\
	printf 'abc123\r';\
	sleep 1;\
	printf 'show running-config\r';\
	sleep 3;\
	printf 'show version\r';\
	sleep 1;\
	printf 'show clock\r';\
	sleep 1;\
	printf 'show ip interface brief\r';\
	sleep 1;\
	printf 'exit\r';\
	sleep 1;\
) | telnet 192.168.0.200

tr で \n と \r を変換しても良いんですけどね。
まぁ、最近は ssh なのでこの手が使いにくいのですが。
というメモでした。

Cisco 機器の場合 perl バージョン

for Cisco
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(try);
no warnings "experimental::try"; # 警告の抑制

use POSIX qw(strftime);
use Net::Telnet;

my $host;					# ホスト or IP
my $user = 'admin';			# ユーザ名
my $pass = 'Cisco123';		# パスワード
my $prompt = '/[>#]$/';		# プロンプト(正規表現)

my @HOSTs = ('100.64.20.1', '100.64.21.1', '100.64.22.1');

foreach my $host ( @HOSTs ){
	&command_exec($host)
}

sub command_exec(){
	my $host = shift;
	my $log_file = strftime("${host}_%Y%m%d_%H%M%S.log", localtime);
	my @result;

	# 失敗しても 3回までリトライする
	for ( 1..3 ) {
		print "--- 再実行します ---\n" unless ($_ eq 1);
		try {
			my $result;
			my $telnet = new Net::Telnet(
				Timeout => 5,
				Errmode => 'return',				# エラーメッセージを追加するため
				Prompt => $prompt,
				Input_log => $log_file,
				Cmd_remove_mode => 0,
				Max_buffer_length => 10485760,		# 10MB
			);

			print "\n*** $host へ接続します\n";

			# ホストに接続してログインする
			die "connect failer\n"
				unless $telnet->open($host);
			die "login failer. check username or password"
				unless $telnet->login( Name => $user, Password => $pass);
			die "enable command failer. check log please."
				unless $telnet->cmd(String => "enable" ,Prompt  => '/Password:/');
			die "enable failer. check enable password."
				unless $telnet->cmd($pass);

			# ここからエラーになることは考えにくいので die にする
			$telnet->errmode("die");

			$telnet->cmd('ter len 0');
			$telnet->cmd('ter wid 0');

			# コマンドの実行
			@result = ($telnet->last_prompt(), $telnet->cmd("show run"));
			print @result;

			@result = ($telnet->last_prompt(), $telnet->cmd("show version"));
			print @result;

			@result = ($telnet->last_prompt(), $telnet->cmd("show clock"));
			print @result;
	
			@result = ($telnet->last_prompt(), $telnet->cmd(String => "show tech", Timeout => 60));
			print @result;

			# コマンドの実行結果にたまたまプロンプトに合致する物が含まれていた場合
			# 途中で切れてしまうので、絶対に実行結果に含まれないような文字列で
			# 最後まで出力していることを確認する。
			@result = ($telnet->last_prompt(), $telnet->cmd(String => "!!! ALL DONE !!!", Prompt  => '/!!! ALL DONE !!!/', Timeout => 60));
			print @result;
			print $telnet->last_prompt();

			# 接続の切断
			$telnet->close;
			print "\n*** $host から切断しました\n\n";
		} catch ($e) {
			# エラーが発生した場合は、もう一度
			# redo だと無限ループになる
			print "\n$e";
			next;
		}
		# 成功した場合は for ループを抜ける
		last;
	}
}

Aruba AP 機器の場合 perl バージョン

接続先毎に、ユーザ名、パスワード、ログファイル名の先頭部分を指定できるように変更しました。

for Aruba AP
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw(strftime);
use feature qw(try);
no warnings "experimental::try"; # 警告の抑制

use Net::Telnet;

my @HOSTs = (
	# 
	# ['<接続先>', '<log_prefix>', '<user>', '<pass>'],
	#
	# 接続先     : IP アドレスや、ホスト名
	# log_prefix : ログファイル名の区別用 (ホスト名など)
	# user       : ログインの user 名
	# pass       : パスワード

	['100.64.10.33', 'AP-001', 'show', 'abc123'],
	['100.64.20.61', 'AP-101', 'show2','Passw0rd'],
);
my $prompt = '/# $/';		# プロンプト(正規表現)


foreach my $host ( @HOSTs ){
	&command_exec($host)
}

sub command_exec(){
	my ($host, $log_prefix, $user, $pass) = @{$_[0]};
	my $log_file = strftime("${log_prefix}_%Y%m%d_%H%M%S.log", localtime);

	# 失敗しても 3回までリトライする
	for ( 1..3 ) {
		print "--- 再実行します ---\n" unless ($_ eq 1);
		try {
			my @result;
			my $telnet = new Net::Telnet(
				Timeout => 5,
				Errmode => 'return',				# エラーメッセージを追加するため
				Prompt => $prompt,
				Input_log => $log_file,
				Cmd_remove_mode => 0,
				Max_buffer_length => 10485760,		# 10MB
				Output_record_separator => "\r",	# コマンド送信時の改行コードは \r
			);

			&print_banner("$host へ接続します");

			# ホストに接続してログインする
			# パターンが違うので、login() は使えない
			die "connect failer\n"
				unless $telnet->open($host);
			die "login failer. no response."
				unless $telnet->cmd(String => '', Prompt  => '/User: $/');
			die "login failer. no/illigal response."
				unless $telnet->cmd(String => $user, Prompt  => '/Password: $/');
			die "login failer. check username or password"
				unless $telnet->cmd($pass);

			# ここからエラーになることは考えにくいので die にする
			$telnet->errmode("die");

			# コマンドの実行
			@result = ($telnet->last_prompt(), $telnet->cmd("show running-config"));
			print @result;

			@result = ($telnet->last_prompt(), $telnet->cmd("show version"));
			print @result;

			@result = ($telnet->last_prompt(), $telnet->cmd("show clock"));
			print @result;
	
			@result = ($telnet->last_prompt(), $telnet->cmd(String => "show tech-support", Timeout => 60));
			print @result;

			# コマンドの実行結果にたまたまプロンプトに合致する物が含まれていた場合
			# 途中で切れてしまうので、絶対に実行結果に含まれないような文字列で
			# 最後まで出力していることを確認する。
			@result = ($telnet->last_prompt(), $telnet->cmd(String => "!!! ALL DONE !!!", Prompt  => '/% Parse error/', Timeout => 60));
			print @result;
			print $telnet->last_prompt();

			# 接続の切断
			$telnet->close;
			&print_banner("$host から切断しました");
		} catch ($e) {
			# エラーが発生した場合は、もう一度
			# redo だと無限ループになる
			print "\n$e";
			next;
		}
		# 成功した場合は for ループを抜ける
		last;
	}
}

sub print_banner(){
	my $str = shift;
	my $line = '*' x (length($str) + 8);
	print "\n";
	print "$line\n";
	print "*** $str ***\n";
	print "$line\n";
	print "\n";
}

perl モジュール、Net-Telnet のマニュアルは cpan を参照
Net::Telnet

sub print_banner 部分、きちんと並べることが出来ませんでしたが、きちんと並べようとすると追加でモジュールを読み込まないといけない雰囲気だったので諦めました。
Perlでマルチバイト文字の文字幅をAmbiguousWidthも考慮して取りたいときのTips

Teraterm のログのタイムスタンプを外す

image.png
タイムスタンプでログを取得したけども、結果を diff しようとしたらタイムスタンプが邪魔。ということも。そういうときには、さらっとタイムスタンプを外してしまいましょう。

teraterm のタイムスタンプを外す
for i in *.log ; do
sed -ne 's/^\[[-0-9]*\] [:\.0-9]*\] //p;' < "$i" > "$i.タイムスタンプなし.log"
done

外部リンク
telnet操作をコンピュータにやらせて処理(show account)を自動化する方法はありませんか?(telnet用チャットスクリプト) (YAMAHA)

0
0
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
0