Category Archives: SharePoint

All SharePoint related posts

Deleting Orphan Template Files from SharePoint 2007 for Upgrade to 2010


I’ve been working on knocking out some issues from the Pre-Upgrade Check Report in order to get ready for our upgrade to SharePoint 2010 and recently hit one heck of a snag where certain artifacts that were created way back in 2003 were somehow still being referenced but not actually used anywhere in 2007.  These items never existed in the 2007 file system and were certainly not visible in any way from the UI.

The items appeared under the “Missing server file or server configuration issues” section of the report under the specific title of “The following setup file(s) are referenced by the content, but they are not installed on the web server”.  They were part of old Site Templates that were fortunately all named starting with “STSFA”.  To find out where SharePoint thought these items were required diving into the content database (Sorry, but the additional data Microsoft provides for these errors is close to useless)  the SQL used is below but the fields of concern are DirName and LeafName:

select * from AllDocs with (nolock)
    where SetupPath like 'SiteTemplates\STSFA%' 
    order by DirName

In my case, I had the following URLs that were being kicked out – “/RealFolder/03folder/default.aspx”. RealFolder exists (obviously) but 03Folder does not, yet SharePoint claimed it did on the Pre-Upgrade report.

It turns out that these items were in a state where, depending on how you looked at them, they were either orphaned or were not orphaned.  Go ahead, put on your Kenobi robe on and wrap your brain around that, I’ll wait.  Back?  Ok, good.  Perhaps a better term for these types of items might be “disowned” rather than orphaned.

After some digging in the Object Model, it turned out that if you use certain methods to access the item, like GetFile() or GetFolder() that it could see the items but it only returns a subset of the data that SharePoint has about the object. The objects returned from these methods always had several properties, including ParentWeb listed as empty. When I attempted to call .Delete() on the item, it would throw the ever popular “Object or reference not set…” exception.

The PowerShell below is a summary of how I got past that issue and it includes the comments as to why the steps are there.  Yes, I could have written this as a C# console application as well, but I wanted to keep it in PowerShell so that the other Admins would know exactly what the script was doing.

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[Microsoft.SharePoint.SPSite]$site = [Microsoft.SharePoint.SPSite]("http://SiteUrlGoesHere/")
$fileUrl = "http://SiteUrlGoesHere/RealFolder/03Folder/default.aspx"

#get a handle to the web that thinks it contains the orphan
[Microsoft.SharePoint.SPWeb]$parentWeb = $site.OpenWeb($fileUrl, $false)

#Get a handle to the object itself.  
#for some reason, this call brings back way more information than GetFile(), 
#not the least of which is the Guid to the actual object $tempFile = $parentWeb.GetObject($fileUrl) #use the Guid to get the real object [Microsoft.SharePoint.SPFile]$oldFile = $parentWeb.GetFile($tempFile.UniqueId) #Now make all your dreams come true #oldFile.Delete() #but don't forget to clean house $parentWeb.Dispose()

I tried about 7 variations on the above method, including trying to open the items from the root of the site, using GetFile() directly, etc..  This was the only version I tested that actually deleted the items from the SharePoint database. 

The best part about this is that the update is done completely via the Object Model so it is a fully supported way to cleanup these types of orphaned files.

Custom Site Columns missing from Search Metadata Properties


I have been working a lot more with SharePoint search lately and have been enjoying it for the most part.  Except recently when I started seeing a problem where my custom site columns were not appearing in the list of available Metadata Properties in Search Administration.

After a great deal of research and experimentation, the problem turned out to be that the standard SharePoint Http Response Header was either removed from IIS or was never added.  In either case, adding this header back in let the crawler in to see all of the appropriate metadata

Name : MicrosoftSharePointTeamServices
Value : 12.0.0.6341

This is set in Start –> Control Panel –> Administrative Tools –> IIS Manager –> [Your Server] –> Sites –> [Your SharePoint Site]  -> HTTP Response Headers

Once I had figured out the answer, I started looking for more information about why that header seems so important.  Nothing.  I did discover that if you search only the Microsoft site for this header, you will find all sorts of SharePoint related mischief when it is missing, from bad Urls to authentication errors and beyond.

My guess is that the crawl uses this to determine how it should attempt to index a site.  If it sees this header then it crawls it as a SharePoint site (including all metadata) but if it doesn’t, it then treats the site as a standard web site.  Experimentation bears this out.  I created a test case where my primary navigation control was not visible during a crawl.  If I remove the header, the index can only see  the links directly on the home page, but if I add the header and do not change anything else, it crawls everything in the SharePoint site, even though there is no navigation pointing to those pages.

Some detailed information from Microsoft about this header would be nice as I know that some security professionals advocate stripping all http response headers out of websites in order to minimize surface area. I can easily see a situation where this condition would be created.

