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

Hello everyone,

I am a user of perl that does nto knwo all that much. My ability stops at being able to take something written and change it how I like it. I just have not had the time to learn more than that so far. Though the more i change the more I learn.

My problem is this:

I am using a program you can get with MS Windows 2003 called SRVINFO.EXE. It prints data out to you in this format:

Server Name: Server1 Security: ***** Registered Owner: **** Registered Organization: ***** ProductID: ****** Original Install Date: Wed Dec 15 15:18:53 2004 Base Source Path: *** Service Pack Source Path: *** Version: 5.1 Build: 2600.xpsp1.020828-1920, Service Pack 1 Current Type: Uniprocessor Free Product Name: Microsoft Windows XP Product Options: Professional HAL.DLL is 5.1.2600.1106 - Microsoft Corporation - 5.1:2600.82 PDC: \\server Domain: domain Domain Guid: {list of numbers and dashes} DNS Forest Name: DNS Forest PDC Site Name: Site Name Computer Site Name: Site Name CPU[0]: x86 Family 6 Model 8 Stepping 6: 866 MHz System BIOS Date: Date System BIOS Version: Version Hotfixes: Windows XP: SP2 [KB823182]: Installed on 12/15/2004 by User [KB823559]: Installed on 12/15/2004 by User [KB823980]: Installed on 12/15/2004 by User [KB824141]: Installed on 12/15/2004 by User [KB824146]: Installed on 12/15/2004 by User [KB825119]: Installed on 12/15/2004 by User [KB828028]: Installed on 12/15/2004 by User [KB828035]: Installed on 12/15/2004 by User [KB828741]: Installed on 12/15/2004 by User [KB833987]: Installed on 8/16/2005 by User [KB835732]: Installed on 12/15/2004 by User [KB892944]: Installed on 8/11/2005 by Administrator [Q323255]: Installed on 12/15/2004 by User [Q327696]: Installed on 12/15/2004 by User [Q328310]: Installed on 12/15/2004 by User [Q329390]: Installed on 12/15/2004 by User [Q331953]: Installed on 12/15/2004 by User [Q810833]: Installed on 12/15/2004 by User [Q815021]: Installed on 12/15/2004 by User [Q817606]: Installed on 12/15/2004 by User SP3 [KB873333]: Installed on 5/3/2005 by User [KB885250]: Installed on 5/3/2005 by User [KB888113]: Installed on 5/3/2005 by User [KB890047]: Installed on 5/3/2005 by User [KB891781]: Installed on 5/3/2005 by User [KB893066]: Installed on 5/3/2005 by User [KB893086]: Installed on 5/3/2005 by User [KB896422]: Installed on 8/16/2005 by User [KB899588]: Installed on 8/19/2005 by User Internet Explorer 6: SP1 [KB867282-IE6SP1-20050127.163319]: Installed on 5/3/2005 by U +ser [KB890923-IE6SP1-20050225.103456]: Installed on 5/3/2005 by U +ser Drive: [FileSys] [ Size ] [ Free ] [ Used ] Drive Information Network Card [0]: Card name IP Address(es): ***.***.***.*** MAC Address: MAC Network Card [1]: Card Name IP Address(es): ***.***.***.*** MAC Address: MAC Network Card [2]: Card name IP Address(es): ***.***.***.*** MAC Address: *** Protocols: List of Protocols System Up Time: 1 Days, 14 Hr, 9 Min, 13 Sec

Edited for security reasons of course This data is gathered for a list of PC's and then i parse the data out from this file so that it looks like this:

#XP_SP1 #Patches begin here (All) #Server1 KB823182 KB823559 KB823980 KB824141 KB824146 KB825119 KB828028 KB828035 KB828741 KB833987 KB835732 KB892944 Q323255 Q327696 Q328310 Q329390 Q331953 Q810833 Q815021 Q817606 KB873333 KB885250 KB888113 KB890047 KB891781 KB893066 KB893086 KB896422 KB899588 KB867282-IE6SP1-20050127.163319 KB890923-IE6SP1-20050225.103456 #XP_SP1 #Patches begin here (All) #Server2 [Another List of Patches] #XP_SP1 #Patches begin here (All) #Server3 [Another List of patches]

