Perl script to execute commands in cisco router - perl

I'm new to perl.I was trying to login to a cisco router to execute few commands.
I was able to login using Net::SSH::Perl and execute a couple of commands.
But when i tried to switch to the configure mode the script fails.
br-waas#
br-waas#configure
br-waas(config)#
Is there a perl cpan module to do this?
use Net::SSH::Perl;
my $host = "XX.XX.XX.XX";
my $user = "XXXX";
my $password = "XXXX";
my $ssh = Net::SSH::Perl->new($host);
$ssh->login($user, $password);
print "check the version of the build \n";
my ($stdout) = $ssh->cmd("show statistics accelerator http object-cache");
print $stdout;
sleep(3);
print "enter the config mode \n";
my($stdout1) = $ssh->cmd("config");
print "$stdout1 \n";
When the configure command executes the script fails with the following error. % Invalid input detected at '^' marker.

If you're having trouble with Net:SSH, Net::OpenSSH has always done the job well for me.
If you have an enable password, at the end of the day, you're going to need something implementing Expect, which is always a hassle.

The one library that worked for me is NET::Appliance::Session.
It is reliable, solves the "channel locking" issue en cisco routers/switches and can send commands without the use of expect (or at least does it internally can't remember well)

Does the command "config" work when doing this by hand? I assume you will get a question echoed back on the terminal.
If this is a plain Cisco router running IOS, the command to enter config mode is "configure terminal".

Related

Batch file to SSH Cisco phone and reboot it

First post, new to batch and scripting in general so please go easy on me.
I was tasked with writing a Perl script that would initiate SSH sessions with 6 phones and send them one CLI command to reboot them. Funny thing is, I know JACK about Perl. I do know a little batch automation and figured it'd be pretty simple to use plink to do what I needed. How wrong I was.
Here is an example of my plink batch.
#echo off
plink.exe -t -ssh XXXXXXX#111.111.1.1 -pw Abcd1234 < "C:\commands\commands.txt">output.txt
pause
Commands.txt:
debug
debug
reset hard
Running the batch file returns a cmd window displaying: Using Username "XXXXXXX"
And my output.txt shows:
debug
debug
reset hardsnoopyplus login:
It was at this point I realized I'd need some insight on how to service this second set of login credentials before sending my reset command.
Here we are at day 3 and my boss would like some results. I have about 4 broken iterations of my script and a good attitude. What can I try?
Also, here is a portion of a Perl script I found that claimed to be able to handle the snoopyplus debug login for cisco phones that I was unable to get working. The little bit of info I found told me to rewrite it in OpenSSH which I don't think is supported on Windows.
sub reboot{
my ($ip,$sshpassword,$sshusername,$debuglogin,$debugusername,$debugpassword,$debugprompt,$command) = #_;
print "\nPlease be patient whilst Cisco phone at address $ip is rebooted. This may take up to 90 seconds to complete...\n";
my $ssh = Net::SSH::Perl->new("111.111.1.1");
my $login_output = $ssh->login();
#my $ssh->login($sshusername, $sshpassword) || myAuditLog(LOG,"Login has failed. $!");
$ssh->waitfor('/'.$debuglogin.'>.*$/');
$ssh->send($debugusername);
$ssh->waitfor('/Password :.*$/');
$ssh->send($debugpassword);
$ssh->waitfor('/'.$debugprompt.'>.*$/');
$ssh->exec($command);
$ssh->close();
If you are on Windows, take a look at Net::SSH2, which comes included with Strawberry Perl. Using it, you should be able to talk to your IP phones:
#!perl
use strict;
use warnings;
use Net::SSH2;
my $ssh2 = Net::SSH2->new();
$ssh2->connect('example.com') or $ssh2->die_with_error;
if ($ssh2->auth_password($debuglogin, $debugpassword)) {
my $chan = $ssh2->channel();
$chan->shell();
while (!$channel->eof) {
if (my ($o, $e) = $channel->read2) {
$out .= $o;
$err .= $e;
} else {
$ssh2->die_with_error;
}
}
};
Try this format of plink command:
plink.exe -t -ssh -pw Abcd1234 -m "C:\commands\commands.txt" XXXXXXX#111.111.1.1 >output.txt

Putty command from Perl

I am trying to run a couple of commands in putty from perl. Right now my code gets me into putty but I am unsure of how to execute commands from there.
my $PUTTY = 'C:\Users\Desktop\putty.exe';
my $dacPutty = "$PUTTY, -ssh username#server - l username -pw password";
system ($dacPutty);
system (ls);
use plink instead. ( http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter7.html )
plink is in the same directory as putty.
Usually in Perl it's better to use a Perl module, where one exists, than to shell out.
Using a module is more portable, and often gives you more control. system introduces many opportunities for security bugs, so it's good to avoid it where possible.
In this case, use Net::SSH::Perl http://search.cpan.org/~turnstep/Net-SSH-Perl-1.38/lib/Net/SSH/Perl.pm
Once installed:
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new("host1");
$ssh->login("user1", "pass1");
$ssh->cmd("cd /some/dir");
$ssh->cmd("foo");
For reliability, you should actually check the result of each cmd:
my ($stdout, $stderr, $exit) = $ssh->cmd("cd /some/dir");
unless ($exit == 0) {
// Handle failed cd
}
The document notes that with SSH-1, each cmd reconnects, so the above would not work -- you would cd in one shell, then foo in a completely new shell. If you have to use SSH-1, then you'd need to do:
$ssh->cmd("cd /some/dir; foo");
(And you can use a similar trick even if you're making a system call to plink)

Regarding running multiple ssh commands using perl

I am bit stuck here I want to ssh in to a machine and then run about 3 commands which are basically setup commands and then i want to return back to my machine with env variables of that machine
like
setup1
setup2
setup3
env > envtext.txt.
return back
All this i have to do in perl
i tried commands like
system("ssh #machine command1 && command 2") doesnt work
is there something like?
system("ssh #machine command1 -cmd command 2 -cmd command 3")
if not than what is the best way to do it
like making a shell script then calling it or i can do it in perl itself without any shell scripts?
code
#!/usr/bin/perl -w
use Net::SSH::Perl;
my $host = "address";
my $user = "name";
my $password = "password";
-- set up a new connection
my $ssh = Net::SSH::Perl->new($host,
debug=>0,
identity_files => ['path to key'],
options=> ["StrictHostKeyChecking no"]
#interactive => yes,
);
-- authenticate
$ssh->login($user,$password);
-- execute the command
my($stdout, $stderr, $exit) = $ssh->cmd("env");
print $stdout;`
error it gives is Permission denied at ssh.pl line 25
Thank you
I think your question is about SSHing to a single remote host and running multiple commands there. If that's true, then you need to pack your multiple commands up into a single command line that the remote shell can execute. The easiest way to do this is to use the list form of system, and pass the command line as a single parameter:
system "ssh", "machine", "setup1; setup2; setup3";
On to the second part of your question: You want to get data back from the remote side. For that, you'll want your program to read SSH's output rather than using system. For this, you can use:
open my $FH, "-|", "ssh", "machine", "setup1; setup2; setup3; env";
my #lines_from_ssh = <$FH>;
close $FH;
If you also need to send input to the remote side, look into IPC::Open2. If you need to capture both stdout and stderr, see IPC::Open3.
What you can do :
system("ssh $_ command1 -cmd command 2 -cmd command 3") for #machines;
Another Pure Perl solution is to use Net::OpenSSH

[Perl][net::ssh2] How to keep the ssh connection while executing remote command

I'm working on a perl script using net::ssh2 to make a SSH connection to a remote server.
(I'm working on windows)
I chose Net::SSH2 because i had to make some SFTP connections in the same script.
For now, my sftp connections work perfectly. The problem is when i try to execute a "long-duration" command. I mean a command which execution can take more than 30sec.
$ssh2 = Net::SSH2->new();
$ssh2->connect('HOST') or die;
if($ssh2->auth(username=>'USER', password=>'PSWD'))
{
$sftp = Net::SFTP::Foreign->new(ssh2=>$ssh2, backend=>'Net_SSH2');
$sftp->put('local_path', 'remote_path');
$channel=$ssh2->channel();
##
$channel->shell('BCP_COMMAND_OR_OTHER_PERL_SCRIPT');
# OR (I tried both, both failed :( )
$channel->exec('BCP_COMMAND_OR_OTHER_PERL_SCRIPT');
##
$channel->wait_closed();
$channel->close();
print "End of command";
$sftp_disconnect();
}
$ssh2->disconnect();
When i execute this script, the connection is successfull, the file is correctly sent but the execution is not (completely) performed. I mean, I think the command is sent for execution but terminated immediatly or not sent at all, i'm not sure.
What i want is the script waits until the command is completly finished before disconnect everything (just because sometimes, i need to get the result of the command execution)
Does anyone know how to solve this? :( The cpan documentation is not very explicit for this
Thanks!
PS: I'm open to any remarks or suggestion :)
Edit: After some test, i can say that the command is sent but is interrupted. My test was to start another perl script on the remote server. This script writes in a flat file. In this test, the script is started, the file is half-filled. I mean, the file is brutaly stopped in the middle.
In the other hand, when i performed a "sleep(10)" just after the "$channel->exec()", the script goes to the end successfully.
Problem is, that I can't write a "sleep(10)" (i don't know if it will take 9 or 11 seconds (or more, you see my point)
You can try using Net::SSH::Any instead.
It provides a higher level and easier to use API and can use Net::SSH2 or Net::OpenSSH to handle the SSH connection.
For instance:
use Net::SSH::Any;
my $ssh = Net::SSH::Any->new($host, user => $user, password => $password);
$ssh->error and die $ssh->error;
my $sftp = $ssh->sftp;
$sftp->put('local_path', 'remote_path');
my $output = $ssh->capture($cmd);
print "command $cmd output:\n$output\n\n";
$sftp->put('local_path1', 'remote_path1');
# no need to explicitly disconnect, connections will be closed when
# both $sftp and $ssh go out of scope.
Note that SFTP support (via Net::SFTP::Foreign) has been added on version 0.03 that I have just uploaded to CPAN.

How to run SSH commands using Net::SSH::Perl?

I don't know if I managed to install Net::SSH::Perl module successfully but I can't seem to be able to run the following code:
my $ssh = Net::SSH::Perl->new($remote_host);
$ssh->login($username, $password);
print "login done", "\n";
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
I am able to login but cannot print the $out. I keep getting this error:
Use of uninitialized value $out in string at test_ssh.pl line 28.
Line 28 refers to print "$out", "\n";.
I am running this code on Cygwin. What should I do now?
EDIT:
I got the following error msg when I ran my $ssh = Net::SSH::Perl->new($remote_host, options => ["Debug yes"]);:
Use of uninitialized value $out in string at test_ssh.pl line 29 (#1)
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.
EDIT2:
Here's my full code
use strict;
use warnings;
use Net::SSH::Perl;
my $remote_host = '<host ip address>';
my $password = 'pass';
my $username = 'user';
my $cmd = 'copy run tftp:<my own ip address>';
warn "Starting SSH Services:...";
my $ssh = Net::SSH::Perl->new($remote_host, debug => 1);
print "done", "\n";
warn "Starting Login:...";
$ssh->login($username, $password);
print "login done", "\n";
warn "Starting command:...";
#$ssh->cmd($cmd);
#my($stdout, $stderr, $exit) = $ssh->cmd($cmd);
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
The error message on "print "$out","\n";" line:
<Computername>: channel 1: new [client-session]
<Computername>: Requesting channel_open for channel 1.
<Computername>: Entering interactive session.
<Computername>: Channel open failure: 1: reason 4:
Use of uninitialized value $out in string at test_ssh.pl line 29.
LAST EDIT: I decided to use Net::Appliance::Session to login via SSH to the network devices instead. it's a lot easier to use than Net::SSH::Perl.
Please show more of your code. What is the value of $cmd?
Note that the login method doesn't perform a login: it merely stores the username and password to be used when the connection is set up for each cmd call.
The correct way of enabling debugging messages is
my $ssh = Net::SSH::Perl->new($remote_host, debug => 1);
This will give you trace information from the cmd method which should say, amongst other things
Sending command: xxx
Entering interactive session.
and should give you some clues about what is going wrong.
Your debug output shows the problem. Looking at SSH2.h, open failure reason 4 is SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED. Your username and password are incorrect.
Net::SSH::Perl does support login via username/password, I have a working example, I just got this to work. I used the code from above and took out the Double Quotes (" ") and used single quotes (' ') instead. And "debug => 1" works for debugging the code when having issues. It will display info to you when you try to login if the debug option is set.
I am connecting to a Win32-OpenSSH SSHD server based on Windows Powershell very similar to BSDLinux SSHD server with SFTP support. Supports same Linux style based connection.
I have been trying all other SSH modules all day. Hopefully someone can use this code to just run a command and get the output if required.
You can install Net::SSH::Perl with "cpan -i module-name"
use Net::SSH::Perl;
my $host = 'testmachine.acme.local'; #Or just IP Address
my $user = 'domain\username'; #Or just username
my $pass = 'Password#123';
my $cmd = 'dir C:\\Windows\\';
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new($host, debug => 1);
$ssh->login($user, $pass);
my ($out, $err, $exit) = $ssh->cmd($cmd);
print "$out", "\n";
Net::SSH::Perl does not support login via username/password only via interactive password entry or public key. See this post for more information.
http://www.perlmonks.org/?node_id=590452