Pages

Showing posts with label Perl. Show all posts
Showing posts with label Perl. Show all posts

1/25/2012

Script to push config changes to switches and routers.

Perl::Cisco::Script to push config changes to switches and routers.


#reconfig.pl
#
#############
use Net::Telnet;
#
my $list = "./list.txt";
my $cmd = "./cmds.txt";
my $login = "config";
my $password = "XXXXXXXXXX";
open HOSTS, "<", $list or die "$list not found!";
    my @all = ;
close HOSTS;
open CMDS, "<", $cmd or die "$cmd not found!";
    my @todo = ;
close CMDS;
###############
foreach $host (@all) {
$host =~ s/^\s+//;
$host =~ s/\s+$//;
my $outfile = "./$host-log.txt";
open OUT, ">", $outfile or die "Unable to create $outfile!";
print $host;
 if ($host =~ m/#/i) { #skip
  next;
 }
 print OUT "HOST=$host\n";
 $telnet = new Net::Telnet ( 
     Timeout=>15,
  Errmode=> sub{&ConnErr},
  Prompt => '/.*#$/');
 $telnet->open($host);
 $telnet->login($login, $password);
 foreach $task (@todo) {
  if ($task =~ m/#/i) { #skip
   next;
   }
  print OUT " -> $task  <-\t";
  @result = $telnet->cmd(String =>$task, Prompt => '/.*#$/');
  $telnet->waitfor('/#/');
  print OUT @result;
  print OUT "\r\n";
  foreach $line (@result) {
   if (($line =~ m/%/i)or($line =~ m/Translating/i)) { #Woah there!
    print OUT "ERROR:  Terminating\r\n";
    print "ERROR:  Check Log\r\n";
    exit;
   }
  }
  $telnet->waitfor('/#/');
 } #foreach task
print OUT "----------------------------------------\r\n";
#$telnet->waitfor('/#/');
close OUT;
} #foreach host

#END MAIN

################
sub ConnErr {
    print OUT "ERROR:  Connection Failed to $host\r\n";
    print OUT "----------------------------------------\r\n";
    next;
}
################

3/27/2011

AD Attributes Reference

ADSI & LDAP in scripts is very powerful, but there are so many little details to get right. There are often ways to make a script to see all your options, but sometimes it's good to be able to just look up what exactly attribute names are or see a list of them all.
Here on MSDN

1/24/2011

WSUS: Microsoft Windows Server Update Service

The MMC for WSUS leaves much to be desired for reporting. It'd be nice to be able to print or at least export the view that lists the clients and their status. So it can be used to figure out which clients are missing or what servers might be configured there still that no longer exist.
The script below will help. It generates a list of server machine accounts from AD and then exports the list from WSUS and then generates lists for review.
#LIST-AUDIT.PS1
#Export list of server accounts from AD, export WSUS clients, compare
#
#Define variables
$WSUSserver = 'PRIWSUS02'
$serverlist = 'c:\audit\data\servers.txt'
$WSUSList = 'c:\audit\data\WSUS.txt'
$InWSUS = 'c:\audit\data\OK-Servers-on-WSUS-list.txt'
$NotInWSUS = 'c:\audit\report\REVIEW-Servers-not-on-WSUS-list.txt'
$allservers = 'c:\audit\data\allservers.txt'
$WSUSorphans = 'c:\audit\report\REVIEW-WSUS-item-not-on-Servers-list.txt'
#Initialize files
New-Item $serverlist -Type file -Force >$nul
New-Item $WSUSList -Type file -Force >$nul
New-Item $InWSUS -Type file -Force >$nul
New-Item $NotInWSUS -Type file -Force >$nul
New-Item $allservers -Type file -Force >$nul
New-Item $WSUSorphans -Type file -Force >$nul
#Get list of servers from AD
$strCategory = "computer" 
$strOS = "Windows*Server*"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher 
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("OperatingSystem=$strOS")
$colProplist = "dnshostname"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults) 
{$objComputer = $objResult.Properties;  
$objComputer.dnshostname >> $serverlist}
#Get WSUS list
function Get-WSUSComputers()
{
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($WSUSserver,$false)
$wsus.GetComputerTargets()
}
Get-WSUSComputers | Sort FullDomainName |`
Select FullDomainName | `
Out-File -FilePath $WSUSList -Force
$Servers = get-content $ServerList
$WSUS = get-content $WSUSList
#compare lists
Foreach ($Server in $Servers)
{$Server = $Server.tolower()
$Server = $Server + (" " * (79 - $Server.Length))
Add-content $allservers $Server
If ($WSUS -contains $Server)
{ Add-content $InWSUS $Server }
Else
{ Add-content $NotInWSUS $Server }
}
$ADList = get-content $allservers
Foreach ($Server in $WSUS)
{
If ($ADList -contains $Server)
{ write-host "ok" >$nul }
Else
{ Add-content $WSUSorphans $Server }
}

