Tuesday, June 9, 2009

Free Last Modified By/Date From SharePoint

Who Responsible For This Edit!?

With the exception of politicians, most people are in favor of accountability. When it comes to web content management, I'd be the first to agree.

In this post we're going to go over how to get free Last Modified By and Last Modified Date fields on content pages by modifying either select page layouts or master pages. The end product will look like:

Last Modified By/Last Modified Date from SharePoint

What We're Using

We'll be keying off two base fields (Modified, and Modified By) that you can expect to find on pretty much any list you'll ever work with. To prove to you I'm not making things up, feel free to look up the fields yourself (and a tonne of other useful fields) by using SharePoint Explorer for WSS v3.

Modified and Modified By fields displayed in SharePoint Explorer.

Easy Win

Once you find out the names of the fields and their type, the markup to get at these fields is pretty straight forward. We use out of the box SharePoint SPField controls to pull and format the field values. It's of note that we put the ControlMode property to "Display" since we never want these fields to be editable.

Last modified at:
<%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
...
<SharePointWebControls:DateTimeField FieldName="Modified" runat="server" ControlMode="Display"/>by
<SharePointWebControls:UserField FieldName="Modified By" runat="server" ControlMode="Display" />

That's pretty much it, throw the above markup into any page layout or master page and you're pretty much done.

But Wait There's More

I'd hate it if you left this post thinking all you'd learned about were two lousy fields and how to display them on a page. There's a tonne of fields that are worth exploring and could potentially add value to your next SharePoint related application.

Example 1: ETL developers could make use of the Created/Created By/Modified/Modified By fields to perform incremental loads when pulling data from the SharePoint object model.

Example 2: UI Developers could use the Comments and Version fields to display the current version and any comments associated with the current version.

The point is that there is yet another lever here to help you get the most functionality out of your next SharePoint related application. Best of all, it's dead simple and doesn't involve a single line of code.

Best,
Tyler

Friday, April 10, 2009

CSS Selector Collisions

Thick Competition

For those brave souls who actively try to make stock SharePoint UIs look user friendly, there's a gauntlet that first needs to be run. The challenge has to do with competing CSS rules and styles. Stock SharePoint will emit many style sheets who will often also be trying to style the same element that you are.

When it comes to deciding which rule wins, you should keep the following rules in mind. They'll very likely help you troubleshoot, especially when combined with tools like the IE Developer Toolbar or the Firefox Web Developer Tools extension.

Specificity

In general more specific rules tend to win. Remember that CSS styles can come from four different places. Rules that are increasingly specific will trump those who come from more generalized sources. Below we list (from most general to most specific) the four most common sources of CSS for a given html document.

  1. The browser's default styles. Believe it or not each browser has a stock set of styles that get applied to elements whether you've chosen to style them or not. You'll have to compete with these even if they're the easiest to best.
  2. An external style sheet (referenced from within the <head> tag [below]).
    <head>
    <link rel="stylesheet" type="text/css" href="mystyle.css" />
    </head>
  3. Internal style sheet (rules described in <style> tags within the HTML document itself).
    <HEAD>
    <STYLE type="text/css">
    H1 {border-width: 1;}
    </STYLE>
    </HEAD>
  4. Inline styles (styles placed on individual elements themselves).
    <P style="font-size: 12pt; color: fuchsia">Some Text</P>

More specific rules (those further down the list) will win out over more general ones.

Weight

Certain selectors are a little stronger than others. More specifically, ID has more weight than Class which has more weight than Tag name.