Inside the SharePoint People Picker


SharePoint provides a handy control commonly known as a “people picker” that allows users to search for and select users defined at some specified scope.  This control is normally associated with Personnel field in a SharePoint List.  However, what happens when you need to add this functionality to some custom component and need to access it programmatically?  It gets a lot more complicated!

Fli5A

This article is meant as more of a repository of knowledge that I’ve discovered while working with this control rather than a “how-to”.  If you are looking for How-To articles, try these: Eric Kraus or SharePoint Tips.   Likewise, please let me know if you have any additional information about the actual workings of this poorly documented control.

Where to find the control

The control is actually called a “PeopleEditor” and is in the ‘Microsoft.SharePoint.WebControls‘ namespace.  You will need to add a reference to ‘Microsoft.Sharepoint.dll’ to your project in Visual Studio, which is something you probably already have if you are writing anything that works with SharePoint.

What is it?

The PeopleEditor is simply a standard UserControl with it’s own hierarchy of elements.  If you were to walk the tree of controls used, you would see the structure shown below  (control IDs are in green italics).

Microsoft.SharePoint.WebControls.PeopleEditor
|-System.Web.UI.HtmlControls.HtmlInputHidden (hiddenSpanData)
|-System.Web.UI.HtmlControls.HtmlInputHidden (OriginalEntities)
|-System.Web.UI.HtmlControls.HtmlInputHidden (HiddenEntityKey)
|-System.Web.UI.HtmlControls.HtmlInputHidden (HiddenEntityDisplayText)
|-System.Web.UI.WebControls.Table (OuterTable)
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.Table
|- |- |- |- |-System.Web.UI.WebControls.TableRow
|- |- |- |- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |- |- |- |-System.Web.UI.HtmlControls.HtmlGenericControl (upLevelDiv)
|- |- |- |- |- |- |-System.Web.UI.WebControls.TextBox (downlevelTextBox)
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.HyperLink (checkNames)
|- |- |- |-System.Web.UI.LiteralControl
|- |- |- |-System.Web.UI.WebControls.HyperLink (browse)
|- |- |- |-System.Web.UI.LiteralControl
|- |- |- |-System.Web.UI.HtmlControls.HtmlInputButton (CreateItem)
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.PlaceHolder
|- |- |- |- |-System.Web.UI.WebControls.Label (errorLabel)
|- |- |- |- |-System.Web.UI.WebControls.Table
|- |-System.Web.UI.WebControls.TableRow
|- |- |-System.Web.UI.WebControls.TableCell
|- |- |- |-System.Web.UI.WebControls.Label

Of particular interest are upLevelDiv and downlevelTextBox as those are the controls used when a person is manually entering a name.

Developing With It

The default behavior and styling is sufficient in most cases.  However, if you need to do more than the very basics with the control then I strongly recommend that you subclass it so that you can hook into the control behavior at a much deeper level.  Some of the things you get with this approach are:

  • Control over Formatting.  Microsoft hard-codes much of the formatting in the control and buries it behind protected methods so that you can’t touch it from the outside.  Microsoft applies the style between the PreRender() event but before the SaveViewState() event.  In order to change the style used, you will need to override the Render() event and apply your style changes immediately before the actual control is rendered.
  • OnChange event.  There is none exposed but by subclassing it you can create your own and then hook into the RaisePostDataChangedEvent() method in order to raise your own.
  • Access to the actual controls used.  All of the controls used by the people picker are available as protected properties which means that your subclass has direct access to them without having to walk the hierarchy.
  • Future Changes.  By subclassing this control at the beginning and coding to your new class, you are laying the foundation so that you don’t have to redo tons of code later on in the event that you find yourself needing some of the protected behaviors.

Quirks

  • Normally, you will want to work with the .Entities collection as that has the most information available about a selection but there is a great big “Gotcha” here.  You need to reference .CommaSeparatedAccounts property before calling .Entities because the collection seems to only get populated after that property is referenced.
  • Another Gotcha is that the control will do an Active Directory lookup of all the names you enter in .CommaSeparatedAccounts so it can be a bit of a performance hit – especially if one of those names isn’t in AD.  In my environment, populating this with one valid name takes 0.1 seconds.  Not much, but if you have several of these controls populated with several names then that quickly adds up to real time.
  • The .Entities collection is sometimes null so you have to be careful when working with it.  Given that normal development practices dictate that all public collections exist but have a .Count of zero, I have to assume that this is either developer oversight or an indication of some internal state.  In either case, watch what you are doing when working with this and always check it against null before referencing properties of it.
  • The RaisePostDataChangedEvent event seems to fire whenever the page is posted back a second time even if the value hadn’t changed.
  • Since this is actually a SharePoint control, it expects a few things to be in place – specifically that SharePoint’s “core.js” be included on the page.

Styling the Control