10/13/2008

Cisco::SNMP::IP Accounting


Gathering IP accounting information from a router via SNMP.
Cisco document with details about SNMP calls to gather MAC table and IP accounting tables from routers via SNMP.

Perl script to do this:



#!/usr/bin/perl
use SNMP_util;

$host = $ARGV[0];
chomp($host);
if ($host eq "") {
print "Host address (return = $defaultHost) ? ";
$host = <stdin>;
chomp($host);
}
if ($host eq "") { die "Usage: ipac [host address]\n"; }


print "Gathering data from $host . . .\n";

@accounting = snmpwalk ("public\@$host",".1.3.6.1.4.1.9.2.4.9");

my @src, @dest, $pkts, $bytes;

foreach $line (@accounting) {
($pre, $data) = split (/\:/, $line);
@mib = split(/\./, $pre);
if ($mib[1] eq "1") { push (@src, $data);}
elsif ($mib[1] eq "2") { push (@dest, $data);}
elsif ($mib[1] eq "3") { push (@pkts, $data);}
elsif ($mib[1] eq "4") { push (@bytes, $data);}
elsif ($mib[1] eq "5") { last;}
else { print "unrecognized data\n";}
}

my $index = 1;


open (OUT, ">", "output.html");
open (CSV, ">", "output.csv");

print OUT "<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\" /></head><body><table border=\"1\" bordercolor=\"black\">";
print OUT "<h2>$host IP Accounting</h2><a href=\"output\.csv\" target=\"_blank\">Open in Excel</a>";
print CSV "$host IP Accounting\n";
print OUT "<tr><th>Source</th><th>Destination</th><th>Bytes</th><th>Packets</th></tr>\n";
print CSV "Source,Destination,Bytes,Packets\n";

foreach $from (@src) {
print OUT "<tr><td>$src[$index]</td><td>$dest[$index]</td><td>$bytes[$index]</td><td>$pkts[$index]</td></tr>\n";
print CSV "$src[$index],$dest[$index],$bytes[$index],$pkts[$index]\n";
$index++;
}

print OUT "</table></body></html>\n";

close OUT;
close CSV;

`output.html`
#
#

9/07/2007

Perl::Script::Cleanup Old Files


The following script will accept a list of folders and recursively look through each one for files older than a specified number of days.
A parameter file is used to provide input so it can be flexible after packaging with PerlPackager.

