Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
syphon^2
Sep 22, 2004
I would like to kick things off with a Perl question. (this is almost E/N)

I'm a beginner when it comes to programming. I work for my company's Build Team, which I've heard best described as "Half IT, half developer". Most of our stuff is written in Perl, so I picked up O'Reilly's Learning Perl and read through it. I've also grabbed Intermediate Perl, and am about halfway through that.

For the last year or so, I've been doing a lot of development in Perl. I've dabbled in other languages, but this is really my first. I've written several scripts for use in a command prompt (my company is solely win32), and have recently started creating basic CGI web-apps.

Basically, my question is, where do I go from here? I can continue learning Perl (I've only brief glimpses into Object-Oriented Perl), or I can focus on learning to create bigger and better web-apps with Perl, or I can move on to a different language altogether. I don't think I'll ever be a full-time developer, but obviously I enjoy coding in Perl and want to learn more, even if that means going to Python or Ruby.

Lots of people are kinda pressuring me into learning Ruby, but I'm hesitant to try to "start over" and learn a whole new language. Part of the reason I'm happy with where I am with Perl is that I'm at a stage where I can produce actual deliverables, while still having plenty of room to learn more.

So, Perl gurus, where do I go next?

Adbot
ADBOT LOVES YOU

syphon^2
Sep 22, 2004

InvSqrt posted:

I want to start using my Perl knowledge for web development.

What's the best way to do this using Apache?
And what special stuff do I need to do in Perl to get this to work? I remember trying this once before and couldn't even get output to work.
I was in your same position a while back. I learned Perl for my job, and I started having an interest in Web-Programming. I didn't want to pick up a new language, so I looked into what I could do with Perl...

1) Set up Apache (I use IIS myself) to work with CGI (you can google this)
2) Create a perl file with "use CGI ':standard';" at the head. Save as *.cgi
3) Read the documentation on CGI.PM.

I started out writing really simple apps. A single .cgi file with a simple HTML form that executed certain code based on how the user filled out the form. After that, I got more complex, adding in a Templating system and working under an MVC style.

Personally, I recommend starting out making a flat .cgi file that handles everything. Get comfortable with what CGI can do, and how to write it. Then expand towards using mod_perl or Templates or whatever you like.


EDIT:

Triple Tech posted:

1) mod_perl. To this day I'm still not sure what it does in that I haven't done anything with it myself.

2) Frameworks. I guess Catalyst would be a good choice.

3) Templating engines. Mason is pretty popular.
1) I'm not too knowledgable on mod_perl, but I installed it and tried it out. I think the big thing is that CGI loads the Perl interpreter independently with each call to a CGI page, while mod_perl keeps it loaded and just serves the page at request. It saves CPU cycles and makes the app run faster.

2) Catalyst is a pretty big framework. Personally, I found the overhead to be HUGE. I'd use this if I were developing some HUGE perl web-app, but otherwise, I'd avoid it. I installed it and played around, and after a few hours, I was still really far from actually getting anything done.

3) I personally recommend Template Toolkit (recommended to me by another goon). It works well for my needs.

syphon^2 fucked around with this message at 15:00 on Dec 6, 2007

syphon^2
Sep 22, 2004

InvSqrt posted:

Thanks guys.
For the record, here's what I did to get it working:

1. apt-get install libapache2-mod-perl2
2. Found some example config and added it
code:
<Files ~ "\.pl$">
  SetHandler perl-script
  PerlResponseHandler ModPerl::PerlRun
  Options +ExecCGI
  PerlSendHeader On
</Files>
3. Created an index.pl containing this:
code:
#!/usr/bin/perl
use CGI;
print "Content-type: text/html\n\n";
print "<h1>Hello World!\n";
Awesome. That's exactly where I started. I advise your next step being...

1) Write a more complex index.pl that utilizes a form to gather input and then do something with that input.
2) Maybe play around with a few different types of forms, making more complex pages.
3) Use a templating system to separate out your HTML and Perl code
4) Use a full blown framework.
5) Take over the world.

Then again, I'm only somewhere between steps 3 and 4 myself. :)

syphon^2
Sep 22, 2004

SpeedFrog posted:

It's even super easy to AJAXify the application if you bolt in CGI::Ajax or use a toolkit like Prototype or Ext.
Ooh, CGI::Ajax looks super easy to use, and I'd like to utilize it to implement some Ajax functionality in a web-app I have.

