Teams, Teams, Teams!
Teams, Teams, Teams!
November 3, 2016
Microsoft RD Logo
Microsoft Regional Director
April 21, 2017

Embracing the future: Integrating SharePoint Portal Server 2001 with Microsoft Azure Functions

During Christmas break in late 2016 I started planning for my upcoming presentations and demos for the first half of 2017. I’ve held talks on a wide range of topics, including all things SharePoint, Microsoft Azure Security, PowerApps and Flow, and Azure App Service to mention a few. I like the challenge of learning about new technologies, platforms, frameworks and approaches for productivity and modern work. So once again in December it was time to think about something new.

My first presentation was yesterday in Paris, for the Microsoft Cloud Summit. I knew I wanted to touch a bit on PowerApps and Flow, since they’ve progressed hugely in the past few months. In addition I’ve been using Azure Functions quite a bit in recent projects so I felt a talk on all three cloud-based services would be a good, fresh and challenging idea.

2017-01-25 10.45.25

Sometimes I skip demos, if I feel they don’t provide enough value for the attendees. Upon sharing my slides (which I’ve done quite actively on my Docs.com account during the past few years) a demo-filled presentation is quite useless. You have the introduction slide, a few jokes, 3 slides on demo this, demo and a finishing slide to recap thing. For development topics I also often feel that the audience does not want to see me live-code things – you always miss the occasional semicolon, or things just take a bit longer to build and deploy to ruin the good flow and vibe during the session.

2017-01-25 10.15.39

Lately I’ve found more value in demos, as they force me to build something a bit more long lasting that I can reuse at a later time. They also force me to learn and understand how things actually work, as opposed to quickly skimming through a Technet or MSDN article and kind-of understanding it. Habits of being a long-time trainer, I guess – you don’t always have the luxury of learning everything, but learning it well enough to talk about it for a few moments.

My first demo for 2017

I started building a demo around Microsoft Azure Functions, which is an amazing platform for running your small bits of code and scheduled tasks in the cloud. I truly love the fact I can run old-school .BAT files too! Not that I have many of them in need of being executed on a global cloud platform but I respect the option to go back to my 1982 archive to run something that was high-tech at the time.

While playing around with Azure Functions, I knew many in the audience of the French Microsoft community might be involved with SharePoint. I started my own journey with SharePoint with the first bits on Site Server back in 1996..1997. It was a way for me to learn what would eventually be SharePoint Portal Server 2001. We also had Microsoft Content Management Server 2001 at the time, which was later more or less forcefully merged (cannibalized?) with SharePoint. While reminiscing the old times, I went to MSDN Subscription Downloads to see if I could still download Microsoft Site Server. Sadly it’s not there anymore. But I did find SharePoint Portal Server 2001, and two separate downloads for Service Pack 1 and 2!

I thought it would be fun to pour a glass of red wine and hack together a working SPS2001 environment. And maybe integrate that with something more modern – like Azure Functions?

What started out as a quick trip down the memory lane turned into a 3-night long hackathon trying to get things running on my Surface Pro 4.

The first challenge: Windows 2000 Advanced Server

Installation package for SPS2001 is only 125 MB. I had just upgraded my home connection to a 1 Gbps fiber, so it was a joy to click Download and for once be finished in a few seconds. That’s the challenge in these days: by downloading a 4 GB .ISO image you’re forced to wait tens of seconds, maybe even several minutes. I find it both hilarious and sad that one can never be truly happy with things in their current state. Service Pack 1 has to be installed first (no cumulative updates here), and SP2A is split into 5 packages so in total SPS2001 with all current patches from MSDN is 375 MB.

image

The problem now was that SPS2001 officially only supports Windows 2000 Server, or Windows 2000 Advanced Server. I don’t have a Pentium III around anymore, so I opted for VMware Workstation 12 Pro – which luckily supports legacy guest operating systems such as Windows 2000 Server. For reasons unbeknownst to me, MSDN does not carry Windows 2000 Server anymore. Luckily a colleague of mine is very thorough and had the media available on old-school optical media.

ws2000

I chose to deploy Windows 2000 Advanced Server, as I recalled the ‘Advanced’ part had something better in it. VMware acts very nice on such a legacy OS, no issues while installing it. Even TCP/IP worked out of the box, by using the wifi connection from the host OS.

I felt things were progressing nicely, and I would be done in an hour or so. After all, I have extensive experience fighting with SPS 2001 and SPS 2003, and I was confident I hadn’t forgotten anything in the past 10 or 15 years. I was so wrong.

Booting up W2KAS takes only 15 seconds with 4 GB of RAM and 2 cores for the virtual machine.

image

