APM: Process/System questions

Bakken, Tom - Temple, TX tom.bakken at tx.usda.gov
Fri Sep 17 11:06:51 CDT 2004


Some time ago I posted a problem I was having with a script that was
supposed to restart workstations but stalled when it hit certain PCs.  I
used Bill Raty's suggestion of the spawn subroutine.   I wasn't able to
get it to work and put it aside until I recently had more time and now
seem to have gotten it running.

Shutdown.exe has a known bug where if the workstation that's to be shut
down is at the Windows login screen, it will lock up.  Bill's solution
works around that problem by waiting 20 seconds and then continuing if
the workstation stalls.  Unfortunately, the system command returns a 0
exit status for success even if shutdown.exe stalls.  Is there any way
to capture the output from shutdown.exe which is "the device is not
ready"?  Either that or if the script does wait 20 seconds and fails,
can I test for that somehow?

I appreciate the help.

#############
#!perl -w
# Purpose:	Create a list of workstations, restart them and store
results in log file
# Notes:	Portablilty: shutdown switch to abort programs is /C on
Windows 2000 and /F on XP	

use strict;
use Text::ParseWords;		# Help for comma separated data
use POSIX 'strftime';		# Load function
use Time::Local;

# Create list of servers to analyze:

my $LogFile = 'WorkstationRestartLog.txt';
unless (open LOGFILE, "> $LogFile") {
  die "Cannot open $LogFile: $!";
}

my $LocalServer = 'MyServer';
my $Domain = 'MyDomain';
my $ServerFile = 'c:/bin/reboot/csv.log';
my $StateAbbrev = 'TX';
my @ListOfWorkstations = ();
my @MachineNameAndDomain = ();

GetWorkstations(\@ListOfWorkstations, $Domain, $LocalServer,
$ServerFile, $StateAbbrev);
my $Status;  

WorkstationRestart(\@ListOfWorkstations);		# Restart the
list of workstations

######################   Subroutines
########################################
sub GetHumanTime {
  my $TimeStamp = strftime("%m/%d/%Y %I:%M %p", localtime(time));
  return $TimeStamp;
}
sub spawn (&) {
  my ($CodeRef) = @_;
  my $pid;
  unless ($pid = fork) {
    $CodeRef->();		# Start the child process.  Make sure it
exits too!
    exit;
  }
  $SIG{CHLD} = "IGNORE";	# Make sure we don't have any ghost
processes.  Have perl do the waitpid
  return $pid;
}
sub GetWorkstations {
  my $ListOfWorkstationsArrayRef = shift;
  my $Domain = shift;
  my $LocalServer = shift;
  my $ServerFile = shift;
  my $StateAbbrev = shift;
  my $Status = system "csvde -f $ServerFile \
               -s $LocalServer.$Domain.one.usda.gov \
               -d \"ou=$StateAbbrev, dc=$Domain, dc=one, dc=usda,
dc=gov\" \
               -p subtree \
	       -r \"(&(Objectcategory=Computer)(objectClass=computer))\"
	       -l \"name, dNSHostName, description, operatingsystem,
whencreated, whenchanged\"";
  warn "Active Directory query failed: $!" unless $Status == 0;

  unless (open WORKSTATIONS, "$ServerFile") {
    die "Cannot open $ServerFile: $!";
  }
  while(<WORKSTATIONS>) {
    chomp;			# Remove ctrl+M
    s/\000//g;			# Remove null padding
    my @Fields = parse_csv($_);
    my ($DN, $Description, $DnsHostName, $OS, $Name, $WhenChanged,
$WhenCreated) = @Fields;
##print "$Name = \$Name\n";
    push @{$ListOfWorkstationsArrayRef}, join '|', $Name, $Description,
$DnsHostName,
           $OS, $WhenChanged, $WhenCreated;
  }
}			# End GetWorkstationUptime subroutine
sub WorkstationRestart {	# Copy files to server using a list of
machine names 
  my $MachineNameAndDomainArrayRef = shift;
  my $Count = 0;
  my $Error = 0;
  my $StartTime = GetHumanTime();
  print LOGFILE "                  Start: Computer Restart Log:
$StartTime\n\n";
  my $i = ();
  foreach $i (sort @{$MachineNameAndDomainArrayRef}) {
    unless (open LOGFILE, ">> $LogFile") {		# Close write
filehandle and open append
      die "Cannot open $LogFile: $!";
    }
    $Count++;
    my ($MachineName, $Domain) = split /\|/, $i;
#print "\$MachineName = $MachineName\n";
    next unless $MachineName;				# Skip blank
records
    print "$Count:	Attempting Reboot on: $MachineName\n";
    $Status = system "uptime \\\\$MachineName > /nul";
    unless ($Status == 0) {
      print LOGFILE "$Count	ALERT!!! Could not contact $MachineName.
Error: $?\n";
      print "$Count   ALERT!!! Could not contact $MachineName. Error:
$?\n";
      $Error++;
      next;
    }
print "Parent PID: $$\n";
#########    
    my $ChildPid = spawn {
     $Status = system "shutdown.exe -m \\\\$MachineName -F    -R -T 90";
# Windows XP
###     $Status = system "shutdown.exe \\\\$MachineName /C /Y /R /T:90";
# Windows 2K
###      $Status = system "uptime \\\\$MachineName > /nul";
      unless ($Status == 0) {
        print LOGFILE "$Count   ALERT!!! Could not restart $MachineName.
Error: $?\n";
        print  "$Count   ALERT!!! Could not restart $MachineName. Error:
$?\n";
        $Error++;
        next; 
      }
      my $TimeStamp = GetHumanTime();
      print LOGFILE "$Count	$MachineName successfully rebooted at
$TimeStamp\n";
      print "$Count	$MachineName successfully rebooted at
$TimeStamp\n";
    };				# Don't forget the semicolon here!!!!
###########
    sleep 20;			# Give uptime 20 seconds to run
    print "Child pid: $ChildPid\n";
    kill TERM => $ChildPid;	# Kill after that amount of time
  }		# End server loop
  my $EndTime = GetHumanTime();
  print LOGFILE "\n                   $Count Computer restarts
attempted.  $Error Failed.\n\n" . 
                "                   End: Computer Restart Log:
$EndTime\n" .
                '=' x 50 . "\n\n";
}				# End WorkstationRestart subroutine
sub parse_csv {
  return quotewords(",", 0, $_[0]);
}
###################

Tom Bakken



More information about the Austin mailing list