However, it doesn't look like it really works with Templating systems. It wants to create the html through it's build_html() method, which doesn't work with any templating systems I see.

Any ideas how I can combine the two?

EDIT:
It looks like CGI::Ajax has other methods to use in case you don't want it to render the HTML. However, it still doesn't work. Here's my sample page. It tries to use Template Toolkit in conjunction with CGI::Ajax. Feel free to try it yourself.

EDIT2: Hmmm, it apears that the Ajax works simply by invoking the CGI script again with a set of parameters, so that the CGI itself returns ONLY the value determined by the function. Maybe if I add some logic to detect those parameters, and bypass the rest of the page if they're included?

EDIT3: I got it working. There's not as much documentation available out there as I'd like... but I found someone who got it working. It turns out I need to use a third parameter in $template->process to output the HTML to a scalar, rather than straight to STDOUT. Then, I use CGI::Ajax's build_html method to output the HTML instead.

syphon^2 fucked around with this message at 18:04 on Dec 7, 2007

syphon^2
Sep 22, 2004

dagard posted:

This looks like what you want:
http://outflux.net/software/shorts/perl/Idle
Hey that's really cool. How would one handle multiple-line "interactive" scripts then? The carriage return let's you re-draw the current line, but what if you need to re-draw the PREVIOUS line(s)?

syphon^2
Sep 22, 2004
Can anyone give me tips on using File::Find, or maybe point out a more appropriate module to use? (EDIT: I'd rather not use one that doesn't come with most default Perl distributions... ActivePerl 5.8 for Windows, in this case. I saw File::Find::Rule, but dismissed it because of that caveat)

Basically, all I need to do is traverse a directory tree (it's actually a UNC path on a remote Win32 server) looking for a specific filename, and then determine the full path to that file. This file is unique (there's only 1 file by that name), but it could be anywhere in the tree. All I need is to find out where that file lives.

The problem is, File::Find's 'wanted' function is just a callback, it's return value is ignored. I'm able to find the file I'm looking for, but I don't know how to get that info back to where I need it!

Here's my code:
code:
sub FunctionFullOfStuff {
    use File::Find;

    [...]

    my @dir = ('\\REMOTESERVER\Folder\Subfolder');
    find(\&wanted, @dir);

    [...]
}

sub wanted {
    print "$File::Find::name\n" if (lc($_) eq 'uniquefilename.xml');
}
This works great. When it finds 'uniquefilename.xml' anywhere in '\\REMOTESERVER\Folder\Subfolder' path, it prints out the full path, which is EXACTLY what I need.

Here's the problem. find() ignores whatever is returned by wanted(). I can print the filename out, but I can't pass it back to my FunctionFullOfStuff where I need it. The only solution I can think of is making some global variable and stuff the filename there if it finds it. However, that's a pretty terrible idea as this function is in a shared .pm file... I don't want to just create random globals that most people won't care about.

Any ideas?

syphon^2 fucked around with this message at 15:47 on Mar 18, 2008

syphon^2
Sep 22, 2004

Triple Tech posted:

Couldn't you just declare your accumulator in the same scope as where the find function is called and just have wanted be an anonymous function?
You are my hero. I hadn't considered an anonymous function.

Here's my final code:
code:
use File::Find;

my $file;
my @dirs = ("$server\\$path");

find( sub { $file = $File::Find::name if (lc($_) eq 'uniquefilename.xml') },  @dirs);
print "Now I have the file path ($file) stored in a variable!\n";
Many thanks!

syphon^2 fucked around with this message at 16:48 on Mar 18, 2008

syphon^2
Sep 22, 2004
This is getting a bit outside the scope of Perl... but hope you guys will still help me. :)

TiMBuS posted:

mod_rewrite stuff
This has really gotten me to want to use mod_rewrite with my CGI apps, but the actual documentation is a little hefty to wrap my head around. Is there any way someone can provide the lines I'd add to httpd.conf to accomplish this?

I want to access this URL: http://hostname/appname/app.cgi?param=foo
Via this URL: http://hostname/appname/foo