Old school ASCII boot screen. Brings back memories.

image

It still warms my heart to see the classic Windows logo.

image

Things don’t always work like they should, something failed. I decided to debug that later, as TCP/IP was working and I could transfer files between shared folders on the host to the guest.

image

I might have over-exaggerated with the screen resolution but Windows 2000 Advanced Server runs smoothly on 1670*905 resolution in 32 bit colors.

image

As is customary, I ran Windows Update to check for any new updates. That felt silly. But maybe some updates?

image

The old Windows Update site is still running! I hit Express in hopes of getting a boatload of critical updates. I didn’t really need these, as my intention was to only run the VM during demos, and not connected to any external networks. So security wise, I felt a bit unprotected but put on straight poker face.

image

This is the moment of truth: a cryptic error number (0x80072F78). Initially I thought maybe Microsoft had finally given up on maintaining the old Windows Update infrastructure but forgot about the landing page. I was maybe expecting to see a reminder to finally upgrade to Windows 10. I spent about 45 minutes trying to fix the issue – there are numerous discussions on different sites about the possible reason for the error. More on this in a bit.

While trying to resolve the failed Windows Update, I installed Service Pack 4 for Windows 2000. No problems there, and I felt a bit more updated and fresh now.

image

So back to Version 5.0 of Windows. That’s like half as good as Windows 10?

While figuring out the Windows Update issue, I updated from IE 5 to IE 6. Not a huge difference but at least IE 6 is something I actively disliked. You can get IE 6 bits from MSDN. Remember to install Service Pack 1 also. You still don’t have anything modern in the browse, such as tabbed browsing.

This is how www.microsoft.com looks on IE6 today:

image

Hold on, it doesn’t actually work! What about www.google.com? Nope, still the same generic error of not finding the server or having a DNS error. But how is windowsupdate.microsoft.com working then? Nslookup shows me that it can resolve www.microsoft.com and similar addresses correctly. I had a tab open on my Windows 10 for The Verge, so I copy-pasted the address to IE6 on the Windows 2000 box. And it worked. Kind of.

image

So yeah, images are missing, most – if not all – of the style sheets are gone, and not much is happening. But at least I can open a site and read the contents without excessive ads.

image

Looks like some of the modern browser add-ins that promise a distraction-free reading experience. Maybe IE6 was right all along!

Thinking about this on the second night of hacking the VM together I figured this has to do with the browser, the OS or something outside the VM. Then it hit me – IE6 is a prehistoric browser. Maybe it simply cannot handle HTTPS, as most sites default to secured connections by default? I figured I might give a try to updating the root certificates, which were a bit out of date. Several forums provided hacked root certificate packages – some a bit shady, to say the least. Microsoft had the official update available here for Windows XP and Windows 2000. The page is now gone but I was able to find the package through a mirror link.

The problem stems from SNI, or Server Name Indication. SNI addressed the challenge of maintaining multiple SSL certificates for websites back in 2004. The patch wasn’t backported to Windows 2000, and there’s problem also for Windows XP apparently. Windows Vista did get SNI supported. So, several long hours on trying to get IE6 to run Windows Update on Windows 2000 Advanced Server fell short: no support from Microsoft on the OS level. I contemplated building a quick HTTP-to-HTTPS proxy to use in my environment but as I knew I didn’t really need this to be working, I could just be happy with what I got running. It would have made things simpler, as you’ll see in a bit.

image

I needed Internet Information Services along in order to get to my next installation, and luckily that installed without any issues.

image

Glad to see NNTP services in full swing again!

Deploying SharePoint Portal Server 2001

I took a snapshot of the VM to save my progress. Windows 2000 Advanced Server feels very robust but at the same time, very fragile.

image

Unpacking SPS2001 RTM media on the disk and installing SPS2001 is a breeze. At least when you compare the installation to SharePoint 2016, which has numerous steps to complete before you actually get to the installation phase. Keep in mind that SPS2001 does not use a SQL-based database, but a JET-based database inherited from the then-modern Exchange 2000 platform.

image

image

Installation of SPS2001 takes a few moments. Installing SP1 and SP2A is like a full reinstall of SharePoint and takes a few moments. Since we’re talking about the first incarnation of SharePoint there isn’t a Central Administration site. But there are client tools, which include the administration tool as a Win32 executable.

image

The tool allows you to create new workspaces (kind of like site collections back in the day). You can also control security, indexing, logging and discussions of a given workspace with the tool. Plain and simple, compared to today’s SharePoint administration tasks.

image

Upon creating a workspace I can now finally open my freshly patched IE6, and navigate to a SharePoint Portal Server 2001 based Portal.

image