#cleanup.pl
use File::Find;
#get parameters
open (PRM, ";
close (PRM);
my $folder = $prm[0];
chomp $folder;
my @folder = split(/,/,$folder);
my $limit = $prm[1];
chomp $limit;
#Create log folder if it does not exist
if (not(-e "cleanup\\.")) {
mkdir ("cleanup");
}
#Name Log File
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime();
$m = sprintf("%0.2i", $mon+1);
$d = sprintf("%0.2i", $mday);
$y = $year + 1900 ;
$yy = substr($y, -2, 2);
$yy = sprintf("%0.2i", $yy);
$hh = sprintf("%0.2i", $hour);
$mm = sprintf("%0.2i", $min);
$ss = sprintf("%0.2i", $sec);
$T = "$y$m$d$hh$mm$ss" ;
$logfile=".\\cleanup\\$T.log";
open(LOG, ">$logfile");
print LOG "Cleanup run: $m\/$d\/$y $hh:$mm:$ss\n Folders: @folder\n Delete older than: $limit days\n";
print LOG "The following files, if any, have been deleted:\n";
find(\&CheckFile, @folder);
sub CheckFile {
if (not(-d $_)) {
if ($limit < (-M $_)) { $current = $File::Find::name; $current =~ tr/\//\\\\/; unlink $_; print LOG " $current\n"; } } } close (LOG);

The parameter file is below. It is setup to purge it's own log folder (.\cleanup) after the same number of days.

.\cleanup,c:\dev\purge\test\bak\1,c:\dev\purge\test\bak\2
10
#line 1 = comma separated list of folders to recursively search for old files.
#line 2 = number of days after which to delete files.

Perl::File Testing



# -o $file true if owned by EUID
# -e $file exists
# -z $file zero file
# -s $file non-zero file, returns size
# -r $file readable
# -w $file writeable
# -x $file executable
# -f $file plain file
# -d $file directory
# -l $file symbolic link
# -p $file named pipe or FIFO
# -S $file socket
# -b $file block special file
# -c $file character special file
# -T $file text file
# -B $file binary file
# -u $file setuid
# -g $file setgid
# -k $file sticky
# -t $file true if opened to a tty
# -M $file age in days since modified
# -A $file age in days since last accessed
# -C $file age in days since inode changed

8/21/2007

Perl::Regular Expression::Matching Expression Variables



Match Variables
If a =~ match expression is true, the special variables $1, $2, ... will be the substrings that matched parts of the pattern in parenthesis -- $1 matches the first left parenthesis, $2 the second left parenthesis, and so on. The following pattern picks out three words separated by whitespace...

if ("this and that" =~ /(\w+)\s+(\w+)\s+(\w+)/) {

## if the above matches, $1=="this", $2=="and", $3=="that"

This is a nice way to parse a string -- write a regular expression for the pattern you expect putting parenthesis around the parts you want to pull out. Only use $1, $2, etc. when the if =~ returns true. Other regular-expression systems use \1 and \2 instead of $1 $2, and Perl supports that syntax as well. There are three other special variables: $& (dollar-ampersand) = the matched string, $` (dollar-back-quote) = the string before what was matched, and $' (dollar-quote) = the string following what was matched.

The following loop rips through a string and pulls out all the email addresses. It demonstrates using a character class, using $1 etc. to pull out parts of the match string, and using $' after the match.

$str = 'blah blah nick@cs.stanford.edu, blah blah balh billg@microsoft.com blah blah';

while ($str =~ /(([\w._-]+)\@([\w._-]+))/) { ## look for an email addr
print "user:$2 host:$3 all:$1\n"; ## parts of the addr
$str = $'; ## set the str to be the "rest" of the string
}

output:
user:nick host:cs.stanford.edu all:nick@cs.stanford.edu
user:billg host:microsoft.com all:billg@microsoft.com


Thanks to: http://cslibrary.stanford.edu/108/EssentialPerl.html

4/10/2007

Perl::Screen Scraping


Required: MRTG Graphing for "source records remaining" of replica on Data Domain DDR appliance.

Problem: The replication statistics are not exposed via SNMP.

Workaround: Create external monitoring script to http to the device and grab this stat out of the html table that we are manually checking it from now.

I used PAR to package this into an EXE so I don't even need to screw with Perl modules on the MRTG/Web server.

Perl code:
####################################################
# checkrep.pl
#
# MRTG External Monitoring Script
# to return Records Remaining to be replicated
# for specific host & replication destination
####################################################

use Socket; # include Socket module
require 'tcp.pl'; # file with Open_TCP routine
use HTML::TableExtract; # Module to parse HTML

##########################################
#
# Parameters for customization below:
#
##########################################

##########################################
# Host to query

my $host="DDR05";

##########################################
# Replication Destination

$Query="dir://ddr02.usa.mydomain.com/backup/rep1";

##########################################
#
# Don't mess with stuff below here
#
##########################################


my $time = localtime;
open (LOG, '>checkrep.log');

#open (OUT, '>replication.html');


print LOG "\n----------\n$time\n";

##########################################
#Authenticate

open_TCP('F', $host, 80);
print LOG "\n----------\nLOGON-\n";
print F "POST /cgi-bin/auth.pl HTTP/1.0\n";
print F "User-Agent: Mozilla/1.1N (X11; I; SunOS 5.3 sun4m)\n";
print F "Accept: */*\n";
print F "Accept: image/gif\n";
print F "Accept: image/x-xbitmap\n";
print F "Accept: image/jpeg\n";
print F "Accept: text/javascript\n";
print F "Content-type: application/x-www-form-urlencoded\n";
print F "Content-length: 31\n";
print F "\n";
print F "user=TESTLOGON&password=********\n";

# get the HTTP response line
my $the_response=;
print LOG $the_response;

# get the header data
my %header;
while(=~ m/^(\S+):\s+(.+)/) {
$header{$1} = $2;
print LOG "$1: $2\n";
}

# get the entity body
print LOG while ();

# close (F);


##########################################
#Open Main (create cookie)

open_TCP('F', $host, 80);
print LOG "\n----------\nOPEN MAIN-\n";
# request the path of the document to get
print F "GET $header{'Location'} HTTP/1.0\n";
print F "Accept: */*\n";
print F "User-Agent: Mozilla/1.1N (X11; I; SunOS 5.3 sun4m)\n";
print F "Connection: Keep-Alive\n";
print F "\n";

# get the HTTP response line
$the_response=;
print LOG $the_response;

# get the header data
while(=~ m/^(\S+):\s+(.+)/) {
$header{$1} = $2;
print LOG "$1: $2\n";
}

my $Cookie = $header{'Set-Cookie'};


# get the entity body
print LOG while ();


# close the network connection
close(F);

##########################################
#Open Page
open_TCP('F', $host, 80);
print LOG "\n----------\nOPEN REPLICATION PAGE-\n";
print F "GET /view.cgi?ref=replication.gui HTTP/1.0\n";
print F "Accept: */*\n";
print F "User-Agent: Mozilla/1.1N (X11; I; SunOS 5.3 sun4m)\n";
print F "Connection: Keep-Alive\n";
print F "Cookie: $Cookie\n\n";

# get the HTTP response line
$the_response=;
print LOG $the_response;

# get the header data
while(=~ m/^(\S+):\s+(.+)/) {
print LOG "$1: $2\n";
}

# get the entity body
# print OUT while ();
@line = ;

# close the network connection
close(F);

##########################################
#Logout

# Test to see if session is still logged on
# e.g. http://atlddr05/view.cgi?ref=main.gui&session=14

open_TCP('F', $host, 80);
print LOG "\n----------\nLOGOUT-\n";
print F "POST /logout.cgi HTTP/1.0\n";
print F "User-Agent: Mozilla/1.1N (X11; I; SunOS 5.3 sun4m)\n";
print F "Accept: */*\n";
print F "Accept: image/gif\n";
print F "Accept: image/x-xbitmap\n";
print F "Accept: image/jpeg\n";
print F "Accept: text/javascript\n";
print F "Content-type: application/x-www-form-urlencoded\n";
print F "Content-length: 0\n";
print F "Pragma: no-cache\n";
print F "Cookie: $Cookie\n\n";

# get the HTTP response line
$the_response=;
print LOG $the_response;

# get the header data
while(=~ m/^(\S+):\s+(.+)/) {
$header{$1} = $2;
print LOG "$1: $2\n";
}
# get the entity body
print LOG while ();

print LOG "\n----------\nEND\n----------\n";
close (F);
close (LOG);
close (OUT);

##########################################
# Parse HTML


#use Data::Dumper;

foreach $line (@line) {
$line =~ s/\x0d{0,1}\x0a{0,1}\Z/ /s;
}

$html_string = join ('',@line);

$te = HTML::TableExtract->new( headers => ['Destination', 'Source Records Remaining'] );
$te->parse($html_string);

#print Dumper $te;
#print "\n";

foreach $ts ($te->tables) {
foreach $row (@$ts) {
# print join(',', @$row), "\n";
($Null,$Destination,$Null,$Null,$Null,$Null,$Null,$SourceRecordsRemaining,$Null,$Null) = @$row;
$Result{$Destination} = $SourceRecordsRemaining;
}
}

$RecordsRemaining = $Result{$Query};

$RecordsRemaining =~ s/,//;


##########################################
# Return Results

$Results = "$RecordsRemaining\n$RecordsRemaining\nNA\n$host\\$Query\n";

print $Results;



#The external command must return 4 lines of output:

#Line 1 - current state of the first variable, normally 'incoming bytes count'
#Line 2 - current state of the second variable, normally 'outgoing bytes count'
#Line 3 - string (in any human readable format), telling the uptime of the target.
#Line 4 - string, telling the name of the target



##########################################
# END
##########################################

MRTG - External Monitoring Scripts


Having a bit of fun lately working with MRTG to graph "non-standard" stats from external monitoring scripts.
MRTG.CFG
RunAsDaemon: yes
#RunAsDaemon: no
Interval: 60
EnableIPv6: no
WorkDir: c:\inetpub\wwwroot\mrtg

Target[DDR05]: `c:\monitor\checkrep.exe`
MaxBytes[DDR05]: 500000
Options[DDR05]: gauge,growright,nopercent,noo
XSize[DDR05]: 600
YSize[DDR05]: 175
PNGTitle[DDR05]: DDR05->DDR02 Replication Status
LegendI[DDR05]: Records:
Ylegend[DDR05]: Records
ShortLegend[DDR05]: records  
Title[DDR05]: Data Domain Replication Status
PageTop[DDR05]: <*h1>Source Records Remaining - DDR05->DDR02