Looking at the example you provided, it seemed like it would be pretty straightforward, but I'm obviously screwing something up, as it's not working. This is what i added...
code:
RewriteEngine on
RewriteBase /
RewriteRule ^appname/app.cgi?param=(.*)$ $1 [L]
RewriteRule ^appname/(\w+)(/.*)?$ appname/app.cgi?param=$1 [NC,L]
EDIT: It seems to work, but whenever I use the form to manually change what param should be, the URL stays the same. I guess it's just not quite behaving quite as I'd expect.

syphon^2 fucked around with this message at 18:40 on Apr 14, 2008

syphon^2
Sep 22, 2004
Can anyone give an example of a Perl script (using Win32::OLE) which enumerates all websites installed in IIS (preferably either version 5 or 6) and just dumps the data out in some consumable format?

I've found Win32::OLE and Win32::OLE::Enum, which seem like they'd do what I need. I'm not familiar with Win32::OLE or the IIS Metabase, so I don't even know how to parse the object for the data I need.

I can find a few examples, but nothing that really does what I need.

For example... this (scroll down a bit) manages to grab the default site, but then crashes my Perl interpreter! The code found here seems to work, but I have to provide it with a specific siteid to inspect (and I want to gather all sites, no matter their siteid).

Any advice?


EDIT: I'm muddling through it, but painfully slow. I guess what I'm asking for is a snippet of code or module or something that does what I need more gracefully. This code crashes Perl in certain scenarios (unknown yet) and I think won't work with IIS6.

This is what I have so far
code:
#!perl
use Win32::OLE;
use Win32::OLE::Enum;

$websvc = Win32::OLE->GetObject("IIS://localhost/W3SVC") 
	or print Win32::OLE->LastError;

$enumIIS = Win32::OLE::Enum->new($websvc); 

foreach $objSites ($enumIIS->All) { 
	print "$objSites->{ServerComment}\n" unless ($objSites->{Name} =~ /(Filters|Info|SSLKeys)/);
}
It prints out all sites found on the target server (just localhost in this case). I guess I can get what I need out of this, but there has to be a better way!

syphon^2 fucked around with this message at 17:51 on May 7, 2008

syphon^2
Sep 22, 2004
Can anyone share a really simple method of timing my code? I want to see how long certain code takes (in milliseconds), but can't find a clear, easy way to do this. I've tinkered around with time(), localtime(), Time::HiRes, and Benchmark.

I'm basically looking for something that'll do this...
code:
my $start_time = startclock();
# ... do a bunch of stuff
my $end_time = stopclock();
my $duration_in_ms = duration($start_time, $end_time);
print "Your code took ". $duration_in_ms . "ms to run!\n";
Nothing seems to do this as easily as I'd hope. Benchmark came close, but I have no idea how to interpret the results it's giving me.

syphon^2
Sep 22, 2004

dagard posted:

I've honestly almost always just used Time::HiRes for things like that.
I've got a stupid question...

From http://search.cpan.org/~jhi/Time-HiRes-1.9715/HiRes.pm

quote:

tv_interval

tv_interval ( $ref_to_gettimeofday [, $ref_to_later_gettimeofday] )

Returns the floating seconds between the two times, which should have been returned by gettimeofday(). If the second argument is omitted, then the current time is used.
Uhhh, what are "floating seconds"? Ironically, a google search just refers you back to that Time::HiRes doc, which doesn't explain it. I'm able to tell that querying this server took my app "0.315718" floating seconds... but I have no idea how long that is in relevant time.

syphon^2
Sep 22, 2004
I've got another simple question (boy, this really shows how incompetent I am at reading documentation!)

I'm using Win32::TieRegistry to gather information from the registry of a series of remote servers. My script has 6 methods, each which need to connect to the registry and grab some data. After implementing Time::HiRes, I can see that this is causing quite a delay, as each of these methods grabs several keys, and the methods are called multiple times for various servers.

Since all the keys I'm interested are stored under HKLM/Software/CompanyName, I'd like to connect once and get a dump of all sub keys just once, and then let Perl iterate through the data structure rather than connect multiple times to get the data it needs.

Any ideas? It seems like the whole module is built around connecting to the registry each time for individual keys.

syphon^2
Sep 22, 2004
Does anyone know of a way to take a dump (heh heh) of a portion of the Win32 registry, and store it in a hash to be parsed through later?