It looks.. SharePointy! You have search, categories (“metadata”), a document library and subscriptions. Editing a page looks very familiar for SharePoint people.

image

Modifying web part layout was ahead of its time in 2001:

image

You can actually drag and drop web parts from one zone to another. Not much has changed since then.

There’s a document library for actually, you know, getting your work done. It’s simplistic enough and allow you to add new files, subscribe to changes and deleting files.

image

Looking at a document, you get all the essential information.

image

Who needs modern capabilities such as browser-based editing, when you can download documents.

So, at this point I had a VM running with Windows 2000 Advanced Server, SharePoint Portal Server 2001 with relevant patches and I was able to upload documents to my workspace. The service also works from my host machine by using Google Chrome.

image

It took me the better part of two nights to get up to this point. Things seemed relative stable, and SharePoint is very fast. It’s basically pure HTML without excess payloads.

Integrating SharePoint Portal Server 2001 with Microsoft Azure Functions

Finally, we’re getting to the meat of this blog post! Since I now had SharePoint 2001 running, and accessible outside the VM, I could start building a true integration. I already had other demos for Microsoft Flow and PowerApps, so my initial intention was to integrate SPS2001 with a custom Azure Function. Maybe upon uploading and publishing a new document, I could execute a cloud-based approval workflow.

The first major obstacle I already knew: I couldn’t call HTTPS sites programmatically. I tried cURL, VBScript and even tried compling some old code I had laying around for Visual Basic 6, but this was time consuming and didn’t really provide me with a platform I could reliably get working. In the end I knew I had to have a working demo, without all the hassle of COM components, DLL hell and VBRUN600.DLL issues. Slowly, the horrors of the 2000 era problems started crawling back to me.

For SharePoint Portal Server 2001, there really isn’t a true API or integration engine. Luckily there is the Document Management Object Model, or PKMCDO.DLL binary.

I hacked together a very simple prototype to see if I could read data from a SPS2001 based workspace, and expose it externally, in hopes of retrieving that information for my Azure Function.

Here is the initial version, which simply instanties a CDO.KnowledgeFolder object, connects with the workspace and gets the files. I needed to use Visual Basic Scripting (VBScript), as I didn’t want to start installing a legacy Visual Studio/Interdev on the box and running into all sorts of compilation issues. Keep in mind I was unable to get any updates beyond Windows 2000 SP4 for the box.

Option Explicit

dim objFolder
dim rstDocs

Set objFolder = CreateObject(“CDO.KnowledgeFolder”)
objFolder.DataSource.Open “
http://ws2000as/demo/Documents”

Set rstDocs = objFolder.Items