Now this is my delima. I would like for it to create a txt file called patches.server#.txt (Server# being the actual name of the PC from the file) for each server I have in the file called pcinfo. Right now all my output does is make a long list of the servers and there patches. But I would still have to cut and paste each list into a new txt document.

The lines of the file need to stay verticle like that, this is for another script that is already running right (someone else wrote).

Any ideas of how to get this done would be appreciated, maybe even point me in the right direction on what I need to do. Of course if you find a fix and think it will work, writing it for me aint bad and i will pick it apart and examine it to help me learn.

The history of this perl script is that the first portion I wrote myself to take the PCINFO input and run the command line for each computer in that file and then output the information to SRVINFO file. The second part of the script was written by someone here at work who is no longer here...he was the one who started to teach me (pulled this one out his bottom like all the others he helped me with when it woudl take me years to figure it out). I was able to change some things on the second portion to make my outcome even better suit my needs and then change it some more to what you see so that i get the output how I need it now. The first output was the servername and then the patches all on the same line delimited by commas.

So here is the Code:

#!/usr/local/bin/perl -w use diagnostics; # optional; causes warnings to be explained in grea +ter detail. use strict; # generates compile and run-time errors for certain + unsafe constructs. #AGT Tester srvinfo Section print "Backing up old agtsrvinfo.txt... <br>"; rename ("txtfiles\\srvinfo.txt", "txtfiles\\bac\\srvinfo.bac") || +die "Cannot rename agtsrvinfo.txt: $!"; print "Starting AGT Tester hotfixes finder <br>"; open (PCINFO, "txtfiles\\pcinfo.txt") or die "I could not get at a +gtpcinfo.txt as input"; open (SRVINFO, ">>txtfiles\\srvinfo.txt") or die "I could not open + agtsrvinfo.txt as output"; my $time; $time = localtime(time()); print SRVINFO "$time.------------------------------------- +--------------------------<br><br>"; while (<PCINFO>) { chomp; my $srv; $srv=$_; print "$srv <br>"; my $result; $result = `srvinfo -ns \\\\$srv`; my $dump; $dump.="Server Name: $srv<br>"; $dump.="$result<br>"; $dump.="<br>===========================<br><br>"; print SRVINFO $dump; $dump=""; } close PCINFO; close SRVINFO; #AGT Tester hotfixes Section print "Backing up old agthotfixes.txt... <br>"; rename ("hotfixes.txt", "hotfixes.bac") || die "Cannot rename agth +otfixes.txt: $!"; open (INPUT, "txtfiles\\srvinfo.txt") or die "I could not open agt +srvinfo.txt"; ($WAIT_NAME, $WAIT_FIX, $WAIT_DRIVE) = (0,1,2); open (OUTPUT, ">>hotfixes.txt") or die "I could not open agthotfix +ed.txt"; $CUR_STATE = $WAIT_NAME; @FIXES; while(<INPUT>) { if($CUR_STATE == $WAIT_NAME && /^Server\ Name\:\ (.+)<br>/) { print OUTPUT "\#XP_SP1<br>\#Patches begin here (All)<br>"; print OUTPUT "\#$1<br>"; #print OUTPUT "$1"; $CUR_STATE = $WAIT_FIX; } elsif($CUR_STATE == $WAIT_FIX && /^Network\ Error\ (.+)<br>/) { print OUTPUT " $1"; $CUR_STATE = $WAIT_NAME; } elsif($CUR_STATE == $WAIT_FIX && /^PDC\:\ Error\ (.+)<br>/) { print OUTPUT " $1"; $CUR_STATE = $WAIT_NAME; } elsif($CUR_STATE == $WAIT_FIX && /^Hotfixes/) { $CUR_STATE = $WAIT_DRIVE; @FIXES=""; } elsif($CUR_STATE == $WAIT_FIX && /^Drive/) { $CUR_STATE = $WAIT_NAME; print OUTPUT "@FIXES"; @FIXES=""; } elsif($CUR_STATE == $WAIT_FIX && /^Network/) { $CUR_STATE = $WAIT_NAME; print OUTPUT "@FIXES"; @FIXES=""; } elsif($CUR_STATE == $WAIT_DRIVE && /^Drive/) { $CUR_STATE = $WAIT_NAME; print OUTPUT "@FIXES"; @FIXES=""; } elsif($CUR_STATE == $WAIT_DRIVE && /^Network/) { $CUR_STATE = $WAIT_NAME; print OUTPUT "@FIXES"; @FIXES=""; } elsif($CUR_STATE == $WAIT_DRIVE && /^Protocols/) { $CUR_STATE = $WAIT_NAME; print OUTPUT "@FIXES"; @FIXES=""; } elsif($CUR_STATE == $WAIT_DRIVE && /\[(.+)\]\:/) { push (@FIXES,"$1<br>"); } else { # die "INVALID DATA:$_"; } } close INPUT; close OUTPUT;