A script I'm working on gathers data from a bunch of remote servers, some of them across the world. The data I need all resides within a key in HKLM/Software/KEYNAME, and isn't terribly large. I'd like gather all these keys in one go, and use Perl to iterate through them.

I'm currently using Win32::TieRegistry to do this.
code:
#!perl
use Win32::TieRegistry;
$Registry->Delimiter("/");	
my $server = 'REMOTESERVERNAME';
my $value1 = $Registry->{"//$server/LMachine/SOFTWARE/KEYNAME/SUBKEY"};
my $value2 = $Registry->{"//$server/LMachine/SOFTWARE/KEYNAME/SUBKEY2"};
my $value3 = $Registry->{"//$server/LMachine/SOFTWARE/KEYNAME/SUBKEY3"};
# ... and so on
That's a really simplified example, but I need to gather about 20 registry values from various places inside this key. This needs to happen for several servers.

As I mentioned, some of the servers are (physically) very far away, so the latency is very high. Win32::TieRegistry seems to re-connect to the server each time it needs to gather a registry value. In some of the extreme cases, it's taking my script anywhere from 2-10 seconds to gather each registry key, for a total of about 30 seconds per server. This is SLOOOOOW.

Do you guys know of anything that will connect to the remote server, take a dump of the Key I specify (and all subkeys), then disconnect, maybe giving me a hash of the whole Key? I tried using Win32::TieRegistry, but it only seems to support tied-hashes (meaning, even though I try to store all the data at once, Win32::TieRegistry remotely queries each key as it's needed).

Any ideas?

syphon^2
Sep 22, 2004
I'll try that tomorrow... but like I said, I suspect Win32::TieRegistry only works with tied-hashes. Thus, when it goes through the loop, it makes and breaks the connection for every iteration. That's what happened when I tried it earlier (although I did it slightly differently).

EDIT: It's as I suspected. Using either snippet of code from above, creating the hash is reasonably quick (around the order of 600-800ms on my test scenario). Executing 'print Dumper(%copy);', however, took approximately 51938ms.

EDIT2: Well, I'm starting to think the bottleneck isn't Win32::TieRegistry, but really just the act of querying a remote registry. On a whim, I changed to calling reg.exe with a backtick (reg.exe is WinXP's native command line registry tool)
code:
my $reg = `reg query \\$server\HKLM\SOFTWARE\KEYNAME /s`;
and this process STILL took about 30s to complete.

syphon^2 fucked around with this message at 23:27 on Jun 30, 2008

syphon^2
Sep 22, 2004

Erasmus Darwin posted:

Rather than relying on the registry query code to handle communicating with each remote server, what about installing a local script on each one that bundles up all the relevant registry keys and spits it out as a single blob of data to your main script?
The script is responsible for querying servers out of a pool of ~300. New ones are added and old ones are deprecated on a nearly daily basis.

syphon^2
Sep 22, 2004
Is this the best way to sort hashrefs alphabetically (well, ASCI-betically)? Something seems inefficient about it, but it's how I've been doing it so far.
code:
#!perl

use strict;

my $data = GetData(); #GetData returns a hashref packed full of information.
my @alphabetical_list = sort keys %$data; #a sorted list of keys

#Use the array to iterate through the hashref alphabetically.
foreach my $key (@alphabetical_list) {
    print $data->{$key) . "\n";
}

syphon^2
Sep 22, 2004
I don't know, it seemed that creating a new array and sorting it JUST for the sake of iterating through another hash in a certain manner (alphabetized) wasn't the best way to do things. I had no valid reasons to think so, I just wanted to make sure. :)

syphon^2
Sep 22, 2004
Has anyone used CGI-Ajax? I need a way to implement a callback from an Ajax function, but it doesn't look like it supports it.

I have an app that queries a remote server for a bunch of service statuses (running|stopped|starting). Using CGI-Ajax, I've implemented a 'refresh' button, which refreshes the service status in an Ajaxy manner (doesn't reload the whole page). This currently works fine.

