http://www.perlmonks.org?node_id=279335

Hi Monks, I work in a job where me, and my coworkers, need to log into many Cisco routers and switches all day long. Sometimes we need to do he same thing on differnt groups of Cisco devices. I ussualy write tiny scripts for my own use, but it was my first time to write one for site wide use. Here is the resultant code, which my coworkers have used for a week, and love. It is very primitive so any suggestions or comments would be apprecaited. I have included the coe for the script and after that, an example config file.

Note: I realzie that the Telnet function requires some work to cover the many differnt log in/enable style that Cisco routers support. I made it work ,just enough, for my enviroment.


batch_router.pl - the script itself
#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(:config no_ignore_case bundling); use Net::Telnet::Cisco; use FileHandle; use Term::ReadKey; use Config::Tiny; $|=1; #! #!<VERSION> my $version="0.07"; my $version_date="07/22/03"; #!</VERSION> #! #Get command line options my $ln_group=""; my $ln_router=""; my $user_name=""; my $password=""; my $input_file=""; my $output_file=""; my $flag_help=0; my $flag_version=0; my $command=""; GetOptions( 'r=s'=>\$ln_router, 'router=s'=>\$ln_router, 'g=s'=>\$ln_group, 'group=s'=>\$ln_group, 'u=s'=>\$user_name, 'username=s'=>\$user_name, 'p=s'=>\$password, 'password=s'=>\$password, 'i=s'=>\$input_file, 'input=s'=>\$input_file, 'o=s'=>\$output_file, 'output=s'=>\$output_file, 'c=s'=>\$command, 'command=s'=>\$command, 'h'=>\$flag_help, 'help'=>\$flag_help, 'v'=>\$flag_version, 'version'=>\$flag_version, ); #Validate command line options #my @commands=(); #if ($command ne "") #{ # $commands[0]="first array"; # push (@commands,$command); # my $line=""; # foreach $line (@commands) # { # print $line . "\n"; # } #} #exit 0; if ($flag_help) { #List Options print STDOUT "Batch Router - the batch router configurator\n"; print STDOUT "\n"; print STDOUT "List of options and their functions:\n"; print STDOUT "-r --router \t Specify a single router name from the + config file, overides -g/--group.\n"; print STDOUT "-g --group \t Specify a single group of routers from + the config file.\n"; print STDOUT "-u --username \t Specifies username to use for TACAC +S logins. If not supplied then script will prompt for name. Cannot be + blank\n"; print STDOUT "-p --password \t Specifies password to use for TACAC +S logins. If not supplied then script will prompt for password. Canno +t be blank\n"; print STDOUT "-c --command \t Specifies single command to run. Com +mand must be surround with double qoutes, if there are spaces.\n"; print STDOUT "-i --input \t Specifies name and path to file which +has the commands that will be ran on each router. If not supplied the +n script will prompt for path/name. Cannot be blank\n"; print STDOUT "-o --output \t Specifies name and path where to send + output from routers. If not supplied output will be sent to STDOUT\n +"; print STDOUT "-h --help \t This help screen. Displays a list of op +tions.\n"; print STDOUT "-v --version \t Display version information for this + script.\n"; exit 0; } if ($flag_version) { #Show Version print STDOUT "Batch Router - the batch router configurator\n"; print STDOUT "Version number $version\n"; print STDOUT "Latest revision on $version_date\n"; exit 0; } #Load Config file my %routers=(); my $conf = Config::Tiny->read('batch_router.cnf'); my $conf_routers = $conf->{routers}; # Hash ref with routers informati +on my $conf_groups = $conf->{groups}; # Hash ref with group information my $validation=0; if ($ln_router ne "") { #Check for Single Host #Validate router with config file $validation = &Check_routers($conf_routers, $ln_router); if (!$validation) { print STDOUT "Router \'$ln_router\' is not in routers list.\n" +; exit 1; } $routers{$ln_router}=$conf_routers->{$ln_router}; } elsif ($ln_group ne "") { #Check for group of hosts #Validate group with config file $validation = &Check_groups($conf_groups, $ln_group); if (!$validation) { print STDOUT "Group \'$ln_group\' is not in group list.\n"; exit 1; } #Pull each router name from $conf_group and put into a list my @router_list=&Group_to_routers($conf_groups->{$ln_group}); #Validate each router name in group my $line = ""; foreach $line (@router_list) { #Reset Validation to false $validation=0; $validation = &Check_routers($conf_routers, $line); if (!$validation) { print STDOUT "Router \'$line\' in group \'$ln_group\' is n +ot in routers list.\n"; exit 1; } $routers{$line}=$conf_routers->{$line}; } } else { #Make sure single or group of hosts selected print STDOUT "You must select a router or group to run this script +.\n"; exit 0; } #Prompt for user name if not provided if ($user_name eq "") { print STDOUT "Please enter your user name: "; ReadMode('normal'); $user_name = ReadLine(0); chomp $user_name; ReadMode('restore'); if ($user_name eq "") { print STDOUT "User name cannot be blank.\n"; exit 1; } } #prompt for password if not provided if ($password eq "") { print STDOUT "Please enter your password: "; ReadMode('noecho'); $password = ReadLine(0); chomp $password; ReadMode('restore'); if ($password eq "") { print STDOUT "Password cannot be blank.\n"; exit 1; } print "\n"; } if ($input_file eq "" && $command eq "") { print STDOUT "Please enter \'input' filename, with path if needed: + "; ReadMode('normal'); $input_file = ReadLine(0); chomp $input_file; ReadMode('restore'); if ($input_file eq "") { print STDOUT "Input filename can not be blank name cannot be b +lank.\n"; exit 1; } } #Get list of commands from Input file or from the command line my @commands=(); if ($command ne "") { push (@commands,$command); } elsif ($input_file ne "") { print STDOUT "*Reading in commands from Input File..."; @commands= &Open_input_file($input_file); #Check for returned error if (scalar(@commands) <= 0) { print STDOUT "\nInput file '$input_file' does not exist, is un +readable, or is empty.\n"; exit 1; } print STDOUT "Done\n"; } #Set $out_fh(refernce to output file handle) to STDOUT or output file print STDOUT "*Setting up output file, if any..."; my $out_FH = &Set_output_FH($output_file); if (!$out_FH) { print STDOUT "\nOutput file '$output_file' can not be created or o +pened.\n"; exit 1; } print STDOUT "Done\n"; print STDOUT "*Logging into Routers.\n"; if ($output_file eq "") {print "\n";} my $host=""; my %Result=(); foreach $host (keys %routers) { print STDOUT "*Logging into router $host($routers{$host}).\n"; if ($output_file ne "") { print $out_FH "Router $host($routers{$host}).\n"; } %Result= &Router($user_name,$password, $routers{$host}, @commands) +; my $line = ""; foreach $line (@commands) { print $out_FH "-" . $line . "\n"; my $output_list=""; foreach $output_list ($Result{$line}) { my $output_line=""; foreach $output_line (@$output_list) { chomp ($output_line); print $out_FH "\t" . $output_line . "\n"; } } } print $out_FH "\n"; print $out_FH "--------------------------------------------------- +-\n"; if ($output_file eq "") {print STDOUT "\n";} } if ($output_file eq "") {print STDOUT "\n";} print STDOUT "*Closing output file, if any..."; if (!$output_file eq "") { close ($out_FH); } print STDOUT "Done\n"; ## Start of subfunctions sub Check_routers { #Check router Hash reference for router string my ($conf_routers, $ln_router)=@_; if (!defined($conf_routers->{$ln_router})) { return 0; } return 1; } sub Check_groups { #Check group Hash refernce for group string my ($conf_groups, $ln_group)=@_; if (!defined($conf_groups->{$ln_group})) { return 0; } return 1; } sub Group_to_routers { #Convert group router string into list of router names my ($group)=@_; chomp $group; $group =~ s/[ \[\]]//g; my @router_list = split/,/,$group; return @router_list; } sub Open_input_file { #Open config file ($input_file)=@_; my @list = (); #Check if file exists and size > 0, else return error if (-s $input_file) { #Open Input file, else return Error unless (open IP_FH, "<$input_file") { close IP_FH; return (); } @list = <IP_FH>; chomp(@list); } else { close IP_FH; return (); } close IP_FH; return @list; } sub Set_output_FH { #Set output file handle, default to STDOUT ($output_file)=@_; my $out_FH=""; if ($output_file eq "") { $out_FH = \*STDOUT; } else { unless (open OUT_FH,">$output_file") { return 0; } $out_FH=\*OUT_FH; } return $out_FH; } sub Router { #Log into single router. Return command output in hash (with neste +d list) my ($user_name,$password, $host, @commands)=@_; my $t = Net::Telnet::Cisco->new(Host => $host, Dump_log=> "telnetlog$host.txt"); #Log in With Username and Password $t->login($user_name,$password); my @level = $t->cmd("show privilege"); #Check if at level 15, if not then enable if (!($level[0] =~ /15/)) { # if user level not 15 then enable $t->enable($password); } my $command=""; $t->cmd("terminal length 0"); my %Result=(); foreach $command (@commands) { @{$Result{$command}} = $t->cmd($command); } $t->close; return %Result; }

batch_router.cnf - the Config file
## Router Identification [routers] any-core_12016 = 192.168.1.1 any-edge_12012 = 192.168.1.2 ##Group of routers [groups] network = [any-core_12016, any-edge_12012]