Microsoft embeds the formatting for the control deep inside and then makes use of the .Style attribute rather than the .CssClass attribute which makes styling it somewhat problematic as the .Style attribute will override anything in your CSS.  To make this a little bit worse, this control renders differently in IE than in other browsers like Firefox so you will have to solve styling for both browsers.

Here is what the control renders as in Internet Explorer (I’ve highlighted the key styling areas and their associated class)

Fli8E

Here is how it renders in Firefox.  Note that the resolved user name shown is the Domain ID instead of the user name like in IE.  Also, this is a simple textbox instead of the textbox/div combo that IE uses.

Fli29B

Tracking down what style is used where is made considerably easier with tools like the Developer Toolbar for IE and FireBug for Firefox – both free.  These tools allow you to inspect page elements as they are currently rendered, showing the hierarchy of styles, controls and such.  They are invaluable if you will be doing considerable tweaking to the layout of the People Picker.

Validation

There is an internal validator that allows you to validate the names entered (both on client and on Page Postback) and it works like any other validator in Asp.Net.  You can enable this by setting the .ValidatorEnabled property to “True”.

It is worth noting that this is merely an implementation of the IValidator interface so it cannot be cast as one of the standard Validator types (CustomValidator, RangeValidator, etc.).  This can be problematic if you are trying to work with it via the Page.Validators() collection as the IValidator interface doesn’t really provide enough information to be useful.  In my case, I had to cast it as my subclassed version of the PeopleEditor control and then get the values I needed that way.

Helpful Links

SharePoint Dev Tip – Restart the Timer


The SharePoint Timer service is handy for what it does but it occasionally gets very hungry and devours hundreds of megs of RAM and keeps it for hours.  This isn't a problem on most production environments because of the memory those machines typically have but it can be a killer on a memory challenged dev Virtual Machine.

The most common symptoms that I've run across is that starting Visual Studio in Debug Mode takes 2-3 times as long as normal and stepping through the code is painfully slow.  When this happens, I restart the timer and all is well again.

I used to do this from the Control Panel but found that there is a much more efficient method: use a batch file with the commands below and just run it periodically.  I have a shortcut to this in my Quick Launch menu and run it before starting any development.

net stop "Windows SharePoint Services Timer"
net start "Windows SharePoint Services Timer"

Of course, if you happen to be doing work that doesn't rely on the Timer functionality (which is most likely the case) then you could always turn off the service and avoid the problem entirely.

Accessing SharePoint List Data as XML


The other day, I found myself in need of a way to access SharePoint list data as XML but the only method available to me was a simple http GET.  This is not too bad, but what can I get from SharePoint via GET?  RSS is too limited and scraping the page is too painful and error-prone to even contemplate. 

It turns out that there is an option available in 2007 that was carried forward from SharePoint 2003 / FrontPage days: owssvr.dll.  But this isn't some forgotten FrontPage artifact, it is still a central part of SharePoint.  In fact, if you pull up a list view and then view the source looking for owssvr.dll, you will see that this is the mechanism behind both the Export to Spreadsheet and Open with Access options on the list Actions menu.

How It Works

Simply put together a URL like this:

http://MyServer/%5Bsite%5D/_vti_bin/owssvr.dll?Cmd=Display&List={listGuid}&XMLDATA=TRUE

This will only return the fields that are defined on the default view of the list.  If you need specific fields then you need to create a view with those fields and pass the View ID as well, like this:

http://…/owssvr.dll?Cmd=Display&List={listGuid}&view={viewGuid}&XMLDATA=TRUE

Specifying Fields to be Returned

There is also a Query parameter that lets you specify which fields are to be included in the resulting XML, regardless of how the view is defined.  For example, if you wanted just to bring back the Title and Status Fields, you would add the field names separated by spaces (URL Encoded, of course) like "&Query=Title%20Status".  If you want to return all fields, use an asterisk (*) instead of field names.

http://…/owssvr.dll?Cmd=Display&List={listGuid}&query=Title%20Status&XMLDATA=TRUE

Filtering Data

Regardless of whether you pass a view or use the default it will still use the filter defined by that view.  Not bad, but you can trim this data even more by including a filter of your own using the FilterFieldn and FilterValuen arguments in the querystring.  These are the same values that are passed when you use the filter options in the column headers of a view which makes it pretty easy to track down exactly what needs to be passed.  Simply pull up the view that is your starting point and use the column filters to create your desired filter.  Once you have it, grab all of the FilterField and FilterValue items from the querystring and add them on to yours.

http://…/owssvr.dll?Cmd=Display&List={listGuid}&query=Title%20Status&XMLDATA=TRUE&FilterField1=Status&FilterValue1=In%20Progress

For a full list of what can be done with this technique, check out the URL Protocol or the older Using the URL Protocol on MSDN.