What I want to do, is make my 'refresh' button change into a 'loading' button while the refresh process is running (usually takes anywhere from 1-6 seconds). Then, when the Ajax request has completed, it'd change back into a 'refresh' button. I'm getting feedback from my users that they want/need more visual feedback that the process is running (if no service-statuses have changed, there's no visual feedback that anything at all is happening).

I'm going to commit a cardinal sin, and paste my javascript code here, as it is the relevant code. The ajax_refresh_services() function is a Perl function... the first param is the server name and second is the name of the div to paste the output into.
code:
//'back up' our refresh button
var oldRefreshButton = document.getElementById('refreshButton').innerHTML;
//change the refresh button into a 'loading' button
document.getElementById('refreshButton').innerHTML = '<img src="./img/loading.gif>';
//invoke CGI::Ajax function (takes anywhere from 1-6 seconds)
ajax_refresh_services( params, output );
//now restore the refresh button back to what it was
document.getElementById('refreshButton').innerHTML = oldRefreshButton;
Here's the problem. Since CGI-Ajax runs asynchronously, the button only stays as a 'loading' button until the Ajax call succeeds... it doesn't wait for the Ajax function itself to succeed. This means it changes icons for approximately 10ms.

What I think needs to happen, is for me to be able to specify a callback in my ajax_refresh_services() function. That way, when the services are refreshed, it'd change my button back to the original loading button.

I googled around but it doesn't look like CGI-Ajax supports this. Any ideas?

syphon^2
Sep 22, 2004
Hmm, I guess I was just hoping for someone to come in and say 'oh you could just use the so-and-so method for a call-back'. I have a couple solutions in mind, but I don't like them (involves putting too much HTML into my .pm file). :(

EDIT:
Ok, I'll hijack my own post for a completely different question involving HTML::Template and best practice. How would you guys do this?

I have a web-app that displays a bunch of junk, and one thing it displays is an overall "Pass|Fail". Stylistically speaking, I want to color this text, green if it's a 'pass', red if it's a 'fail'. HTML::Template doesn't have a lot of function, since it tries to separate code and design (I know template toolkit can do this by matching the variable in the template, but I really like HTML-Template's idea of keeping code out of your HTML).

The only way I could think of was computing what color the font should be inside my method, and then passing the template two variables.
code:
my $status = getStatus(); #returns 'Pass|Fail'
my $color = whatColor($status); #returns 'red|green'
$template->param( #Insert them into the template
    STATUS => $status,
    COLOR => $color,
);
... and then...
code:
<h3>
Status: <font color=<TMPL_VAR COLOR> > <TMPL_VAR STATUS> </font>
</h3>
Is this the best way to do it? It feels ugly... determining Design information in the code itself. However, I can't find any way to do this inside the template. (just to clarify, I'd actually set the font color via a stylesheet, but typed it up this way to get my point across)

syphon^2 fucked around with this message at 22:31 on Sep 30, 2008

syphon^2
Sep 22, 2004

TiMBuS posted:

CGI::Ajax allows you to specify a javascript callback instead of a div to insert the returned xml(html) into. The how-to is on the perldoc page:
Oh my god I love you. I skimmed over the documentation (too quickly, apparently) and then Ctrl-F'd for variations of 'callback'. Thanks so much for this!

TiMBuS posted:

e: why not make a css class for 'Fail' and 'Pass' and use <span class='<TMPL_VAR COLOR>'> <TMPL_VAR COLOR> </span>
This is the solution I'll go with, since it's very close to my original implementation. Right now, my 'Pass' class is named 'txt_success' and my 'Fail' class is named 'txt_fail'. I don't see any reason I can't rename those classes to 'txt_Pass' and 'txt_Fail', which would allow my template to set the class/color accordingly.

Thanks so much for your help guys!

syphon^2
Sep 22, 2004
Does anyone have any advice for making Perl talk to Active Directory?

My company is a Windows shop, and we use AD in both our corp workstations and test lab. The growing trend among my team is to interrogate DL's (which as I understand it, are the same thing as AD groups) to determine system authorization.

I've tried a couple how-tos, one on Net::LDAP and another that uses Win32::OLE, but I couldn't get either example working with my existing network. I think there's just too much about AD/LDAP I don't know about, so I don't even know where I'm going wrong.

Any advice would be greatly appreciated.

syphon^2
Sep 22, 2004

Ninja Rope posted:

I've used Net::LDAP many times to interact with Active Directory and it has worked quite well. Where exactly are things failing?
Here's the code I'm using... cut&paste from the Net::LDAP example I posted. The code first connects to the LDAP server, then binds to it (I'm not sure which of the two bind methods I should use, I've tried both individually). Then, it performs two searches based on the example given. It first tries to get all users, then it tries an individual user look-up.

