3dbc has asked for the wisdom of the Perl Monks concerning the following question:

Hi perl Monks,

Unfortunately we all don't have the privilege of working on linux or solaris all the time but still love to use perl to do everything! personally I hate powershell especially when window$ people tell me to use it instead of perl, vbscript is cumbersome, and batch files just plain suck most of the time because they aren't very extendable, robust or creative. There's a lot of published powershell scripts on this topic which read from a csv file that has hostnames and user id / passwords, which I could easily build into this, but just wanted to get something out there because a google search on "perl windows reboot" script returns nothing...

I wrote a quick and dirty reboot script, planning to expand it a bit more to parse log files, make net service calls, ping ip address to confirm each server is up before moving to the next depending on the underlying software dependencies which created the need for this in the first place, but trying to build in some basic error handling, which will help me expand this further. On my first go, I received a hickup from one of the servers complaining about:

The handle is invalid. Error communicating with PsExec service on Blah.Blah.Blah
When I logged onto the server I saw a whole bunch of dll errors, which usually happens after windows patches have been deployed but the server wasn't rebooted, so therefore psexec call didn't work...

I want to be able to process this output and if I don't get the response:

cmd started on Blah.Blah.Blah with process ID 4428.


then I want to terminate the program. I'm calling the command with a
print for qx|$externalExe 2>&1|;
How do I process this output within the perl script to exit gracefully (or try alternative methods) when an error is encountered? Perhaps I'm not totally understanding this 2>&1 part of my qx, can I read this output within the script?
Thanks!

Sample Code:
#!/usr/bin/perl use strict; use warnings; my @servers = qw( Blah.Blah.Blah Blah1.Blah.Blah Blah2.Blah.Blah Blah3.Blah.Blah Blah4.Blah.Blah ); foreach (@servers){ my $externalExe = qq(psexec.exe \\\\$_ ); $externalExe .= q(-u BLAH\foo -p secret -i -d cmd /c shutdown /r /f /t + 0); print "\n\nStarting external program...\n"; print for qx|$externalExe 2>&1|; # Executes the program, and prints it +'s output print "Program $externalExe run completed.\n"; sleep 360; }
- 3dbc

Replies are listed 'Best First'.
Re: SEQUENTIAL REBOOT ORDER WINDOW$
by Marshall (Canon) on Jan 19, 2018 at 02:22 UTC
    It would be helpful if you could post some code that I'm able to run on my single Win10 machine.

    Perhaps I'm not totally understanding this 2>&1 part of my qx, can I read this output within the script?
    This is a very standard command line syntax that redirects both the STDERR and STDOUT filehandles to the same output stream. This works on Unix and on Windows.

    On Windows, you can open a pipe to an external program, just like in Unix:

    #!/usr/bin/perl use strict; use warnings; open TASK, "tasklist 2>&1|" or die "cannot open pipe to tasklist"; while (<TASK>) { print; }
    Again, it would be helpful if you could "dumb down" the example to something that the Monks with Windows can run.
    tasklist is a standard Windows command line program that I believe you can run.
      That worked, now I just need to grep "invalid" within $_ and kill the perl script if it encounters an error with the reboots. When I redo the code, I'll post it here, but you definitely helped move me in the right direction. Thanks.
      - 3dbc
        updated the foreach section, you might have to move around some of the comments because I was experimenting with other commands like ipconfig to see if I can parse the output of a remote machine, which i can ;-) thankfully due to this post kicking my ass in the right direction!:
        sub getDOS { print "This is dollar 0 $_[0]\n\n"; open TASK, "$_[0] 2>&1|" or die "cannot open pipe to DOS"; my @return; while (<TASK>) { #chomp; #chop; #print; #return $_; push @return, $_; } return @return; } foreach (@servers){ my $externalExe = qq(psexec.exe \\\\$_ -u ); $externalExe .= $dev_cred . " -p "; #$externalExe .= $prod_pass . ' -i -d cmd /c shutdown /r /f /t 0'; $externalExe .= $dev_pass . ' ipconfig'; print "\n\n... Program START: \n\n $externalExe \n \n"; my @output = getDOS($externalExe); print "\n\nReturned output from DOS command:\n"; foreach(@output){ print; die if $_ =~ /$[Ee]rror/; die if $_ =~ /[Ii]nvalid/; } #wmic process call create "cmd /C > C:\temp\test.txt 2>&1 netstat. +exe -ano" #PsExec v2.2 - Execute processes remotely #Copyright (C) 2001-2016 Mark Russinovich #Sysinternals - www.sysinternals.com #The handle is invalid. #Error communicating with PsExec service on PR0235IPRT002: #print for qx|$externalExe 2>&1|; # Executes the program, and prin +ts it's output print "\n\n.... run complete ...\n"; sleep 360; }


        next goal is to make this asynchronous and get rid of the sleep command in the loop. I'm going to build in pings / and more psexec's where I parse the output to ensure the server is up before moving onto the next. Also going to include some net server stop commands to more gracefully stop some of the services before doing a forced shutdown.
        - 3dbc
Re: SEQUENTIAL REBOOT ORDER WINDOW$
by Anonymous Monk on Jan 17, 2018 at 04:01 UTC