If you need anymore information please let me know and I will indulge it. I will also be trying some stuff while I wait and probably breakling the crap out of it (Good thing I only tinker with a copy :) )

Oh, and this does work the way it is now to give the outputs you see.

A list of inputs and outputs:

PCINFO: pcinfo.txt (first input to the script, a list of computer names)

SRVINFO/INPUT: srvinfo.txt (The first output and the second input. The data printed from running srvinfo.exe for the computers in pcinfo.txt)

OUTPUT: hotfixes.txt (the last output. The script parses the hotfixes from srvinfo.txt and makes this file so you knwo what hotfixes are installed on the PC)

Thank you so much,

Jason (Sunnmann) Dykstra

READMORE tags added by Arunbear

Replies are listed 'Best First'.
Re: Creating multiple files from txt data
by ikegami (Patriarch) on Sep 23, 2005 at 03:56 UTC
    Simply move open(SRVINFO, ...) into the while (<PCINFO>) loop.
Re: Creating multiple files from txt data
by aufflick (Deacon) on Sep 23, 2005 at 05:08 UTC
    Please use <readmore> tags in your post - it's really long in list view!

    (See Writeup Formatting Tips)

    Oh, and the reply by ikegami is spot on - you just need to put the open() call inside the loop and use a different filename each time. You don't need to close() the filehandle because (as stated in the perldoc for the open function which you can see using perldoc -f open) the open() call will close the filehandle first if necessary.

Re: Creating multiple files from txt data
by puploki (Hermit) on Sep 23, 2005 at 09:30 UTC

    If you are trying to determine what hotfixes are installed on a Windows PC, using srvinfo or psinfo is perhaps not the best way to go.

    Microsoft's MBSA is an excellent (free) patch scanning tool - it can also output an XML report (you can run it from the command line as well as GUI) so if you want you can parse the output and do some post-processing with Perl with XML::Parser say.

    I suppose I should weigh in with an off-topic non-Perl answer (as is my way) by saying that if this is for a Corporate environment you should probably take a look at WSUS and/or SMS for Windows patch management.

      We have tried the SUS and all that for patching. Problem is ourt firewalls here and the configuration. The IT department has patching systems, but once again our firewalls block us from being able to use those...and they WILL not understand that the systems I am talking about ABSOLUTELY cannot be rebooted ona whim. They run 24/7 and are testing teh whole time...to reboot these machines we have to get time from teh manufacturing floor so they are able to either swap the product around or if it is a quick reboot just stop at end of testing and then reboot quickly.

      So we have come up with this solution. The main script works fine, I am just trying to make it easier on people to install this by cutting down on the preliminary work.

      I thank yo ufor your suggestion though and i will see how MSBA will work. I have tried it before, but if I am not able to write a perl script to parse out a simple txt document I dont know how I will write one to parse out an XML file :)
        You would use XML::Parser of course. :-)

        TStanley
        --------
        The only thing necessary for the triumph of evil is for good men to do nothing -- Edmund Burke