(please forgive the fairly messy variable delcaration, I tried to sanitize my code before posting it here)
code:
#!perl

use strict;
use Net::LDAP;

my $adserver	= "AD-SERVER.MY.CORP.NETWORK.COM";
my $user	= "username";
my $pass	= "password";
my $name	= "User Name";
my $group	= "All Users";
my $dc		= "DC=MY,DC=CORP,DC=NETWORK,DC=COM";

my $ad = Net::LDAP->new('ldap://' . $adserver)
	or die("Could not connect to LDAP server. $!");
		  
$ad->bind($user . "\@" . $adserver, password=>$pass)
	or die "Error binding to LDAP Server: $!";
$ad->bind("CN=" . $name . ",OU=Policy 0, OU=" . $group . "," . $dc)
	or die "Error binding to LDAP Server: $!";

#------Search for all users----------	
# The search base?
my $base = 'OU=' . $group . ',' . $dc;
# What are we searching for?
my $filter = "memberof=CN=" . $group . "," . $dc;
# Which attributes should be returned?
my $attrs = "sn, givenname";
# Execute the search
my $results = $ad->search(base=>$base,filter=>$filter,attrs=>$attrs);
# How many entries returned?
my $count = $results->count;
print "Total entries returned: $count\n";
# Display entries
my $entry;
for (my $i=0; $i<$count; $i++) {
     $entry = $results->entry($i);
     print $entry->get_value('sn').", ".
           $entry->get_value('givenname')."\n";
}


#------Look up a specific user----------
use Time::Local;
# . . .
my $base = 'OU=All Users,' . $dc;
# What are we searching for?
my $filter = "CN=" . $name;
# Which attributes should be returned?
my $attrs = "sn, givenname, telephonenumber, mail, pwdLastSet";
# Execute the search
my $results = $ad->search(base=>$base,filter=>$filter,attrs=>$attrs);
# Display entries
my $entry;
$entry = $results->entry(0);
print $entry->get_value('sn').", ".$entry->get_value('givenname')."\n";
print "Tel: ".$entry->get_value('telephonenumber')."\n";
print "Email: ".$entry->get_value('mail')."\n";
print "Password last changed: ".
       localtime($entry->get_value('pwdLastSet'))."\n";

$ad->unbind;
This code outputs the following:
code:
C:\enlistment>perl ldap.pl
Total entries returned: 0
Can't call method "get_value" on an undefined value at ldap.pl line 54, <DATA> line 466.
As you can see, there are two problems. First, it's failing to retrieve any users from the generic search. Second, it's failing to look up a specific user (I hope that's causing the error it gave).


EDIT: I figured it out. I had a coworker sit with me (who'd done something similar in Ruby), and we were able to figure it out. I had my Search Base all wrong.

syphon^2 fucked around with this message at 13:44 on Oct 13, 2008

syphon^2
Sep 22, 2004
Use Data::Dumper to view the data structure. At the very least, you can paste it here and people can tell you how to de-reference it properly. :)

syphon^2
Sep 22, 2004
Has anyone used Win32::OLE to access remote registry keys, instead of Win32::TieRegistry? I'm trying to compare the performance of the two, and the only example I could find of using Win32::OLE to grab remote registry data is... cumbersome, to say the least.

Here's the example: http://aspn.activestate.com/ASPN/Mail/Message/activeperl/2965351

Here's the code (adapted to my own needs):
code:
use Win32::OLE;
use Win32::OLE::Variant;

use constant HKEY_LOCAL_MACHINE	=> 0x80000002;

my $server = "SERVERNAME";

my $oReg = Win32::OLE-> GetObject( 'winmgmts:{impersonationLevel=impersonate}!\\\\'
 . $server . '\\root\\default:StdRegProv')
	or die "GetObject: " . Win32::OLE-> LastError();

my $path = "SOFTWARE\\CompanyName";
my @names = ('Key1', 'Key2', 'Key3');
my @types = (VT_BSTR, VT_BSTR, VT_I4); 
#Note that @types has to directly correlate to @names

my $strKeyPath = $path;
for (my $ii = 0; $ii < @names; ++$ii) {

	my $strValueName = $names[$ii];

	if ($types[$ii] == VT_BSTR) {
		my $strValue = Variant (VT_BSTR|VT_BYREF, '<Not Set> ');
		my $ret = $oReg-> GetStringValue(HKEY_LOCAL_MACHINE,$strKeyPath, $strValueName, $strValue);
		$strValueName = '(Default)' if not $strValueName;
		print "$strValueName: ", $strValue-> Value(), "\n";
	} else {
		my $Value = Variant (VT_I4|VT_BYREF, 0);
		my $ret = $oReg-> GetDWORDValue(HKEY_LOCAL_MACHINE,$strKeyPath, $strValueName, $Value);
		print "$strValueName: ", $Value-> Value(), "\n";
	}
}

syphon^2
Sep 22, 2004
The environment I'm running in is very geographically diverse (it's not uncommon for a server from Seattle to query one in Dublin or Sydney), so latency is quite high.

