Added controller states to the processes, added image specific processing to all processes, reinstated registry extraction and included a few new scripts to draw information.

Signed-off-by: Alex Ebadirad <aebadirad@42six.com>
This commit is contained in:
Alex Ebadirad 2012-02-10 09:08:39 -07:00
parent ac8d3b75a7
commit 6b5fa72de2
12 changed files with 416 additions and 37 deletions

View File

@ -13,6 +13,7 @@ import java.util.logging.Logger;
import java.util.*;
import java.io.File;
import java.io.IOException;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -37,16 +38,21 @@ public class Chrome {
}
public void getchdb(int image){
public void getchdb(List<String> image, IngestImageWorkerController controller){
try
{
Case currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase tempDb = currentCase.getSleuthkitCase();
List<FsContent> FFSqlitedb;
Map<String, Object> kvs = new LinkedHashMap<String, Object>();
Map<String, Object> kvs = new LinkedHashMap<String, Object>();
String allFS = new String();
for(String img : image)
{
allFS += " and fs_obj_id = '" + img + "'";
}
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE 'History' AND parent_path LIKE '%Chrome%' and fs_obj_id = '" + image + "'");
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE 'History' AND parent_path LIKE '%Chrome%'" + allFS);
FFSqlitedb = tempDb.resultSetToFsContents(rs);
ChromeCount = FFSqlitedb.size();
@ -58,7 +64,11 @@ public class Chrome {
String temps = currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db";
String connectionString = "jdbc:sqlite:" + temps;
ContentUtils.writeToFile(FFSqlitedb.get(j), new File(currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db"));
File dbFile = new File(temps);
if (controller.isCancelled() ) {
dbFile.delete();
break;
}
try
{
dbconnect tempdbconnect = new dbconnect("org.sqlite.JDBC",connectionString);
@ -91,6 +101,7 @@ public class Chrome {
}
j++;
dbFile.delete();
}
}
catch (SQLException ex)
@ -122,6 +133,10 @@ public class Chrome {
String connectionString = "jdbc:sqlite:" + temps;
ContentUtils.writeToFile(FFSqlitedb.get(j), new File(currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db"));
File dbFile = new File(temps);
if (controller.isCancelled() ) {
dbFile.delete();
break;
}
try
{
dbconnect tempdbconnect = new dbconnect("org.sqlite.JDBC",connectionString);
@ -182,6 +197,10 @@ public class Chrome {
String connectionString = "jdbc:sqlite:" + temps;
ContentUtils.writeToFile(FFSqlitedb.get(j), new File(currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db"));
File dbFile = new File(temps);
if (controller.isCancelled() ) {
dbFile.delete();
break;
}
try
{
dbconnect tempdbconnect = new dbconnect("org.sqlite.JDBC",connectionString);

View File

@ -4,6 +4,7 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import java.util.List;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
/**
@ -16,27 +17,27 @@ public class ExtractAll {
}
public boolean extractToBlackboard(IngestImageWorkerController controller, int image){
public boolean extractToBlackboard(IngestImageWorkerController controller, List<String> imgIds){
controller.switchToDeterminate(3);
try{
// Will make registry entries later, comment out for DEMO ONLY
// ExtractRegistry eree = new ExtractRegistry();
//eree.getregistryfiles();
ExtractRegistry eree = new ExtractRegistry();
eree.getregistryfiles(imgIds, controller);
controller.switchToDeterminate(3);
Firefox ffre = new Firefox();
ffre.getffdb(image);
ffre.getffdb(imgIds, controller);
controller.progress(1);
if (controller.isCancelled())
return true;
Chrome chre = new Chrome();
chre.getchdb(image);
chre.getchdb(imgIds, controller);
controller.progress(2);
if (controller.isCancelled())
return true;
ExtractIE eere = new ExtractIE(image);
ExtractIE eere = new ExtractIE(imgIds, controller);
eere.parsePascoResults();
controller.progress(3);
if (controller.isCancelled())

View File

@ -44,6 +44,8 @@ import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.KeyValueThing;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -74,8 +76,8 @@ public class ExtractIE { // implements BrowserActivity {
boolean pascoFound = false;
public ExtractIE(int image) {
init(image);
public ExtractIE(List<String> image, IngestImageWorkerController controller) {
init(image, controller);
}
//@Override
@ -83,7 +85,7 @@ public class ExtractIE { // implements BrowserActivity {
return IE_PASCO_LUT;
}
private void init(int image) {
private void init(List<String> image, IngestImageWorkerController controller) {
final Case currentCase = Case.getCurrentCase();
final String caseDir = Case.getCurrentCase().getCaseDirectory();
PASCO_RESULTS_PATH = caseDir + File.separator + "recentactivity" + File.separator + "results";
@ -111,9 +113,13 @@ public class ExtractIE { // implements BrowserActivity {
resultsDir.mkdirs();
Collection<FsContent> FsContentCollection;
indexDatQueryStr = indexDatQueryStr; // + " and fs_obj_id = '" + image + "'";
tempDb = currentCase.getSleuthkitCase();
ResultSet rs = tempDb.runQuery(indexDatQueryStr);
String allFS = new String();
for(String img : image)
{
allFS += " and fs_obj_id = '" + img + "'";
}
ResultSet rs = tempDb.runQuery(indexDatQueryStr + allFS);
FsContentCollection = tempDb.resultSetToFsContents(rs);
rs.close();
rs.getStatement().close();
@ -131,6 +137,10 @@ public class ExtractIE { // implements BrowserActivity {
//indexFileName = "index" + Long.toString(bbart.getArtifactID()) + ".dat";
temps = currentCase.getTempDirectory() + File.separator + indexFileName;
File datFile = new File(temps);
if (controller.isCancelled() ) {
datFile.delete();
break;
}
try {
ContentUtils.writeToFile(fsc, datFile);
}
@ -235,7 +245,6 @@ public class ExtractIE { // implements BrowserActivity {
if(url.length > 1)
{
user = url[0];
realurl = url[1];
realurl = realurl.replace("Visited:", "");
realurl = realurl.replace(":.*:", "");

View File

@ -11,9 +11,9 @@ import java.sql.SQLException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.modules.InstalledFileLocator;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -30,13 +30,18 @@ public class ExtractRegistry {
public void getregistryfiles(){
public void getregistryfiles(List<String> image, IngestImageWorkerController controller){
try
{
Case currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase tempDb = currentCase.getSleuthkitCase();
String allFS = new String();
for(String img : image)
{
allFS += " and fs_obj_id = '" + img + "'";
}
List<FsContent> Regfiles;
ResultSet rs = tempDb.runQuery("select * from tsk_files where lower(name) = 'ntuser.dat' OR lower(parent_path) LIKE '%/system32/config%' and (name = 'system' OR name = 'software' OR name = 'SECURITY' OR name = 'SAM' OR name = 'default')");
ResultSet rs = tempDb.runQuery("select * from tsk_files where lower(name) = 'ntuser.dat' OR lower(parent_path) LIKE '%/system32/config%' and (name = 'system' OR name = 'software' OR name = 'SECURITY' OR name = 'SAM' OR name = 'default')" + allFS);
Regfiles = tempDb.resultSetToFsContents(rs);
int j = 0;
@ -54,7 +59,7 @@ public void getregistryfiles(){
//Now fetch the results, parse them and the delete the files.
if(regSuccess)
{
//Delete index<n>.dat file since it was succcessfully by Pasco
//Delete dat file since it was succcessfully by Pasco
regFile.delete();
}
j++;
@ -73,7 +78,7 @@ public void getregistryfiles(){
}
}
//Simple wrapper to JavaSystemCaller.Exec() to execute pasco2 jar
// TODO: Hardcoded command args/path needs to be removed. Maybe set some constants and set env variables for classpath
// I'm not happy with this code. Can't stand making a system call, is not an acceptable solution but is a hack for now.
private boolean executeRegRip(String regFilePath, int fileIndex)
@ -94,7 +99,7 @@ public void getregistryfiles(){
}
if(regFilePath.toLowerCase().contains("ntuser"))
{
type = "ntuser";
type = "autopsy";
}
if(regFilePath.toLowerCase().contains("default"))
{

View File

@ -16,6 +16,7 @@ import java.lang.*;
import java.util.*;
import java.io.File;
import java.io.IOException;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute;
@ -38,14 +39,20 @@ public class Firefox {
}
public void getffdb(int image){
public void getffdb(List<String> image, IngestImageWorkerController controller){
//Make these seperate, this is for history
try
{
Case currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase tempDb = currentCase.getSleuthkitCase();
String allFS = new String();
for(String img : image)
{
allFS += " and fs_obj_id = '" + img + "'";
}
List<FsContent> FFSqlitedb;
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE '%places.sqlite%' and parent_path LIKE '%Firefox%' and fs_obj_id = '" + image + "'");
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE '%places.sqlite%' and parent_path LIKE '%Firefox%'" + allFS);
FFSqlitedb = tempDb.resultSetToFsContents(rs);
FireFoxCount = FFSqlitedb.size();
@ -54,12 +61,15 @@ public class Firefox {
int j = 0;
while (j < FFSqlitedb.size())
{
{
String temps = currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db";
String connectionString = "jdbc:sqlite:" + temps;
ContentUtils.writeToFile(FFSqlitedb.get(j), new File(currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db"));
File dbFile = new File(temps);
if (controller.isCancelled() ) {
dbFile.delete();
break;
}
try
{
@ -126,8 +136,13 @@ public class Firefox {
{
Case currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase tempDb = currentCase.getSleuthkitCase();
String allFS = new String();
for(String img : image)
{
allFS += " and fs_obj_id = '" + img + "'";
}
List<FsContent> FFSqlitedb;
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE '%cookies.sqlite%' and parent_path LIKE '%Firefox%' and fs_obj_id = '" + image + "'");
ResultSet rs = tempDb.runQuery("select * from tsk_files where name LIKE '%cookies.sqlite%' and parent_path LIKE '%Firefox%'" + allFS);
FFSqlitedb = tempDb.resultSetToFsContents(rs);
rs.close();
rs.getStatement().close();
@ -139,6 +154,10 @@ public class Firefox {
String connectionString = "jdbc:sqlite:" + temps;
ContentUtils.writeToFile(FFSqlitedb.get(j), new File(currentCase.getTempDirectory() + "\\" + FFSqlitedb.get(j).getName().toString() + j + ".db"));
File dbFile = new File(temps);
if (controller.isCancelled() ) {
dbFile.delete();
break;
}
try
{
dbconnect tempdbconnect = new dbconnect("org.sqlite.JDBC",connectionString);

View File

@ -18,14 +18,20 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.ingest.IngestImageWorkerController;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServiceImage;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.FileSystem;
/**
* Example implementation of an image ingest service
@ -57,10 +63,22 @@ public final class RAImageIngestService implements IngestServiceImage {
manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + image.getName()));
ExtractAll ext = new ExtractAll();
Case currentCase = Case.getCurrentCase(); // get the most updated case
SleuthkitCase sCurrentCase = currentCase.getSleuthkitCase();
//long imageId = image.getId();
Collection<FileSystem> imageFS = sCurrentCase.getFileSystems(image);
List<String> imgIds = new LinkedList<String>();
for(FileSystem img : imageFS ){
Long tempID = img.getId();
imgIds.add(tempID.toString());
}
try {
//do the work
ext.extractToBlackboard(controller, (int)image.getId());
//do the work for(FileSystem img : imageFS )
ext.extractToBlackboard(controller, imgIds);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error extracting recent activity", e);

72
thirdparty/rr/plugins/arunmru.pl vendored Normal file
View File

@ -0,0 +1,72 @@
#-----------------------------------------------------------
# runmru.pl
# Plugin for Registry Ripper, NTUSER.DAT edition - gets the
# RunMru values
#
# Change history
#
#
# References
#
#
# copyright 2008 H. Carvey
#-----------------------------------------------------------
package arunmru;
use strict;
my %config = (hive => "NTUSER\.DAT",
hasShortDescr => 1,
hasDescr => 0,
hasRefs => 0,
osmask => 22,
version => 20080324);
sub getConfig{return %config}
sub getShortDescr {
return "Gets contents of user's RunMRU key";
}
sub getDescr{}
sub getRefs {}
sub getHive {return $config{hive};}
sub getVersion {return $config{version};}
my $VERSION = getVersion();
sub pluginmain {
my $class = shift;
my $ntuser = shift;
#::logMsg("autospyrunmru");
my $reg = Parse::Win32Registry->new($ntuser);
my $root_key = $reg->get_root_key;
my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU';
my $key;
if ($key = $root_key->get_subkey($key_path)) {
#::rptMsg("RunMru");
::rptMsg($key_path);
#::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)");
my @vals = $key->get_list_of_values();
my %runvals;
my $mru;
if (scalar(@vals) > 0) {
foreach my $v (@vals) {
$runvals{$v->get_name()} = $v->get_data() unless ($v->get_name() =~ m/^MRUList/i);
$mru = $v->get_data() if ($v->get_name() =~ m/^MRUList/i);
}
::rptMsg("MRUList = ".$mru);
foreach my $r (sort keys %runvals) {
::rptMsg($r." ".$runvals{$r});
}
}
else {
::rptMsg($key_path." has no values.");
::logMsg($key_path." has no values.");
}
}
else {
::rptMsg($key_path." not found.");
::logMsg($key_path." not found.");
}
}
1;

7
thirdparty/rr/plugins/autopsy vendored Normal file
View File

@ -0,0 +1,7 @@
# List of plugins for the Registry Ripper
#-------------------------------------
# NTUSER.DAT
autopsy
autopsyrecentdocs
arunmru

68
thirdparty/rr/plugins/autopsy.pl vendored Normal file
View File

@ -0,0 +1,68 @@
#! c:\perl\bin\perl.exe
#-----------------------------------------------------------
# logonusername.pl
# Plugin for Registry Ripper, NTUSER.DAT edition - gets the
# "Logon User Name" value
#
# Change history
#
#
#
# copyright 2008 H. Carvey
#-----------------------------------------------------------
package autopsy;
use strict;
my %config = (hive => "NTUSER\.DAT",
hasShortDescr => 1,
hasDescr => 0,
hasRefs => 0,
osmask => 22,
version => 20080324);
sub getConfig{return %config}
sub getShortDescr {
return "Get user's Logon User Name value";
}
sub getDescr{}
sub getRefs {}
sub getHive {return $config{hive};}
sub getVersion {return $config{version};}
my $VERSION = getVersion();
sub pluginmain {
my $class = shift;
my $ntuser = shift;
::logMsg("||logonusername||");
my $reg = Parse::Win32Registry->new($ntuser);
my $root_key = $reg->get_root_key;
my $logon_name = "Logon User Name";
my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer';
my $key;
if ($key = $root_key->get_subkey($key_path)) {
my @vals = $key->get_list_of_values();
if (scalar(@vals) > 0) {
#::rptMsg("Logon User Name");
::rptMsg($key_path);
::rptMsg("LastWrite Time [".gmtime($key->get_timestamp())." (UTC)]");
foreach my $v (@vals) {
if ($v->get_name() eq $logon_name) {
::rptMsg($logon_name." = ".$v->get_data());
}
}
}
else {
::rptMsg($key_path." has no values.");
::logMsg($key_path." has no values.");
}
}
else {
::rptMsg($key_path." not found.");
::logMsg($key_path." not found.");
}
}
1;

View File

@ -0,0 +1,161 @@
#-----------------------------------------------------------
# recentdocs.pl
# Plugin for Registry Ripper
# Parses RecentDocs keys/values in NTUSER.DAT
#
# Change history
# 20100405 - Updated to use Encode::decode to translate strings
# 20090115 - Minor update to keep plugin from printing terminating
# MRUListEx value of 0xFFFFFFFF
# 20080418 - Minor update to address NTUSER.DAT files that have
# MRUList values in this key, rather than MRUListEx
# values
#
# References
#
#
# copyright 2010 Quantum Analytics Research, LLC
#-----------------------------------------------------------
package autopsyrecentdocs;
use strict;
use Encode;
my %config = (hive => "NTUSER\.DAT",
hasShortDescr => 1,
hasDescr => 0,
hasRefs => 0,
osmask => 22,
version => 20100405);
sub getShortDescr {
return "Gets contents of user's RecentDocs key";
}
sub getDescr{}
sub getRefs {}
sub getHive {return $config{hive};}
sub getVersion {return $config{version};}
my $VERSION = getVersion();
sub pluginmain {
my $class = shift;
my $ntuser = shift;
::logMsg("||recentdocs||");
my $reg = Parse::Win32Registry->new($ntuser);
my $root_key = $reg->get_root_key;
my $key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs";
my $key;
if ($key = $root_key->get_subkey($key_path)) {
#::rptMsg("RecentDocs");
#::rptMsg("**All values printed in MRUList\\MRUListEx order.");
::rptMsg($key_path);
::rptMsg("LastWrite Time ".gmtime($key->get_timestamp())." (UTC)");
# Get RecentDocs values
my %rdvals = getRDValues($key);
if (%rdvals) {
my $tag;
if (exists $rdvals{"MRUListEx"}) {
$tag = "MRUListEx";
}
elsif (exists $rdvals{"MRUList"}) {
$tag = "MRUList";
}
else {
}
my @list = split(/,/,$rdvals{$tag});
foreach my $i (@list) {
::rptMsg(" ".$i." = ".$rdvals{$i});
}
::rptMsg("");
}
else {
::rptMsg($key_path." has no values.");
::logMsg("Error: ".$key_path." has no values.");
}
# Get RecentDocs subkeys' values
my @subkeys = $key->get_list_of_subkeys();
if (scalar(@subkeys) > 0) {
foreach my $s (@subkeys) {
::rptMsg($key_path."\\".$s->get_name());
::rptMsg("LastWrite Time ".gmtime($s->get_timestamp())." (UTC)");
my %rdvals = getRDValues($s);
if (%rdvals) {
my $tag;
if (exists $rdvals{"MRUListEx"}) {
$tag = "MRUListEx";
}
elsif (exists $rdvals{"MRUList"}) {
$tag = "MRUList";
}
else {
}
my @list = split(/,/,$rdvals{$tag});
::rptMsg($tag." = ".$rdvals{$tag});
foreach my $i (@list) {
::rptMsg(" ".$i." = ".$rdvals{$i});
}
::rptMsg("");
}
else {
::rptMsg($key_path." has no values.");
}
}
}
else {
::rptMsg($key_path." has no subkeys.");
}
}
else {
::rptMsg($key_path." not found.");
}
}
sub getRDValues {
my $key = shift;
my $mru = "MRUList";
my %rdvals;
my @vals = $key->get_list_of_values();
if (scalar @vals > 0) {
foreach my $v (@vals) {
my $name = $v->get_name();
my $data = $v->get_data();
if ($name =~ m/^$mru/) {
my @mru;
if ($name eq "MRUList") {
@mru = split(//,$data);
}
elsif ($name eq "MRUListEx") {
@mru = unpack("V*",$data);
}
# Horrible, ugly cludge; the last, terminating value in MRUListEx
# is 0xFFFFFFFF, so we remove it.
pop(@mru);
$rdvals{$name} = join(',',@mru);
}
else {
# New code
$data = decode("ucs-2le", $data);
my $file = (split(/\00/,$data))[0];
# my $file = (split(/\00\00/,$data))[0];
# $file =~ s/\00//g;
$rdvals{$name} = $file;
}
}
return %rdvals;
}
else {
return undef;
}
}
1;

View File

@ -96,7 +96,7 @@ if ($config{file}) {
my %plugins = parsePluginsFile($config{file});
if (%plugins) {
logMsg("Parsed Plugins file.");
#logMsg("Parsed Plugins file.");
}
else {
logMsg("Plugins file not parsed.");
@ -110,8 +110,8 @@ if ($config{file}) {
if ($@) {
logMsg("Error in ".$plugins{$i}.": ".$@);
}
logMsg($plugins{$i}." complete.");
rptMsg("-" x 40);
#logMsg($plugins{$i}." complete.");
#rptMsg("-" x 40);
}
}
@ -206,7 +206,6 @@ used if no other filename given is \"plugins\\plugins\"\.
-s system name.....Server name (TLN support)
-u username........User name (TLN support)
-h.................Help (print this information)
Ex: C:\\>rr -r c:\\case\\system -f system
C:\\>rr -r c:\\case\\ntuser.dat -p userassist
C:\\>rr -l -c

7
thirdparty/rr/rr.pl vendored
View File

@ -255,7 +255,7 @@ sub go_Click {
logMsg("File: ".$env{ntuser});
logMsg("Environment set up.");
my %plugins = parsePluginsFile($pluginfile);
logMsg("Parsed Plugins file ".$pluginfile);
#logMsg("Parsed Plugins file ".$pluginfile);
if (scalar(keys %plugins) == 0) {
Win32::GUI::MessageBox($main,$ENV{USERNAME}.", the plugins file has no plugins!!.\r\n",
"Doh!!",16);
@ -277,8 +277,9 @@ sub go_Click {
Win32::GUI::DoEvents();
logMsg($err_cnt." plugins completed with errors.");
logMsg($plugins{$i}." complete.");
rptMsg("-" x 40);
#logMsg($plugins{$i}." complete.");
#rptMsg("-" x 40);
rptMsg("---");
}
$report->Append($err_cnt." plugins completed with errors.\r\n");
$status->Text("Done.");