In fact weight of a selector is determined by taking the sum of (100 * [# IDs used] + 10 * [# Classes used] + [# Tags Used].

Here's an example:

#navigation div.container span a.footerLink

Has a weight of (123 since it has 1 ID, 2 classes, and 3 tags. It would be trumped by:

div#navigation div.container span.wrapper a.footerLink

Since the above has a weight of 134 (1 ID, 3 classes and 4 tags).

Order

If specificity and weight are the same then it comes down to who was emitted last. In general rules that were emitted later on in the document will win.

The Ace In The Hole

If you're too lazy to figure out the rest you can simply use the !important flag.

div
{
color:red !important;
}

This should trump all other rules but is considered to be pretty poor form and may get you dirty looks around the water cooler.

Hope that helps.

Best,
Tyler

Thursday, March 5, 2009

Is It Really My Job To Fix That!?

That's Not On My Resume

I have to tell you that working in a software services firm isn't always a picnic.  Being a vendor (read outsider), and responsible for delivering working solutions on other peoples infrastructure, in a foreign LAN is nothing but a brazen undertaking. It's akin to trying to construct a building in a war torn, 3rd world country that happens to be in the middle of ongoing natural disasters. The drama sometimes matches that of most reality TV series, and while it's rarely dull in some regards, there's easier ways in life to get a win.

problems

When the hardware isn't changing and internal IT isn't ignoring you, it's most likely that you'll get bad OS builds, under powered VMs or fail to take note of the hidden agendas in a politically charged atmosphere. This is all in addition to regular project management woes. I'm just talking about delivery here, requirements and software lifecycle are another boat in entier.

You need to be really sharp to see all the possible ways you could fail, and even then it'll probably be something small that never even crossed your worried mind that will end threatening you and your project. Game on.

An Instance of Success

Today we came up with this interesting problem when installing some ETL on a BI server. The machine was running SSIS RTM on a Win2k3 x86 Service Pack 1. The ETL was taking a bunch of records from some source SQL Server database (SP2) and migrating them to another destination SQL Server database (SP2). The ETL would run for about 20ish minutes before consistently throwing the following exceptions:

An OLE DB record is available. Source: "Microsoft SQL Native Client" Hresult: 0x80004005 Description: "Protocol error in TDS stream".

An OLE DB record is available. Source: "Microsoft SQL Native Client" Hresult: 0x80004005 Description: "Communication link failure".

An OLE DB record is available. Source: "Microsoft SQL Native Client" Hresult: 0x80004005 Description: "TCP Provider: An existing connection was forcibly closed by the remote host. ".

Hmm...what to do. The ETL worked great in stage and in our own QA environment. After an exhaustive troubleshoot (on our client's machine) the fix ended up being...disabling TCP Chimney offloading. Not even on our BI server but on the destination SQL Server!

What!? You say? Your problems with delivery weren't even vaguely related to the technologies you were developing!? Exactly, something not even vaguely related to ETL became a huge friction point between us and a client. The worse part is that there's always a risk of this. Vendors come in and constantly take it on the chin (or sometime just look incompetent) because a dependency they depend on isn't working.

What makes it worse is you may have never even seen that machine in your life, and it's the one that just might bury you. Half the time you don't even have the necessary rights on the given machines to fix it let alone conduct a decent troubleshoot. All of this just might want to make a man take up farming.

This time we did have the necessary rights on the machine. We got lucky and there's even a chance that we might actually get paid for the troubleshoot...this time. Who knows what kind of circus fixes we'll be trying to pull off tomorrow. The good news is that after a while some partners actually start to trust you.

Hope that fix helps some vendor somewhere, we sure could have used it.

My Best,
Tyler

Wednesday, February 18, 2009

STSADM Properties

Wait...There's Another Flag

If you've ever felt like theNewTask STSADM utility is taxed with doing more than Emacs, there's a good chance you're in the majority. I was recently trying to figure out what SharePoint settings affect the "New" icon when I stumbled upon the stsadm's getproperty and setproperty flags.

Essentially there's a bunch of SharePoint settings (some of which there's no admin UI screen for) that can be manipulated using this utility. The new icon is one such property.

It might be worth looking at some of these, they include both server and web application level properties.

Server Properties

Web Application Properties

As it turns out the default value for the new icon is 2 days. You can show and change this property by using the following commands:

stsadm -o setproperty -pn days-to-show-new-icon -pv 2 -url [WebAppUrl]

stsadm -o getproperty -pn days-to-show-new-icon -url [WebAppUrl]

This probably wont interest you in the least until you start to think about scripting and how this might help you ensure certain settings have been set when it comes time to deployment.

While many of these settings might be alterable using the SharePoint API, there are still many types of changes that deserve to be versioned in some kind of script rather than C#.

Best,
Tyler

Sunday, February 15, 2009

Start Your April Fools Jokes Early

Time Waits For No One

For some reason Valentines Day always reminds me that April Fools is coming up. This most likely draws from the fact that I'm the youngest of two siblings, and it's become a personality trait to express my affection by irritating the crap out of an individual.

Needless to say I have very few close friends.

Since nothing says "I care about you" like a good practical joke, I'd like to take the time to remind you that April Fools day is a very short 32 business days away, and depending on how deep your pranks run, you may need to get some infrastructure in place.

The Right Joke For The Right Bloke

A good practical joke is tailored to theapril-fool individual. Knowledge of their technical depth, their patience, any history of violence, and past convictions are key to finding just the right level of crazy.

If you'd like to go shopping for ideas, I'd suggest starting here. My only advise is to be prepared for retaliation. Most pranks usually deserve another, and the minute your cover gets blow, it'll already be too late to start wearing a helmet.

Get Going

So get on it. Usually most April Fools jokes fall apart because people leave them to the last minute. DNS records may need to get updated, proxies may need to get provisioned, machines may need to get hacked. Don't risk leaving it to the last minute, start being devious and subversive today!

I'll share this years war story on April 2nd.

Best,
Tyler

Monday, February 9, 2009

How SharePoint Found Its Content Database

Good Question

I was talking a client through a SharePoint web.config change a couple of weeks ago and he ended up asking a dynamite question.

How does the web application know where its content database is at?

You might say something like "it gets it from the config database", but that would beg another question, "how does it know where the config database is?". In reality, we're curious about how a web application orients itself to its environment when it comes time to respond to a request.

You'll notice that SharePoint web.configs don't have any connectionString elements in them that point to a particular content or configuration database, and SharePoint installs don't make any changes to parent web.configs or machine.configs. So how does this web application orient itself at runtime?

Lets Reflect, Literally

If you think about it, there's a few clues to where this code "ought to be". Pretend for a minute that you were tasked with authoring some piece of functionality that let a web application figure out where its database was at runtime. There's some typical places you'd hook in (besides the web.config). You'd know that this piece of functionality would need to be populated in time to serve requests who would need to know where the content db is at.

You might think about putting it in global.asax Application_OnStart or some http module event that's relatively early in the ASP.NET pipeline.

Lets look at how a typical SharePoint request gets resolved and see if we can't flush out some details. This is the path I took to piece this answer together.

  1. A request comes in and gets handled by IIS. The request matches either a port number or a host header on a web site in the web server.
  2. The matching SharePoint web site has wild card ISAPI mappings that pass all request to ASP.NET. Remember that in a typical ASP.NET web site there mappings for known ASP.NET file extensions (.aspx, .asmx, .ascx, etc...) to the ASP.NET ISAPI filter. When IIS gets a request that ends with the given file extension, it knows that this is an ASP.NET request and hands it off to the aspnet_isapi.dll ISAPI. In a SharePoint IIS web site, we pass everything to ASP.NET. This includes .gifs, .jpegs, .PSDs etc... SharePoint gets a chance to fulfill every requests that gets picked up by the site. Below is a screen cap the wild card mapping present in all SharePoint sites. This is created for you automatically when you provision a new web application. If you were to remove it, your SharePoint instance would no longer be able to serve non ASP.NET files out of the content database. Wildcard mapping that sends ALL requests to the .NET frameowrk and eventually to our SharePoint web application.
  3. Once the request gets handed to ASP.NET, its fair game for the web application to start doing some magic. In fact, it had better figure it out soon cause odds are this request is going to want something from the content database before the page life cycle hits. Because we're talking about the ASP.NET request pipeline (and early in it), it's a reasonable guess to assume an http module could be in play. If we look in the web.config under the <httpModules> section we find that SharePoint has registered an HttpModule named "SPRequest", it's fulfilled by code found in the Microsoft.SharePoint.ApplicationRuntime namespace by a class called SPRequestModule.The SPRequest HttpModule.
  4. If you reflect on SPRequestModule and look into BeginRequestHandler (one of the earlier events in the ASP.NET pipeline), it's obfuscated, but you can read it anyway. BeginRequestHandler makes a call to SPFarm.Local which ends up calling SPFarm.FindLocal in an effort to find the farm that this machine belongs to.
  5. SPFindLocal finally calls into SPConfigurationDatabase.Local which runs to the registry looking for HKLM\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0\Secure\ConfigDB. This is where your "connection string" for the current farm lives.
  6. This is also how SharePoint finds the config database, from there it simply takes the current request and uses it to find the content database (if any) associated with the given request. After all this has been figured out, a lot of it gets cached.
  7. Finally BeginRequestHandler starts through the complex task of mapping your request to a bunch of content in the web applications content database. The regular Page Life Cycle kicks off and at the end of the day we end up with an HttpResponse built up by SharePoint.

Thought that someone else might enjoy the answer. This is kind of a neat piece of functionality too, it allows the psconfig tool to move this machine from farm to farm without changing any web.config files, so long as you can tell it where it should remap the registry key to. And with that, there's a little less magic in the world.

Best,
Tyler

Friday, February 6, 2009

When the Reflector Tells You To Hit The Road

Seeing Obfuscated Code

Like every other .NET developer out here, I'm a big fan of the .NET Reflector. It was originally written by Lutz Roeder but is now maintained by the kind gentleman at Red Gate. One of the elements that make the tool stand out (in addition to the ease at which it lets you navigate/disassembling code), is the ton of add ins on CodePlex that extend the base functionality. If you haven't already, you should explore them some time.

I mostly use the .NET Reflector when it comes to things that I don't quite understand and I can't seem to find an adequate answer on the web. Ninety percent of the time, this tool will usually make it easy for you to look underneath the hood and you can find your own answers.

Every now and then when you're reflecting on code that someone doesn't thing you should see, you'll get the following message from the tool.

This item is obfuscated and can not be translated.

This item is obfuscated and can not be translated.

If your stubborn like most rural mules or have never heard of "no means no", you can carry onward by going to View->Options->Click Dissassembler and set the language to IL.

Changing the language to IL in reflector will let you see obfuscated code.

If you're simply asking for the IL, Reflector will gladly show you the contents of the function (if you can make any sense out of it). Intermediate Language is even harder to read than disassembled MISL that's mapped to C# or VB.NET (which unreadable for another variety of reasons).

Code that was previously obfuscated.

In fact if you're just going to be looking at IL, you can actually skip the .NET Reflector in the first place and use the MSIL Disassembler (ildasm.exe) that comes with the .NET framework. May not look as pretty, but you're guaranteed to have it on any machine which as the .NET SDK.

Here's a disclaimer.

It's also worth mentioning that by reverse engineering code you could be violating an EULA, and I'm hear to tell you that you should never do that. In fact, if you're ever given a piece of code that doesn't function correctly, you should never try to fix it or do anything to further your understand what's going wrong. Often the most legally sound action, is to turn off the computer and go home.

Hope that helps someone find an answer.

Best,
Tyler

Friday, January 30, 2009

Quick Deploys And Assembly Resolution

The Error

We recently ran into the most bizarre error on a clients machine that hosts the central administration web site. Every 15 minutes on the dot we'd get the following error for many different assemblies. The error looked a lot like:

Event Type: Error
Event Source: Windows SharePoint Services 3
Event Category: Runtime
Event ID: 6611
Date: 1/15/2009
Time: 1:11:26 PM
User: N/A
Computer: [MACHINE NAME]
Description:
Error: Failure in loading assembly: [AssemblyName], Version=1.0.0.0, Culture=neutral, PublicKeyToken=e376b6bc65267f90

It's worth mentioning that these errors mentioned the names of assemblies that were used in multiple sites (even though they were deployed into bin folders). The sites that used these assemblies were customized, and their Master Pages and Page Layouts referenced the assemblies that supposedly couldn't be loaded (as far as the error was concerned. Some of these dependencies were strong named and others were not. None of them lived in the GAC (all bin folder deployed).

The Solution

We used the fact that the errors occurred every 15 minutes to link them to Quick Deploy jobs. When we changed the quick deployments to every 10 minutes, the errors followed suit reoccurring at the same interval.

At this point we were convinced that the SharePoint Timer (OWSTimer.exe) was trying to load these assemblies butEssential .NET Volume 1 couldn't find them. So how does assembly resolution happen in the .NET framework? We were saved by an an excerpt from Essential .NET, Volume 1: The Common Language Runtime, a book by Don Box and Chris Sells. Essentially it works like this.

  1. When the assembly loader goes to load an assembly, it first looks to whether the assembly is strong named. If it IS, then the loader first looks in the GAC (not the bin folder).
  2. If it can't find the assembly in the GAC, the loader will then look for <codeBase> hints in the applications configuration file. Remember that these settings inherit down from machine.config to app.config/web.config.
  3. If there's no <codeBase> hints then the loader will resort to probing as a last ditch effort to find the assembly. This includes bin folders and any other location dictated by <probing> elements.

If the above seems confusing, consider the following flow chart.Flow chart speaking to assembly resolution.

We first tried putting hints in the local web.configs, but because the OWSTimer has nothing to do with the our applications, the settings were being ignored. We finally helped the timer out by making the following modifications to the machine.config. To ensure that we didn't remap ALL lookups for the given assembly to the specific location, we had any other application who used the same assembly name override these settings below with a similar one in their own web.config. The overridden setting listed a location that made more sense for the particular web application (ie. web applications should go hunting for .dll's in their own bin folder, not some other applications).

The machine.config was changed to read:

<runtime>  
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="[NameOfAssembly]" publicKeyToken="9871993fa258bc6" culture="neutral" />
<codeBase version="1.0.0.0" href="file://C:/folder/directory/bin/[NameOfAssembly].dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>

The web.config was changed to read:

<runtime>  
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="[NameOfAssembly]" publicKeyToken="9871993fa258bc6" culture="neutral" />
<codeBase version="1.0.0.0" href="file://C:/webapplicationLocation/bin/[NameOfAssembly].dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>

You can also provide <codeBase> hints for assemblies that aren't strongly named, you just need to omit the the optional publicKeyToken and culture attributes. Another tip is that you can also use the <probing> element if you want to probe folders other than the bin folder.

We then restarted IIS, followed by the timer service. Low and behold, our random error went away. This toast goes out to the highly configurable .NET framework, and the expressiveness of app/web/machine.config files.

Best,
Tyler

Tuesday, January 27, 2009

TroubleShooting The JQuery Accordion

JQuery and the Accordion

I've been getting more and more into JQuery recently. It's light, free (as in freedom), and has a vibrant community. Sweetening the deal is the ever growing list of animated controls that effortlessly plug into the framework.

We've been using JQuery for quite a few of our clients who have expressed a desire for more interactive SharePoint sites. I've been so impressed with the framework of late that I've started to advocate it over heavier tools that try to achieve similar results.

The Problem

Just today I ran into a pretty interesting problem with the JQuery Accordion. I'm throwing up this fix because I couldn't find a solution on the web. We had the accordion binding off of a SiteMapDataSource in a SharePoint master page, everything looked great in Chrome, FireFox, and Safari...but IE 6 and 7 were giving us a really hard time.

What made this even more frustrating is that it worked fine in at least three other SharePoint sites with exceedingly similar master pages.

The accordion would flicker at the end of the animation every time the user would expand or collapse a sub menu. We tried removing all the CSS, but the page still yielded the same behavior. The menu would briefly flash the entire contents of a sub menu whenever a a new section was collapsed/expanded. The only way we could stop this was by turning the animation off in entire.

The Troubleshoot

At first I tried debugging the JavaScript for JQuery and the accordion, but the source quickly became difficult to follow. The guys who wrote this stuff have mad JavaScript skills, they're head over heels better JavaScript developers than I am.

So I ended up doing what I normally do when I don't understand what's going on. I started to make things simpler. I opened up SharePoint Designer and started removing sizeable sections of the page, block by block, seeing if I could get the problem to go away. I ended up with a ridiculously small html document that basically had the the accordion menu markup and a couple of other html tags.

It was only when the document was about forty lines long that the problem became apparent.

There was no doc type on the html document. I've written about Quirks Mode before, so I was a little embarrassed that I hadn't noticed it earlier. If you're not familiar, or are too lazy to click on the link above, in a nutshell quirks mode is a special rending mode that browsers go to when you either don't specify the doc type or use html that deviates from the declared doc type. The rules for what justifies quirks mode rendering changes from browser to browser. For IE, not declaring a doc type will cause it to render the page in quirks mode.

Quirks mode changes the way that the browser handles CSS rules. When we failed to declare a doc type, IE started rendering the menu in quirks mode. This changed the way that the browser handled the in line CSS that the JQuery accordion was tacking onto menu list markup. Hence the odd behavior.

I added my favorite and most relaxed doc type:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

Low and behold, the animation issue went away. Quirks mode strikes again. I guess the lesson here is that before you get to involved in a markup troubleshoot, ensure the document isn't being rendered in quirks mode! You can figure out how to detect quirks mode by reading this.

Fool Me Twice,
Tyler

Thursday, January 22, 2009

SharePoint: Searching With Managed Properties

Crawled and Managed Properties

When the SharePoint 2007 crawler indexes a piece of content, it finds a not only a bunch of text to index, but also a tonne of metadata about the document. These pieces of metadata are referred to as crawled properties. Consider an Office 2007 Word document (.docx). When the crawler opens up the document, it finds a plethora of information about the file; the file extension, who authored it, when it was created, and the actual text in the document itself. These are just some the many crawled properties captured about any given piece of content. What fields actually get captured are a function of the content and the IFilter that helped the crawler dissect the document.

Here's a reduced screen cap of some of the crawled properties captured for Office Documents. Crawled properties (for Office documents) captured by the SharePoint CrawlerYou can sift through all the properties that are being captured by your crawler by going to the Shared Service Provider, then clicking on Search Settings, Metadata property mappings and then on Crawled Properties. If you click on the Office category you'll end up getting a list that's much longer than the abridged one on the right. Whenever the crawler discovers a new property, it adds the new crawled property to a list maintained in the Shared Service provider. If the property discovered is of type text, then it is automatically added to the search index.

It's important to note that a Crawled Property can be reused in many Managed Properties, and Managed Properties can have mappings from many Crawled Properties (many to many). In fact this is how we harvest value from the Crawled/Managed property marriage. By using them together we can construct extremely powerful and expressive search queries.

Managed Properties are user created labels, that map one or more crawled properties to a searchable term. They are available for basic search, advanced search and for defining scopes. An example of a search expression using a managed property might be the search:

Title:"Tyler"

When I search Title:"Tyler" (read [ManagedProperty]:"[SearchTerm]"), I'm really searching all the crawled properties that are mapped to the managed property Title, for the text "Tyler".

That is, the search expression Title:"Tyler" will bring back all the search results that have the text "Tyler" in at least one of the following crawled properties [Mail:5(Text), People:PreferredName(Text), Basic:displaytitle(Text), ows_Title(Text)]. In fact if you feel that the crawled properties attached to Title aren't sufficient, you can make any changes you want. Managed properties are there for you to explore and tweak.

Creating a Managed Property

You don't really have a lot of control over crawled properties (you simply get what the indexer picks up). You do however get a fair bit of hand over what managed properties exist, and what crawled properties are mapped to them. It's worth mentioning that you don't always need to install a new IFilter to get more crawled properties to show up. The indexer will also pick up custom site columns that you add to your lists/libraries every time it does a full crawl. If this site column has never been seen before (ie. you just created it), a new entry will be added to the crawled properties list.

A good example of this would be if you were to create a new site column (say MyCustomeField) on some list. The nextCreating a Managed Property using a crawled property discoverd from a custom data type. time the indexer does a full crawl, the new crawled property will show up (named ows_MyCustomeField). You can then open up Metadata Property Mappings (from the Shared Service Provider Search Settings) and create a new managed property (say TylersCustomField) that users can use to search exactly that site column. They could, for exaple search for TylersCustomeField:"SomeValue". You can even use that managed property to limit or grow the search results that are governed by any search scope.

When you start to digest the utility of Managed/Crawled properties, it becomes apparent they they're responsible for a huge part of the SharePoint search's expressiveness. They empower you to help users author some pretty functional searches. Not just the kind of searches that find all the documents with a certain file extension (fileextension:"doc", but searches that look only at very custom properties within niche types of content.

Consider the following out of the box managed properties that allow searching for people by their assistant's name (Assistant:"Mary"), by their Responsibilities (Responsibilities:"Sales"), or finding files by filename (filename:"my document"). Managed properties can also be grouped in searches (fileextension:"doc" filename:"my document").

Stop by the Managed Properties pages in the Shared Services Provider and you'll be impressed. Once you start to wrap your head around managed properties, you'll realize how easy it is to leverage this out of the box functionality for your customers. You'll may even start to feel like SharePoint is finally making your job easier.

Best,
Tyler

Sunday, January 18, 2009

Turn On The Search Already!

ROI Unleashed

When IT departments roll out SharePoint, search is usually the last thing on their minds. This is really a shame, because powerful enterprise search is one of the most underutilized features that comes out of the box with MOSS Standard or Enterprise. You get search with WSS too, but you can only search a given site collection.

MOSS allows you to search across a whole enterprise unifying rogue document shares, reclusive business data, and your actual SharePoint content. People can also search for People and find internal resources that possess a particular skill set, or report to a given manager.

Business units naturally tend to carve out their own space for storing tribal knowledge. This is usually irritating to system administrators and confusing to new hires (never mind existing employees). One of the easiest corrective actions is to tell SharePoint to go index all these pieces of hidden content and yield them when the appropriate search string is entered.

Creating a search portal is one of the most obvious value adds that you can quickly provide your users. I can't think of any organization I've ever worked with that didn't have documents scattered across the enterprise. In a day and age when IT is constantly trying to justify it's ROI, turning the key on enterprise search is an easy home run.

What's even better is that SharePoint Search will automatically security trim based on ACL (Access Control List) entries that are found on the content. Microsoft Office SharePoint 2007 Administrators CompanionThis means that if you're indexing an NTFS share that only the DOMAIN\HR users can access, you don't have to worry about the search engine yielding those documents as search results when searches are done by the DOMAIN\Marketing folks. This holds true for SharePoint content which also exposes ACLs to the SharePoint indexer.

If you're completely new to search, consider reading the search chapters in Bill English's Microsoft Office SharePoint Server 2007 Administrator's Companion. While it's not specifically geared to search, it'll speak to search in general and all the topics directly related to search. It's probably the most complete SharePoint reference out there. I like to think of it as the MOSS Bible for all things general and out of the box. If you're looking for a more in depth title more specifically targeted to search, consider Inside the Index and Search Engines: Microsoft Office SharePoint Server 2007 (PRO-Developer).

Fire It Up

If you haven't done so already, consider creating a portal site for your enterprise. After that, create a Search Center somewhere off that root site.

All that's left to do is open up the Shared Service Provider for your farm and start adding content sources. After you perform a full crawl, a myriad of documents that used to be extremely hard to find (or at least required Sherpa like navigation knowledge) will start to show up as search results for anyone who had access in the first place. Start small if you have a tonne of content to index and aren't currently in a large farm set up, but have a little faith in the product too. Even a stand alone installation can easily maintain an index for thousands of documents, and when you need to scale your farm out, rest assured that it's very possible. Many different content sources pulling together enterprise content

If you're part of a huge organization then search becomes a more interesting topic in the sense that indexing millions of documents and setting up the security around all this content is a big job. But the point of this post is to make you more aware of SharePoint search and took at it as a relatively easy value add. Take comfort in the fact that this out of the box search feature (MOSS Standard/Enterprise) will do things that even $10,000 Google Mini's won't. You owe it to yourself to at least start playing with it.

In future posts we'll get into Managed and Crawled Properties, search Scopes, Content Sources etc..., the purpose of this is simply to get you enthused about search. There's no replacement for good planning and a solid information taxonomy, but when information is already scattered to the winds nothing helps round up lost documents like a good search engine.

Good Luck,
Tyler

Thursday, January 15, 2009

STSADM Restore Errors With SQL SERVER Express

But There's Tonnes of Disk Space!

The other day I was migrating a site collection from one machine to another. I had a copy of the source site collection and was ready to restore it on this new machine that another developer had prepped. I created a SharePoint web application at the destination and then proceeded to run the restore command:

stsadm -o restore -url http://someurl -filename c:\file.bak -overwrite

After a while I ended up getting some disgruntled feedback from the stsadm tool:

The site collection could not be restored. If this problem persists, please make sure the content databases are available and have sufficient free space.

Which was confusing, I made sure there was tonnes of disk space (20 GB free for the restore of a 3 GB site collection) and tried again...it died with the same error. After poking around I noticed something odd after running the following query in the Management Studio:

SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'), SERVERPROPERTY ('edition')

As it turns out, the database server I was trying to restore the site collection into was running SQL Server Express Edition which has a file size cap of 4 GB. When this "farm" was set up, it was done so with a Basic install which by defaul installs SQL Express and inherits it's limitations. The site collection I was trying to restore was breaking the 4 GB limit and as a result the stsadm tool thought there wasn't any disk space available, when really there was a bunch to be had..

Upgrading SQL Server Express to Developer/Standard/Workstation/Enterprise

As a result I had to upgrade the OFFICESERVERS instance of SQL Server running on that machine from Express to Developer (you can upgrade it to Developer/Standard/Workstation/Enterprise, whatever you have in terms of media/licensing).

This ends up being pretty easy, you simply find the media/installer and run the setup.exe that you normally would but with an added argument of SKUUPGRADE=1.

setup.exe SKUUPGRADE=1

When the install wizard gives you get a chance, select the OfficeServers instance and upgrade the database engine. If you want a more detailed walkthrough, one is available here. When you're done, run the same SQL query above and the product edition should no longer be Express.

After that small adventure, the restore worked like a charm.

Hope that helps someone.

Best,
Tyler

Tuesday, January 13, 2009

Big Fat Content Deployment Jobs

The Blessings and Woes of Content Deployment

If you've spent a lot of time dealing with Incremental Content Deployment Jobs, then you've most likely either developed the patience of a saint, or a taste for 80 proof liquor.

This particular feature has worked, and then not worked over a series of SharePoint patches. For example, it didn't work under RTM for many sites, then a hot fix corrected the behavior. It was then broken again for most web applications under service pack one, which was followed by a fix in the Infrastructure Update.

Because this particular feature has dealt the world so much hair loss, a lot of clients I've met with have resorted to using full content deployment jobs to get their content from one site collection to another.

The key difference between the two is that an incremental deployment job will deploy only changes (new records, updates, and deletes). A full content deployment job will deploy everything in the site/branch/site collection that you select (that is, it will deploy a copy of the current version, not the version history as well). If you select a site, you're about to get another copy of every asset in that site. If you select the entire site collection, there's even more content that's about to get duplicated.

Hold Off On That Full Content Deployment

The real problem with resorting to full content deployments is that if you're prone to using them too often your content database size can go through the roof. For those who normally deal with SharePoint capacity and planning, this can be a nightmare. The last thing you want is bloated a content database with duplicate copies of 40 MB PowerPoint presentations coupled with the HR departments prized PDF collection.

A particular client we work with ended up using full content deployments for sub sites about 6 months ago because they couldn't get incremental content deployments to work. Before they knew it their destination site collection was 16 times the size of the source site collection. Luckily this particular content database was pretty lean (about 150 MB, and so the destination only ended up being ~2.5 GB). Imagine if they had a source site collection that was around 50 GB (which is very common for many intranet site collections), they'd be looking at a destination site collection which would be ~ 0.8 TB, a near unmanageable (or at least painful) amount of data for most small to medium IT shops.

No one really wins when it comes to regular full content deployments. Even if there's quotas on the site collection the inherent duplication still steals space that users could otherwise use to store useful data. If patching it isn't something you feel you can easily do yourself consider contacting MS SharePoint Support, they're not half bad, and they're pretty cheap ($250 last time I checked).

If you're not already convinced, here's a couple screen caps of data pulled from  Red Gate SQL Data Compare detailing the differences on just a small site. The first cap is a before/after comparison of a sub site being deployed using an incremental job after a small change as taken place (content edit).

The second screen cap is of the same site before/after a full content deployment job targeting the same sub site.

Record Difference Before and After an Incremental Content Deployment

 SQLCompareIncremental

Record Difference Before and After a Full Content DeploymentSQLCompareFull

These results will of course dramatically change with the site of your site collection and what you're doing a full content deployment on. The point is just to offer a reminder that the unnatural growth of the content database just may not be worth it in the long run. If you're currently wed to full content deployments I'd suggest either getting a divorce ASAP, or investing in some sizable disks to help manage the data explosion.

Buying more disks,
Tyler

Wednesday, January 7, 2009

Don't Rule Out MS Support For Help

Someone Call Redmond

SharePoint 2007 has been out for over two years now. Even though I'm a fan of the product, I'd be the last one to tell you that there haven't been glaring bugs with some of the more prominent features. The good news is that over time, hot fix by hot fix, these are slowly getting resolved.

Depending on what you've been using SharePoint for, your mileage may have varied significantly. Until a couple days ago, all of the solutions and workarounds I'd ever applied to the product had come from forums, blogs, white papers, and books. Last week we ran into a problem that we’d flailed at for long enough and decided to enlist the help of Microsoft Support. This is a recount of that experience.

Issues with Content Deployment

We were running MOSS 2007 SP1 and were having problems with incremental content deployments. We were considering deploying the SharePoint Infrastructure Update which supposedly addresses the issue. We were reluctant to deploy the updated because of the related downtime our farm would incur (this particular farm is public facing and gets tens of thousands of visitors a day). If possible we wanted to find another way.

So we decided we’d push the problem onto The Soft and let MS Support deal with it. $250 later, a support ticket was opened. Contrary to the complaints I’d found online there was little to no wait, and within a couple business days someone from MS Support was calling me every morning asking me when we could start working on the ticket.

Although it was probably a different story when the product first launched, it doesn’t seem like there are Black Friday style wait lists for support these days. We also read this post by Eric to help us properly characterize the problem for MS Support. It’s of note that even though we provided a fair amount of detail in the opening emails, I ended up repeating the details back to the support agent anyways.

The troubleshoot went surprisingly well. The support engineer was attentive to our concerns and very thorough in her diagnosis. Although she had a very distinct accent, she was on our time zone (PST) and had exceptional product knowledge. What’s even better is they were willing to work around my extremely varied schedule and were relatively high touch. Someone from the support team phoned and emailed me at least every day, even if I forgot to return their emails. At times I felt like they wanted to fix our issues more than we did. All in all I’d give the experience an 8/10 and recommend it to anyone who feels like they’re grasping at straws.

The money ($250) is relatively cheap compared to your time, and you’ll get a chance to ask a ton of product related questions. What’s even better is that if your problem ends up being fixed by a patch (hot fix/update/service pack) or is related to a product deficiency (you use a work around to resolve it) there’s a strong chance that you’ll be refunded the $250. Ultimately the decision is supposed to be up to the support engineer’s manager. All this is from the mouth of a support engineer, so give it the same credence as you would most hearsay.

I guess the point of all this is to not rule out MS Support when it comes to SharePoint issues. By all means exhaust your regular avenues first, but don’t be afraid to ask for help from Microsoft Support when you start to feel all alone. The process requires a lot of patience, but depending on the problem it may be the cheapest way to fix the problem. Ideally having good support is one of the reasons your company decided to go with a well known vendor in the first place.

One Less Problem,
Tyler