Also, Win32::TieRegistry operates via a tied-hash... it doesn't ever seem to store data in local memory. I have a web-page which queries registry information real-time, so it gathers about 8 reg-keys from a series of remote servers. This runs SLOW, so I'm looking to speed it up. Setting up some timestamps, I can see that Win32::TieRegistry seems to operate (roughly) in this manner...

1) Connect to remote server
2) Gather reg-key value
3) Disconnect from remote server

Now repeat that process serially for 8 reg-keys across 30 servers, and you see why I'm looking for performance gains. :)

I can save myself a lot of time if I can find a way to take a dump (heh heh) of a certain Registry Key and all its sub-keys, and then just let Perl navigate it internally as a hashref or something. I couldn't find any way to do this with Win32::TieRegistry, so I was trying other means.

syphon^2
Sep 22, 2004

tef posted:

If speed is important why don't you do it in parallel ?
My Perl kung-fu is still relatively weak, so I'm not sure how best to tackle this. How would you recommend it? I was thinking of either setting up a fork or using Win32::Process::Create, but it looks like this is the route I'll end up going.

yaoi prophet posted:

Back when I had to solve this problem, I did it by installing an "agent" script , either on the local machines, or on a machine close to them on the network, which would gather up the data and store it locally so that I could poll it in one big chunk. Sped things up tremendously, but I have no idea how applicable that solution is to you.
I thought about this, but it's really not feasible in my situation. Our environment changes so fast (new servers added, old servers removed, servers renamed, servers re-imaged) that trying to maintain an agent system would be impossible (or at least, very very hard and prone to failure).

syphon^2
Sep 22, 2004

Mithaldu posted:

You may wanna try using http://search.cpan.org/~mlehmann/Coro-4.8/Coro/Socket.pm and http://search.cpan.org/~mlehmann/Coro-4.8/Coro.pm to get parallelization. Coro allows such kinda stuff without having to gently caress around with multiple processes or Perl's horrible threads.
Huh, threading/coroutines must be beyond me. I looked over this, and their example seems nothing more than an elaborate goto(), it doesn't run things asynchronously.

Take the following code... for example (ripped straight from http://search.cpan.org/~mlehmann/Coro-4.8/Coro.pm with a timer added in)
code:
use Coro;
use Time::HiRes qw(tv_interval gettimeofday);

my $timer = [gettimeofday];
async {
	# some asynchronous thread of execution
	print "2\n";
	sleep 5;
	cede; # yield back to main
	print "4\n";
};
print "1\n";
sleep 5;
cede; # yield to coroutine
print "3\n";
cede; # and again
print "Elapsed Time:\t" . int(tv_interval($timer) * 1000) . "ms\n";
The output is as follows:
code:
C:\>coro.pl
1
2
3
4
Elapsed Time:   10000ms
My understanding is that the code inside async should be running asynchronously, so the two sleeps should run in parallel. However, as you can see, the script is taking 10 seconds to fully execute.

What am I doing wrong?

Adbot
ADBOT LOVES YOU

syphon^2
Sep 22, 2004

Erasmus Darwin posted:

I think you're probably better off using Win32::Process like you were thinking of before.
Doing it this way means I have to rip out a bunch of code an put it in a separate .pl file though. :( (or can Win32::Process::Create execute Perl code within the same Perl executable?)


EDIT: I just thought of something else... Win32::Process::Create is like fork, in that I can't share variables, right?

  • Locked thread