Do While Not rstDocs.Eof
Title = rstDocs(“urn:schemas-microsoft-com:office:office#Title”)
Author = rstDocs(“urn:schemas-microsoft-com:office:office#Author”)
Filename = rstDocs(“RESOURCE_DISPLAYNAME”)
Modified = rstDocs(“DAV:getlastmodified”)

    Wscript.Echo “-” & Filename & “|” & Title & “|” & Author & “|” & Modified
rstDocs.MoveNext
Loop

I couldn’t initially figure out how to read the metadata of a given document, but MSDN still has proper documentation, which helped. To verify I was really getting the proper data, SPS2001 installation media has a TOOLS folder, with a fantastic debugging tool called PLEX (Platinum Explorer).

image

PLEX allowed me to verify what kind of data was sitting in the database, and quickly iterate through the metadata for the files. With this, I was able to hack together a rudimentary “API” for exposing changes to my workspace’s document library. Here’s the full code, which is slightly expanded from the initial prototype.

Option Explicit

dim objFolder
dim rstDocs

Set objFolder = CreateObject(“CDO.KnowledgeFolder”)
objFolder.DataSource.Open “
http://ws2000as/demo/Documents”

Set rstDocs = objFolder.Items

dim Title, Author, Filename, Modified

dim Marker
dim fso, f

‘ Get Marker data/tick
set fso = CreateObject(“Scripting.FileSystemObject”)
If (fso.FileExists(“c:\temp\__MARKER__.txt”)) Then
Set f = fso.OpenTextFile(“c:\temp\__MARKER__.txt”)
Do Until f.AtEndOfStream
Marker = f.ReadAll()
Loop
f.Close

    Set f = Nothing

    ‘ horrible fix for timezone issues..
Marker = DateAdd(“h”, -2, Marker)
wscript.echo “## MARKER: ” & Marker
End If

‘ Get SPO files, process them, update marker if needed
Do While Not rstDocs.Eof
Title = rstDocs(“urn:schemas-microsoft-com:office:office#Title”)
Author = rstDocs(“urn:schemas-microsoft-com:office:office#Author”)
Filename = rstDocs(“RESOURCE_DISPLAYNAME”)
Modified = rstDocs(“DAV:getlastmodified”)

    if (DateDiff(“s”, Modified, Marker) < 0) then
set f = fso.CreateTextFile(“c:\temp\SPSTrigger\items.txt”, true)
f.WriteLine Filename & “|” & Title & “|” & Author & “|” & Modified
f.Close
set f = Nothing
Else
Wscript.Echo “-” & Filename & “|” & Title & “|” & Author & “|” & Modified
End If

    rstDocs.MoveNext
Loop

‘ Update marker
set fso = CreateObject(“Scripting.FileSystemObject”)
Set f = fso.CreateTextFile(“c:\temp\__MARKER__.txt”, true)

f.WriteLine FormatDateTime(Now)
f.Close

set f = nothing
set fso = nothing

The code retrieves all files, and maintains a marker file for figuring out what was changed. This was the quickest way for me to expose information about new content. This was good enough for my purposes, as I wanted to trigger the Azure Function upon new changes. My scheduling this script to run once per minute, I was able to trap any changes and record the changes to a separate text file. This text file is then exposes outside SharePoint through a IIS virtual directory.

image

So effectively I could get the filename, title, owner and timestamp for any new files uploaded to my document library. SharePoint prefers 1997 Office documents, so a .doc file it is.

Now, for triggering my Azure Function I used a simple PowerShell script to glue together my SharePoint Portal Server 2001-based document library and Azure Function.

$doc = Invoke-WebRequest -Uri “http://ws2000as/SPSTrigger/items.txt”

$filemetadata = $doc.Content.Split(“|”, 2);
$filename = $filemetadata[0]

Invoke-RestMethod -Uri “https://peopleloc.azurewebsites.net/api/SPNewFilesDetected?code={key_removed}&filename=$filename”

The beauty of Azure Functions is that I can simply trigger them through a HTTP GET/POST call.

The Azure Function in turn picks up the filename, and – you guessed it right – tweets about this earth-shattering change in my SPS2001 to the world. I’m not expecting a lot of retweets, but maybe some! In order to send the tweet, I used the TweetInvi library, available on GitHub here.

To send a tweet, it’s supersimple with C# now:

var consumerKey = “{removed}”;
var consumerSecret = “{removed}”;
var accessToken = “{removed}”;
var accessTokenSecret = “{removed}”;
Auth.SetUserCredentials(consumerKey, consumerSecret, accessToken, accessTokenSecret);

var publishedTweet = Tweet.PublishTweet(“A new file was published to SharePoint Portal Server 2001: ” + filename);

if (publishedTweet == null)
{
log.Error($”Failed to publish”);
}
else
{
log.Info($”Published tweet {publishedTweet.Id}”);
}

I still had my own vanity twitter user available for purposes like this.

image

Final thoughts on the integration

In the end, the integration-bit of my demo is fairly simple – but powerful. With only 4 lines of PowerShell, and about 5 lines of C# (in the Azure Function), and a bit of VBScript on the SharePoint side, I am able to integrate a collaboration platform from 2001 with a global cloud-based serverless platfrom from 2017 together. And it works.

I spent a fair amount of time preparing the virtual machine, and a bit more time in figuring out why I couldn’t access HTTPS-secured sites. Time spent building the actual solution was about two hours – and this included the time to figure out how the TweetInvi library works, creating the small PowerShell snippet and building the custom VBScript for exposing changes in SharePoint. I am sure things could be a bit cleaner, nicer and robust. But for the purpose of my demo it’s more than good enough for now.

How is this relevant in 2017? Why should you care about a decades old platform in this day and age? I’m hoping you don’t ever need to upgrade, troubleshoot or implement solutions for any such old environments. Then again, I’ve spent my fair share of time years ago tinkering with platforms like this. It’s a good reminder, and a humbling experience that makes me want to appreciate services such as Azure Functions just so much more.

It would be unfair to say how easy things are today. On the contrary, things are moving so very fast it’s hard to keep up. I find solace with the fact that the things I’ve taught myself and spent time learning, are somewhat the foundation of my skillset even today. I’m hopeful that 10 years from now I can say the same about Microsoft Azure, Office 365 and the Windows platform.

Jussi Roine
Jussi Roine

Helping organizations create secure cloud and hybrid solutions using Microsoft Azure and Office 365 | Microsoft MVP, Microsoft Regional Director, Microsoft Certified Master, Microsoft Certified Trainer Regional Lead | Actively dislikes tomatoes.

Contact me through Twitter at @JussiRoine

Leave a Reply

Your email address will not be published. Required fields are marked *