I would like to read the contents of the Event Log on Windows using the Perl script. I can read the contents of the 'Application' Log. I can't read old logs - .evtx files. Can you advise me where I have a mistake?
$filename = "C:/Windows/System32/winevt/Logs/Archive-Application-2022-10-26-16-18-53-831.evtx";
if (-f $filename) {
printf "%s ... continue ...\n", $filename;
} else {
printf "PROBLEM\n";
exit -1;
}
$EventLog = new Win32::EventLog($filename) || die $!;
$EventLog->GetOldest($first) || die $!; # it dies here
EDIT:
Function GetOldest returns a RecordNumber. I tried UNC:
$filename = "\\\\<server>\\C\$\\Windows\\System32\\winevt\\Logs\\Archive-Application-2022-10-25-04-01-56-731.evtx";
... but the same error. The file exists but died on the GetOldest function. I haven't found something like $EventLog->errstr anywhere on the internet ...
https://metacpan.org/pod/Win32::EventLog
I tried a powerful thing: I canceled the error test:
originally : #$EventLog->GetOldest($first) || die $!;
now : $EventLog->GetOldest($first);
... and continue with the script; the script reads the contents of the .evtx file correctly.
Related
I've looked around here a bit and found similar questions but not exactly. If there is one, I apologize and please point me to it.
I have the following code. I'm trying to create a csv file of simply an ID pulled from a filename and the filename itself. This is the ENTIRE script.
use strict;
use warnings;
use File::Find;
find( \&findAllFiles, '.');
exit;
sub findAllFiles {
my #fp1;
my #fp2;
my $patId;
my $filename;
my $testvar = "hello again";
$filename = $File::Find::name;
if ($filename =~ /\.pdf$/) {
open (my $fh, '>', 'filenames.csv') or die "Failed to open - $!\n";
print $fh "starting...$testvar\n" or die "Failed to print to file - $!\n";
#fp1 = split('/', $filename);
#fp2 = split('_', $fp1[-1]);
$patId = $fp2[-1];
$patId =~ s/\.pdf$//;
print "Adding $patId, file = $filename\n";
print $fh "$patId,$filename\n" or die "File print error: $!";
close $fh or warn "close failed! - $!";
}
return;
}
The line that prints to the screen, prints perfectly.
If I take the file open/close and the first print statement out of the if block, it prints that line into the file, but not the data inside the block.
I've tried every combo I can think of and it doesn't work. I've alternated between '>' and '>>' since it clearly needs the append since it's looping over filenames, but neither works inside the if block.
Even this code above doesn't throw the die errors! It just ignores those lines! I'm figuring there's something obvious I'm missing.
Quoting File::Find::find's documentation:
Additionally, for each directory found, it will chdir() into that directory
It means that when you open inside findAllFiles, you are potentially opening a file filenames.csv inside a subdirectory of your initial directory. You can run something like find . -name filenames.csv from your terminal, and you'll see plenty of filenames.csv. You can change this behavior by passing no_chdir option to find:
find( { wanted => \&findAllFiles, no_chdir => 1}, '.');
(and additionally changing > for >> in your open)
However, personally, I'd avoid repeatedly opening and closing filenames.csv when you could open it just once before calling find. If you don't want to have your filehandle globally defined, you can always pass it as an argument to findAllFiles:
{
open my $fh, '>', 'filenames.csv' or die "Failed to open 'filenames.csv': $!";
find(sub { findAllFiles($fh) }, '.')
}
sub findAllFiles {
my ($fh) = #_;
...
filenames.csv will be created in the directory where the pdf is found, since find() changes directories as it searches. If that's not what you want, use an absolute path to open it (or open it before calling find, which seems like a better idea).
i need to watch files that fall under a directory.I have coded the below script in perl . but it is not doing what i want .
whenever a file or files arrives , it has to do a movement .
And then it has to keep watching files again.
the script should be running in background.
#!/usr/bin/perl
use warnings;
use File::Copy qw(move);
$src_dir = '/root/prasanna/dir';
$tgt_dir = '/root/prasanna/dir/dir1';
while (true) {
opendir( DIR, "/root/prasanna/dir" )
or die "Cannot open /root/prasanna/dir: $!\n";
my #Dircontent = readdir DIR;
close DIR;
my $items = #Dircontent;
if ( $items > 2 ) {
print "files available";
while ($items) {
print $items;
move $src_dir. '/' . $items, $tgt_dir . '/' . $items;
unlink $items;
}
}
else { sleep 50; }
}
The problem with the above code is
1. the if statement keeps on printing the 'files available' . goes on infinite loop , it doesnt watch for files again .even if i do operations on file, i dont knw how to make it look for files again.
2. the script doesnt run in background .
any help is highly appreciated . thanks beforehand.!
presuming you are running under Linux, use Linux::Inotify2...
use Linux::Inotify2;
# create an Inotify object
my $Inotify = Linux::Inotify2->new() or die "Fail: $!";
# choose which operations for which you wish to be notified
my $watchme = IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_TO; # defined and exported
$Inotify->watch('/root/prasanna/dir', $watchme, \&watcher) or die "Fail: $!";
while (1) {
$Inotify->poll;
}
sub watcher
{
# do something here
}
Note it can only monitor local filesystems (i.e. no NFS mounts)
If a file in a directory matches some nomenclature, then it is to be processed.
I have problem with the following piece of code:
if ($fichier =~ /0284\-\d{4}-\w{6}\.0284\.UPDREQ\.\d{4}\.\d{10}/)
{
my $msg = "Processing file is : $fichier \n";
Trace($EXP, __FILE__, __LINE__, "$msg");
}
if(!open (FILE, "< $fichier"))
{
my $cmd = "mv $REP_FLOTS/$fichier $REP_UPDREQ_ARCH/err_$fichier";
system("$cmd");
}
$lines++ while (<FILE>);
close FILE;
It is able to open and read the content sometimes and it fails in other times.
What am I missing in this code? Because it is working fine sometimes.
Why don't you ask system itself about what's going wrong? Variable $! holds last error for previous system call, so if open failed, just print it:
if(!open (FILE, "< $fichier"))
{
warn "unable to open '$fichier' for reading: $!\n";
my $cmd = "mv $REP_FLOTS/$fichier $REP_UPDREQ_ARCH/err_$fichier";
system("$cmd");
}
Im a beginner. I have written a perl script which does the following
-Create a directory under “/x01/abcd/abc_logs/abcd_Logs” by the current date, in the format of “YYYYMMDD” if it has not already been created.
i.e: if the script is run on “01st of jan 2013”, the directory “20130101” will be created under the said path. So whenever there is a need to inspect the logs always look for a directory by the current date.
-Check if the log file(s) have already been downloaded earlier within the same day, and if not log(s) will be downloaded to the TODAY’s directory.
Im having a hard time, coming up with a solution to print a message when there are no files in the share. This is of course when the user specify 2 or more files that are not there in the share. I know that this happens because there is a "die" statement in the "sub get_LOGS". I just cannot seem to understand how to return a message when all the files I specify do not happen to be in the share.
usage of this script is as follows
./abc_logs ....<file(n)>
following is the script.
my $LOGS_LOCAL_PATH = "/x02/abc/abcba2/";
chomp $LOGS_LOCAL_PATH;
my $LOGS_REM_PATH = "/x01/INT/abc/vabc2/";
chomp $LOGS_REM_PATH;
my $TODAY = `date +%Y%m%d`;
chomp $TODAY;
my #GETLOOP = #ARGV;
unless ($#ARGV >= 0) {
print "\nUsage: gtp_logs.pl <file1> <file2> <file3>.....<file(n)>\n\n";
exit;
}
system("clear");
unless ( -d "$LOGS_LOCAL_PATH"."$TODAY") {
print "Directory \"$TODAY\" doesn't exist. So creating the directory..!\n";
print "OK..Done.....!\n\n";
system("mkdir $LOGS_LOCAL_PATH/$TODAY");
}
else {
print "Directory already exists. Logs will be downloaded to ==> \"$LOGS_LOCAL_PATH$TODAY\".....!\n\n";
}
# if_DOWNLOADED($LOGS_LOCAL_PATH,$TODAY,#GETLOOP);
chdir("$LOGS_LOCAL_PATH"."$TODAY") || die "cannot cd to ($!)";
foreach my $GETL (#GETLOOP) {
my $is_downloaded = if_DOWNLOADED($LOGS_LOCAL_PATH,$TODAY,$GETL);
if(!$is_downloaded)
{
get_LOGS("172.25.70.221","abc","abc2","/x01/INT/abc",$GETL);
print "File \"$GETL\" downloaded to ==> \"$LOGS_LOCAL_PATH$TODAY\"\n\n";
}
else
{
print "File \"$GETL\" has already been Downloaded to ==> \"$LOGS_LOCAL_PATH$TODAY\"\n\n";
}
}
sub get_LOGS {
my $LOG_HOST = shift;
my $REM_USER = shift;
my $REM_PASSW = shift;
my $REM_PATH = shift;
my $REM_FILE = shift;
print "Connecting to the sftp share! Please wait....!\n";
my $sftp = Net::SFTP::Foreign->new($LOG_HOST, user => $REM_USER, password => $REM_PASSW);
$sftp->setcwd($REM_PATH) or die "unable to change cwd: " . $sftp->error;
print "OK. On the share! Downloading the file \"$REM_FILE\"...................!\n\n\n\n";
$sftp->error and die "Problem connecting to the share...!!!! " . $sftp->error;
$sftp->get($REM_FILE) or die "File does not seem to be present on the remote share. Please re-request..!!!" . $sftp->error;
return $REM_FILE;
}
sub if_DOWNLOADED {
my $DWD_FILE_PATH = shift;
my $DWD_DIR = shift;
my $DWD_FILE = shift;
if (-e "$DWD_FILE_PATH/$DWD_DIR/$DWD_FILE")
{
return 1;
}
else
{
return 0;
}
}
Please can someone help me finding a solution to this matter? Please try to use the same script and modify.
/V
Some comments to your code:
Use strict and warnings in order to catch lots of errors early.
Read some book on style (i.e. Damian Conway's Perl Best Practices). But in any case try to be consistent when naming variables, subroutines, and everything and also with their case.
When you have to use some calculated value in several places, try to calculate it once and save it in a variable.
Don't use subroutines for trivial things.
You don't need to call chomp on variables you have defined and that don't have a "\n" character at the end.
Opening a new SFTP connection for every file transfer is very inefficient. You can open just one at the beginning and use it for all the transfers.
And now, a simplified version of your script:
#!/usr/bin/perl
use strict;
use warnings;
my $host = "172.25.70.221";
my $user = "abc";
my $password = "abc1234321";
my $LOGS_LOCAL_PATH = "/x02/ABC/abc2";
my $LOGS_REM_PATH = "/x01/INT/abc/vim";
my $TODAY = `date +%Y%m%d`;
chomp $TODAY;
my $TODAY_LOCAL_PATH = "$LOGS_LOCAL_PATH/$TODAY";
my #files = #ARGV;
#files or die "\nUsage: gtp_logs.pl <file1> <file2> <file3>.....<file(n)>\n\n";
system("clear");
if ( -d $TODAY_LOCAL_PATH) {
print "Directory already exists. Logs will be downloaded to ==> \"$TODAY_LOCAL_PATH\".....!\n\n";
}
else {
print "Directory \"$TODAY\" doesn't exist. So creating the directory..!\n";
mkdir "$TODAY_LOCAL_PATH" or die "unable to create directory: $!\n";
print "OK..Done.....!\n\n";
}
chdir $TODAY_LOCAL_PATH or die "cannot cd to ($!)\n";
my $sftp = Net::SFTP::Foreign->new($host, user => $user, password => $password);
$sftp->error
and die "Problem connecting to the share...!!!! " . $sftp->error;
my $ok = 0;
my $failed = 0;
foreach my $file (#files) {
if (-e "$TODAY_LOCAL_PATH/$file") {
print "File \"$file\" has already been Downloaded to ==> \"$TODAY_LOCAL_PATH\"\n";
}
else {
if ($sftp->get("$LOGS_REM_PATH/$file")) {
print "File \"$file\" downloaded to ==> \"$TODAY_LOCAL_PATH\"\n";
$ok++;
}
else {
print "Unable to download file \"$file\" : " . $sftp->error . "\n";
$failed++;
}
}
}
print "$ok files have been downloaded, $failed files failed!\n\n";
I have a Perl script and I am trying to make it print out the value for $article when it errors. The script looks like:
eval{
for my $article($output =~ m/<value lang_id="">(.*?)<\/value>/g)
{
$article =~ s/ /+/g;
$agent->get("someurl");
$agent->follow_link(url_regex => qr/(?i:pdf)/ );
my $pdf_data = $agent->content;
open my $ofh, '>:raw', "$article.pdf"
or die "Could not write: $!";
print {$ofh} $pdf_data;
close $ofh;
sleep 10;
}
};
if($#){
print "error: ...: $#\n";
}
So if there is no .pdf file the code sends an error which is what I want. But what I need to know is it somehow possible to get the name of the $article that caused the error? I was trying to use some kind of global variable with no luck.
Why don't you put the eval inside the for loop? Something like this:
for my $article($output =~ m/<value lang_id="">(.*?)<\/value>/g)
{
$article =~ s/ /+/g;
eval{
# ...
}
if ($#) {
print STDERR "Error handling article: ", $article, " ", $!, "\n";
}
}
If that's your only problem, just declare my $article; before the eval, and remove the my from the for loop. But from your reply to Cornel Ghiban, I suspect it isn't.
Include the file name in the die>/ string:
open my $ofh, '>:raw', "$article.pdf" or die "Could not write '$article': $!";
I assume that you want to write and not read. Unless you have a permission issue or a full file system, a write is likely to succeed and you will never see an error.
Your script does not need to die, you can just set a flag or save message to the log or store error for late handling.
my #errors=();
................
open my $ofh, '>:raw', "$article.pdf" or do { push #errors,"$article: $!" };
if(-e $ofh) {
# work with the file
}
................
if(#errors) {
# do something
}