Why on earth would these two disparate camps ever meet? Perl is 15 million years old, right, and SharePoint is the bane to system administrators everywhere. The small “SharePerl” audience includes me, and two or three really old techs that still use land line phones.
But Perl can make a nice replacement for SharePoint Timer Jobs and can be easier to debug than a Visual Studio developed solution. (Okay, whatever… My .NET experience is only deep enough that I can spell it.)
Setup
I have ActivePerl installed on an XP VM, which I use for all my script development. ActivePerl comes with a Perl Package Manager, which allows you to install any one of 12,000 Perl MODs with relative ease. Over the years I’ve installed a good number of these MODs ranging from simulating poker hands to creating PDF files script-o-matically. When IE finally supports SVG, my cachet will rise dynamically, thanks to Perl MODs.
Perl does not need to be installed on a SharePoint server. Don’t do that. That’s crazy. Perl can be run from any desktop, with the caveat: If you want to schedule Perl scripts to run at certain times, the machine has to be on, with a network connection. The interaction from Perl to SharePoint happens thanks to SharePoint web services and Perl’s LWP MOD.
LWP
LWP stands for “little www-browser for Perl”. It’s a collection of functions and classes that allow Perl to become a simulated web-browser. Ever wonder how email scraping robots work? I think I can safely say that LWP is involved. LWP is in the hacker tool category of “fun, fun, fun”. Go find a poll or survey that doesn’t restrict multiple entries by IP address, and script up an iterative LWP session. Okay, there’s still a law about self-incrimination, right?
LWP uses a Perl site level authentication library specifically tailored for NTLM:
C:\Perl\site\lib\Authen\NTLM.pm
Unfortunately, the library used by LWP for NTLM authentication is not compatible with IIS6 or 7. NTLM.pm needs to be hacked to send parts of the authentication packet in Unicode:
Edit NTLM.pm and find the line:
and replace that code with (or better yet, comment out the code above and insert the code below):$domain = substr($challenge, $c_info->{domain}{offset}, $c_info->{domain}{len});
$domain = &unicode($domain);
SOAP::Lite
SOAP::Lite is a MOD that is subtitled, “Perl's Web Services Toolkit”. If you’ve ever had the privilege of working with SharePoint’s Web Services, you’ll know they can handle almost anything you’ve ever wanted to do with a SharePoint site. This functionality is accomplished via SOAP calls.
When you load a web part page into SharePoint Designer (2007), have you ever seen the SOAP calls churning in the bottom left hand corner?
We’ll use this MOD to formulate SOAP calls to our SharePoint Web Services.
Credit, Where Due
Most of what I learned about the SharePoint / Perl connection, I got from a blog post from a Londoner named James who blogs at WWW.SQUISH.NET. His post entitled, “Talking to SharePoint Lists with Perl” is a gem. James’ bio mentioned he was working in banking, and that he loves Lotus Notes. Well, God bless him.
Let’s Roll
I’m going to just paste the Perl code here:
Here’s the output from the command-line:1: use LWP::UserAgent;2: use LWP::Debug;3: use Data::Dumper;4: use SOAP::Lite on_action => sub { "$_[0]$_[1]"; };5: import SOAP::Data 'name', 'value';6: our $sp_endpoint = 'http://shareperl/sites/wef/_vti_bin/lists.asmx';7: our $sp_domain = 'shareperl:80';8: our $sp_username = 'PIMPS\\wef';9: our $sp_password = 'Pa$$word16';10:11: $debug = 0;12:13: if ($debug) {14: LWP::Debug::level('+');15: SOAP::Lite->import(+trace => 'all');16: }17:18: my @ua_args = (keep_alive => 1);19: my @credentials = ($sp_domain, "", $sp_username, $sp_password);20: my $schema_ua = LWP::UserAgent->new(@ua_args);21: $schema_ua->credentials(@credentials);22: $soap = SOAP::Lite->proxy($sp_endpoint, @ua_args, credentials => \@credentials);23: $soap->schema->useragent($schema_ua);24: $soap->uri("http://schemas.microsoft.com/sharepoint/soap/");25:26: $lists = $soap->GetListCollection();27: quit(1, $lists->faultstring()) if defined $lists->fault();28:29: sub lists_getid30: {31: my $title = shift;32: my @result = $lists->dataof('//GetListCollectionResult/Lists/List');33: foreach my $data (@result) {34: my $attr = $data->attr;35: return $attr->{ID} if ($attr->{Title} eq $title);36: }37: return undef;38: }39:40: sub lists_getitems41: {42: my $listid = shift;43: my $in_listName = name('listName' => $listid);44: my $in_viewName = name('viewName' => '');45: my $in_rowLimit = name('rowLimit' => 99999);46: my $call = $soap->GetListItems($in_listName, $in_viewName, $in_rowLimit);47: quit(1, $call->faultstring()) if defined $call->fault();48: return $call->dataof('//GetListItemsResult/listitems/data/row');49: }50:51: my $list_id = lists_getid('Disk Space');52: print "List ID is: $list_id\n";53: my @items = lists_getitems($list_id);54: foreach my $data (@items) {55: my $attr = $data->attr;56: print Dumper($attr);57: }
And here’s the view of the SharePoint list:
Much more to come in later posts, but I hope you get an idea of where you can go using Perl to interface with a SharePoint list…