<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>SharePoint Interface &#187; Development</title>
	<atom:link href="http://sharepointinterface.com/category/sharepoint-2007/development/feed/" rel="self" type="application/rss+xml" />
	<link>http://sharepointinterface.com</link>
	<description>Multidisciplinary discourse on the topics of SharePoint architecture, development, and administration.</description>
	<lastBuildDate>Mon, 06 Feb 2012 14:11:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='sharepointinterface.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>SharePoint Interface &#187; Development</title>
		<link>http://sharepointinterface.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://sharepointinterface.com/osd.xml" title="SharePoint Interface" />
	<atom:link rel='hub' href='http://sharepointinterface.com/?pushpress=hub'/>
		<item>
		<title>Finding Duplicate GUIDs in Your SharePoint Site Collection</title>
		<link>http://sharepointinterface.com/2011/04/03/finding-duplicate-guids-in-your-sharepoint-site-collection/</link>
		<comments>http://sharepointinterface.com/2011/04/03/finding-duplicate-guids-in-your-sharepoint-site-collection/#comments</comments>
		<pubDate>Sun, 03 Apr 2011 18:41:41 +0000</pubDate>
		<dc:creator>Sean McDonough</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[SharePoint 2007]]></category>
		<category><![CDATA[SharePoint 2010]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Import/Export]]></category>
		<category><![CDATA[linkedin]]></category>
		<category><![CDATA[MOSS]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[SP2010]]></category>

		<guid isPermaLink="false">https://sharepointinterface.wordpress.com/?p=579</guid>
		<description><![CDATA[In this self-described "blog post you should never need," I talk about finding objects with duplicate GUIDs in a client's SharePoint site collection.  I supply the PowerShell script used to find the duplicate GUIDs and offer some suggestions for how you might remedy such a situation.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sharepointinterface.com&amp;blog=7883095&amp;post=579&amp;subd=sharepointinterface&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This is a bit of an oldie, but I figured it might help one or two random readers.</p>
<p>Let me start by saying something right off the bat: you should never need what I’m about to share.&#160; Of course, how many times have you heard “you shouldn’t ever really need this” when it comes to SharePoint?&#160; I’ve been at it a while, and I can tell you that things that never <em>should</em> happen seem to find a way into reality – and into my crosshairs for troubleshooting.</p>
<h3>Disclaimer</h3>
<p>The story and situation I’m about to share is true.&#160; I’m going to speak in generalities when it comes to the identities of the parties and software involved, though, to “protect the innocent” and avoid upsetting anyone.</p>
<h3>The Predicament</h3>
<p>I was part of a team that was working with a client to troubleshoot problems that the client was encountering when they attempted to run some software that targeted SharePoint site collections.&#160; The errors that were returned by the software were somewhat cryptic, but they pointed to a problem handling certain objects in a SharePoint site collection.&#160; The software ran fine when targeting all other site collections, so we naturally suspected that something was wrong with only one specific site collection.</p>
<p>After further examination of logs that were tied to the software, it became clear that we had a real predicament.&#160; Apparently, the site collection in question contained two or more objects with the same identity; that is, the objects had ID properties possessing the same GUID.&#160; This isn’t anything that should ever happen, but it had.&#160; SharePoint continued to run without issue (interestingly enough), but the duplication of object GUIDs made it downright difficult for any software that depended on unique object identities being … well, unique.</p>
<p>Although the software logs told us which GUID was being duplicated, we didn’t know which SharePoint object or objects the GUID was tied to.&#160; We needed a relatively quick and easy way to figure out the name(s) of the object or objects which were being impacted by the duplicate GUIDs.</p>
<h3>Tackling the Problem</h3>
<p>It is precisely in times like those described that PowerShell comes to mind.</p>
<p>My solution was to whip-up a PowerShell script (<strong>FindDuplicateGuids.ps1</strong>) that processed each of the lists (<strong>SPList</strong>) and webs (<strong>SPWeb</strong>) in a target site collection.&#160; The script simply collected the identities of each list and web and reported back any GUIDs that appeared more than once.</p>
<p>The script created works with both SharePoint 2007 and SharePoint 2010, and it has no specific dependencies beyond SharePoint being installed and available on the server where the script is run.</p>
<p>
<pre class="brush: powershell;">
########################
# FindDuplicateGuids.ps1
# Author: Sean P. McDonough (sean@sharepointinterface.com)
# Blog: http://SharePointInterface.com
# Last Update: June 25, 2010
#
# Usage from prompt: &quot;.\FindDuplicateGuids.ps1 &lt;siteUrl&gt;&quot;
#   where &lt;siteUrl&gt; is site collection root.
########################


#########
# IMPORTS
# Import/load common SharePoint assemblies that house the types we'll need for operations.
#########
Add-Type -AssemblyName &quot;Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c&quot;


###########
# FUNCTIONS
# Leveraged throughout the script for one or more calls.
###########
function SpmBuild-WebAndListIdMappings {param ($siteUrl)
	$targetSite = New-Object Microsoft.SharePoint.SPSite($siteUrl)
	$allWebs = $targetSite.AllWebs
	$mappings = New-Object System.Collections.Specialized.NameValueCollection
	foreach ($spWeb in $allWebs)
	{
		$webTitle = &quot;WEB '{0}'&quot; -f $spWeb.Title
		$mappings.Add($spWeb.ID, $webTitle)
		$allListsForWeb = $spWeb.Lists
		foreach ($currentList in $allListsForWeb)
		{
			$listEntry = &quot;LIST '{0}' in Web '{1}'&quot; -f $currentList.Title, $spWeb.Title
			$mappings.Add($currentList.ID, $listEntry)
		}
	}
	return ,$mappings
}

function SpmFind-DuplicateMembers {param ([System.Collections.Specialized.NameValueCollection]$nvMappings)
	$duplicateMembers = New-Object System.Collections.ArrayList
	$allkeys = $nvMappings.AllKeys
	foreach ($keyName in $allKeys)
	{
		$valuesForKey = $nvMappings.GetValues($keyName)
		if ($valuesForKey.Length -gt 1)
		{
			[void]$duplicateMembers.Add($keyName)
		}
	}
	return ,$duplicateMembers
}


########
# SCRIPT
# Execution of actual script logic begins here
########
$siteUrl = $Args[0]
if ($siteUrl -eq $null)
{
	$siteUrl = Read-Host &quot;`nYou must supply a site collection URL to execute the script&quot;
}
if ($siteUrl.EndsWith(&quot;/&quot;) -eq $false)
{
	$siteUrl += &quot;/&quot;
}
Clear-Host
Write-Output (&quot;Examining &quot; + $siteUrl + &quot; ...`n&quot;)
$combinedMappings = SpmBuild-WebAndListIdMappings $siteUrl
Write-Output ($combinedMappings.Count.ToString() + &quot; GUIDs processed.&quot;)
Write-Output (&quot;Looking for duplicate GUIDs ...`n&quot;)
$duplicateGuids = SpmFind-DuplicateMembers $combinedMappings
if ($duplicateGuids.Count -eq 0)
{
	Write-Output (&quot;No duplicate GUIDs found.&quot;)
}
else
{
	Write-Output ($duplicateGuids.Count.ToString() + &quot; duplicate GUID(s) found.&quot;)
	Write-Output (&quot;Non-unique GUIDs and associated objects appear below.`n&quot;)
	foreach ($keyName in $duplicateGuids)
	{
		$siteNames = $combinedMappings[$keyName]
		Write-Output($keyName + &quot;: &quot; + $siteNames)
	}
}
$dumpData = Read-Host &quot;`nDo you want to send the collected data to a file? (Y/N)&quot;
if ($dumpData -match &quot;y&quot;)
{
	$fileName = Read-Host &quot;  Output file path and name&quot;
	Write-Output (&quot;Results for &quot; + $siteUrl) | Out-File -FilePath $fileName
	$allKeys = $combinedMappings.AllKeys
	foreach ($currentKey in $allKeys)
	{
		Write-Output ($currentKey + &quot;: &quot; + $combinedMappings[$currentKey]) | Out-File -FilePath $fileName -Append
	}
}
Write-Output (&quot;`n&quot;)
</pre> </p>
<p>Running this script in the client’s environment quickly identified the two lists that contained the same ID GUIDs.&#160; How did they get that way?&#160; I honestly don’t know, nor am I going to hazard a guess …</p>
<h3>What Next?</h3>
<p>If you’re in the unfortunate position of owning a site collection that contains objects possessing duplicate ID GUIDs, let me start by saying “I feel for you.”</p>
<p>Having said that: the quickest fix seemed to be deleting the objects that possessed the same GUIDs.&#160; Those objects were then rebuilt.&#160; I believe we handled the delete and rebuild manually, but there’s nothing to say that an <a href="http://technet.microsoft.com/en-us/library/cc262465(office.12).aspx" target="_blank">export and subsequent import</a> (via the Content Deployment API) couldn’t be used to get content out and then back in with new object IDs.&#160; </p>
<p>A word of caution: if you do leverage the Content Deployment API and do so programmatically, simply make sure that object identities aren’t retained on import; that is, make sure that <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.deployment.spimportsettings.retainobjectidentity.aspx" target="_blank">SPImportSettings.RetainObjectIdentity = false</a> – not true.</p>
<h3>Additional Reading and References</h3>
<ol>
<li>TechNet: <a href="http://technet.microsoft.com/en-us/library/cc262465(office.12).aspx" target="_blank">Import and export: STSADM operations</a></li>
<li>MSDN: <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.deployment.spimportsettings.retainobjectidentity.aspx" target="_blank">SPImportSettings.RetainObjectIdentity</a></li>
</ol>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sharepointinterface.wordpress.com/579/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sharepointinterface.wordpress.com/579/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sharepointinterface.wordpress.com/579/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sharepointinterface.com&amp;blog=7883095&amp;post=579&amp;subd=sharepointinterface&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sharepointinterface.com/2011/04/03/finding-duplicate-guids-in-your-sharepoint-site-collection/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/ed5effd4d8ce9db816d15726b0220750?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">spmcdonough</media:title>
		</media:content>
	</item>
		<item>
		<title>The ApplyApplicationContentToLocalServer Method and Why It Comes Up Short</title>
		<link>http://sharepointinterface.com/2009/06/06/the-applyapplicationcontenttolocalserver-method-and-why-it-comes-up-short/</link>
		<comments>http://sharepointinterface.com/2009/06/06/the-applyapplicationcontenttolocalserver-method-and-why-it-comes-up-short/#comments</comments>
		<pubDate>Sat, 06 Jun 2009 19:36:14 +0000</pubDate>
		<dc:creator>Sean McDonough</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[SharePoint 2007]]></category>
		<category><![CDATA[Caching]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[linkedin]]></category>
		<category><![CDATA[MOSS]]></category>
		<category><![CDATA[Publishing]]></category>
		<category><![CDATA[WSS]]></category>

		<guid isPermaLink="false">http://sharepointinterface.wordpress.com/2009/06/06/the-applyapplicationcontenttolocalserver-method-and-why-it-comes-up-short/</guid>
		<description><![CDATA[This post explores the SPWebService's ApplyApplicationContentToLocalServer method, the constraints one faces when using it, and an alternative to its use when updating application page sitemap files.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sharepointinterface.com&amp;blog=7883095&amp;post=163&amp;subd=sharepointinterface&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://technet.microsoft.com/en-us/library/cc298466.aspx" target="_blank">Caching</a> capabilities that are available (or exposed) through MOSS are something I spend a fair number of working hours focusing on.  MOSS publishing farms can make use of quite a few caching options, and wise administrators find ways to leverage them all for maximum scalability and performance. While helping a client work through some performance and scalability issues recently, I ran into some annoying problems with disk-based caching – also known as BLOB (<strong>B</strong>inary <strong>L</strong>arge <strong>OB</strong>ject) caching. These problems inspired me to create the <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">BlobCacheFarmFlush</a> solution that I’ve shared on <a href="http://www.codeplex.com/" target="_blank">CodePlex</a>, and it was during the creation of this solution that I wrangled with the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method.</p>
<h3>Background</h3>
<p>The <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">BlobCacheFarmFlush</a> solution itself has a handful of moving parts, and the element I’m going to focus on in this post is the administration page (<strong>BlobCacheFarmFlush.aspx</strong>) that gets added to the farm upon Feature activation.  In particular, I want to share some of the lessons I learned while figuring out how to get the page’s navigational (breadcrumb) support operating properly.</p>
<p>Unlike “standard” content pages that one might deploy through a SharePoint Feature or solution package, application pages (also called “layouts pages” because they go into the <strong>LAYOUTS</strong> folder within SharePoint’s 12 hive) don’t come with wired-up breadcrumb support.  An example of the type of breadcrumb to which I’m referring appears below (circled in red):</p>
<p><img style="display:inline;margin-left:0;margin-right:0;border-width:0;" title="Application Page Breadcrumb Example" src="http://sharepointinterface.files.wordpress.com/2009/06/breadcrumb_example.jpg?w=504&#038;h=121" border="0" alt="Application Page Breadcrumb Example" width="504" height="121" /></p>
<p>Unless additional steps are taken during the installation of your application pages (beyond simply placing them in the <strong>LAYOUTS</strong> folder), breadcrumbs like the one shown above will not appear.  It’s not that application pages (which derive from <strong>LayoutsBasePage</strong> or <strong>UnsecuredLayoutsBasePage</strong>) don’t include support for breadcrumbs – they do.  The reason breadcrumbs fail to show is because the newly added application pages themselves are not integrated into the sitemap files that describe the navigational hierarchy of the layouts pages.</p>
<h3>Wiring Up Breadcrumb Support</h3>
<p>Getting breadcrumbs to appear in your own application pages requires that you update the layouts sitemap files for each of the (IIS) sites serving up content on each of the SharePoint web front-end (WFE) servers in your farm.  The files to which I’m referring are named <strong>layouts.sitemap</strong> and appear in the <strong>_app_bin</strong> folder of each IIS site folder on the WFE.  An example of one such file (in its <strong>_app_bin</strong> folder) appears below.</p>
<p><img style="display:inline;margin-left:0;margin-right:0;border-width:0;" title="A SharePoint Site's LAYOUTS SiteMap File" src="http://sharepointinterface.files.wordpress.com/2009/06/layouts-sitemap.jpg?w=504&#038;h=114" border="0" alt="A SharePoint Site's LAYOUTS SiteMap File" width="504" height="114" /></p>
<p>I’m a “best practices” kind of guy, so when I was doing research for my <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">BlobCacheFarmFlush</a> solution, I was naturally interested in trying to make the required sitemap modifications in a way that was both easy and supported.  It didn’t take much searching on the topic before I came across Jan Tielens’ blog post titled “<a href="http://weblogs.asp.net/jan/archive/2008/04/16/adding-breadcrumb-navigation-to-sharepoint-application-pages-the-easy-way.aspx" target="_blank">Adding Breadcrumb Navigation To SharePoint Application Pages, The Easy Way</a>.”  In his blog post, Jan basically runs through the scenario I described above (though in much greater detail than I presented), and he mentions that another reader (Brian Staton) turned him onto a very simple and straightforward way of making the required sitemap modifications.  I’ll refer you to Jan’s blog post for the specifics, but the two-step quick summary goes like this:</p>
<ol>
<li>Create a <strong>layouts.sitemap.*.xml</strong> file that contains your sitemap navigation additions and deploy it to the <strong>LAYOUTS</strong> folder within SharePoint’s 12 hive on a server.</li>
<li>Execute code that implements one of the two approaches shown below (typically on Feature activation) :</li>
</ol>
<pre style="background-color:#fbfbfb;min-height:40px;width:652px;height:121px;overflow:auto;border:#cecece 1px solid;padding:5px;"><span style="color:#008000;">// Approach #1: Top-down starting at the SPFarm level</span>
SPFarm.Local.Services.GetValue&lt;SPWebService&gt;().ApplyApplicationContentToLocalServer();

<span style="color:#008000;">// Approach #2: Applying to the sites within an SPWebApplication</span>
myWebApp.WebService.ApplyApplicationContentToLocalServer();</pre>
<p>This isn’t much code, and it’s pretty clear that the magic rests with the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method.  This method carries out a few operations, but the one in which we’re interested involves taking the new navigation nodes in the <strong>layouts.sitemap.*.xml</strong> file and integrating them into the <strong>layouts.sitemap</strong> file for each IIS site residing under a target <strong>SPWebService</strong> instance.  With the new nodes (which tie the new application pages into the navigational hierarchy) present within each <strong>layouts.sitemap</strong> file, breadcrumbs appear at the top of the new application pages when they are rendered.</p>
<p>I took this approach for a spin, and everything looked great!  My sitemap additions were integrated as expected, and my breadcrumb appeared on the <strong>BlobCacheFarmFlush.aspx</strong> page.  All was well .. until I actually deployed my solution to its first multi-server SharePoint environment.  That’s when I encountered my first problem.</p>
<h3>Problem #1: The &#8220;Local&#8221; Part of the ApplyApplicationContentToLocalServer Method</h3>
<p>When I installed and activated the <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">BlobCacheFarmFlush</a> solution in a multi-server environment, the breadcrumbs failed to appear on my application page.  It took a little legwork, but I discovered that the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method has “Local” in its name for a reason: the changes made through the method’s actions only impact the server on which the method is invoked.</p>
<p>This contrasts with the behavior that SharePoint objects commonly exhibit.  The changes that are made through (and to) many SharePoint types impact data that is actually stored in SQL Server, and changes made through any farm member get persisted back to the appropriate database and become available through all servers within the farm.  The <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank"><strong>ApplyApplicationContentToLocalServer</strong></a> method, on the other hand, carries out its operations directly against the files and folders of the server on which the method is called, and the changes that are made do not “automagically” appear on or through other farm members.</p>
<p>The Central Administration host server for the farm in which I was activating my Feature wasn’t one of the WFEs serving up my application page.  When I activated my Feature from within Central Admin, my navigation additions were incorporated into the affected sites on the local (Central Admin) host … but the WFEs serving up actual site pages (and my application page) were not updated.  Result: no breadcrumb on my application page.</p>
<p>This issue is one of those problems that wouldn’t normally be discovered in a typical development environment.  Most of the SharePoint developers I know do their work within a virtual machine (VM) of some sort, so it’s not until one moves out of such an environment and into a multi-server environment that this type of deployment problem even makes itself known.  This issue only serves to underscore how important it is to test Features and solutions in a typical target deployment environment before releasing them for general use.</p>
<p>Putting my thinking cap back on, I worked to come up with another way to integrate the sitemap changes I needed in a way that was multi-server friendly.  The <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank"><strong>ApplyApplicationContentToLocalServer</strong></a> method still seemed like a winner given all that it did for a single line of code; perhaps all I needed to do was create and run a one-time custom timer job (that is, schedule a custom <strong>SPJobDefinition</strong> subclass) on each server within the farm and have that timer job execute the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method locally.</p>
<p>I whipped-up a custom timer job to carry out this action and took it for a spin.  That’s when I ran into my second problem.</p>
<h3>Problem #2: Rights Required for ApplyApplicationContentToLocalServer Method Invocation</h3>
<p>The documentation for the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method ends with this one line:</p>
<blockquote><p><em>Only local administrators can call this method.</em></p></blockquote>
<p>Prior to the creation of the custom timer job that I was going to use to update the sitemap files on each of the WFEs, I had basically ignored this point.  The local administrator requirement quickly became a barricade for my custom timer job, though.</p>
<p>Timer jobs, both SharePoint-supplied and custom, are executed within the context of the SharePoint Timer Service (OWSTIMER.EXE).  The Timer Service runs in an elevated security context with regard to the SharePoint farm, but its privileges shouldn’t extend beyond the workings of SharePoint.  Though some SharePoint administrators mistakenly believe that the Timer Service account (also known as the “database access account” or “farm service account”) requires local administrator rights on each server within the SharePoint farm, <a href="http://technet.microsoft.com/en-us/library/cc263445.aspx" target="_blank">Microsoft spells out that this is neither required nor recommended</a>.</p>
<p>The <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank"><strong>ApplyApplicationContentToLocalServer</strong></a> method works during Feature activation when the activating user is a member of the Local Administrators group on the server where activation is taking place – a common scenario.  The process breaks down, however, if the method call occurs within the context of the SharePoint Timer Service account because it isn’t (or shouldn’t be) a member of the Local Administrators group.  Attempts to call the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method from within a timer job fail and result in an “Access Denied” message being written to the Application Event Log.  A quick look at the first section of code inside the method itself (using <a href="http://www.red-gate.com/products/reflector/" target="_blank">Reflector</a>) makes this point pretty clearly:</p>
<pre style="background-color:#fbfbfb;min-height:40px;width:652px;height:101px;overflow:auto;border:#cecece 1px solid;padding:5px;"><span style="color:#0000ff;">if</span> (!SPAdministrationServiceUtilities.IsCurrentUserMachineAdmin())
{
    <span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> SecurityException(SPResource.GetString("<span style="color:#8b0000;">AccessDenied</span>", <span style="color:#0000ff;">new</span> <span style="color:#0000ff;">object</span>[0]));
}</pre>
<p>This revelation told me that the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method simply wasn’t going to cut the mustard for my purposes unless I wanted to either (a) require that the Timer Service account be added to the Local Administrators group on each server in the farm, or (b) require that an administrator manually execute an <strong>STSADM</strong> command or custom command line application to carry out the method call.  Neither of these were acceptable to me.</p>
<h3>Method Deconstruction</h3>
<p>Since I couldn’t use the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method directly, I wanted to dissect it to the extent that I could in order to build my own process in a manner that replicated the method’s actions as closely as possible.  Performing the dissection (again via <a href="http://www.red-gate.com/products/reflector/" target="_blank">Reflector</a>), I discovered that the method was basically iterating through each <strong>SPIisWebSite</strong> in each <strong>SPWebApplication</strong> within the <strong>SPWebService</strong> object being targeted.  As implied by its type name, each <strong>SPIisWebSite</strong> represents a web site within IIS – so each <strong>SPIisWebSite</strong> maps to a physical web site folder within the file system at <strong>C:\Inetpub\wwwroot\wss\VirtualDirectories</strong> (by default if IIS folders haven’t been redirected).</p>
<p>Once each of the web site folder paths is known, it isn’t hard to drill down a bit further to each <strong>layouts.sitemap</strong> file within the <strong>_app_bin</strong> folder for a given IIS web site.  With the fully qualified path to each <strong>layouts.sitemap</strong> file computed, it’s possible to carry out a programmatic XML merge with the new sitemap data from a <strong>layouts.sitemap.*.xml</strong> file that is deployed with a custom Feature or solution.  The <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method carries out such a merge through the private (and obfuscated) <strong>MergeAspSiteMapFiles</strong> method of the <strong>SPAspSiteMapFile</strong> internal type, but only after it has created a backup copy of the current <strong>layouts.sitemap</strong> file using the <strong>SPAspSiteMapFile.Copy</strong> method.</p>
<h3>The Solution</h3>
<p>With an understanding of the process that is carried out within the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method, I proceeded to create my own class that effectively executed the same set of steps.  The result was the <strong><a href="http://blobcachefarmflush.codeplex.com/SourceControl/changeset/view/53851#856355" target="_blank">UpdateLayoutsSitemapTimerJob</a></strong> custom timer job definition that is part of my <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">BlobCacheFarmFlush</a> solution.  This class mimics the enumeration of <strong>SPWebApplication</strong> and <strong>SPIisWebSite</strong> objects, the backup of affected <strong>layouts.sitemap</strong> files, and the subsequent XML sitemap merge of the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method.  The class is without external dependencies (beyond the SharePoint object model), and it is reusable in its current form.  Simply drop the class into a SharePoint project and call its <strong>DeployUpdateTimerJobs</strong> static method with the proper parameters – typically from the <strong>FeatureActivated</strong> method of a custom <strong>SPFeatureReceiver</strong>.  The class then takes care of provisioning a timer job instance that will update the <strong>layouts.sitemap</strong> navigational hierarchy for affected sites on each of the servers within the farm.</p>
<p>As an aside: while putting together the <a href="http://http://blobcachefarmflush.codeplex.com/SourceControl/changeset/view/53851#856355" target="_blank"><strong>UpdateLayoutsSitemapTimerJob</strong></a>, there were times when I thought I had to be missing something.  On a handful of occasions, I found myself thinking, “Certainly there had to be a multi-server friendly version of the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method.”  When I didn’t find one (after much searching), I had the good fortune of stumbling upon Vincent Rothwell’s “<a href="http://blog.thekid.me.uk/archive/2007/01/17/configuring-the-breadcrumb-for-pages-in-layouts.aspx" target="_blank">Configuring the breadcrumb for pages in _layouts</a>” blog post.  Vincent’s post predates my own by a hefty two and a half years, but in it he describes a process that is very similar to the one I eventually ended up implementing in my custom timer job.  Seeing his post helped me realize I wasn’t losing my mind and that I was on the right track.  Thank you, Vincent.</p>
<h3>Conclusion</h3>
<p>I can sum up the contents of this post pretty simply: when developing application pages that entail sitemap updates, avoid using the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method unless you’re (a) certain that your Feature will be installed into single server environments only, or (b) willing to direct those doing the installation and activation to carry out some follow-up administration on each WFE in the SharePoint farm.</p>
<p>Why does the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method exist?  I did some thinking, and my guess is that it is leveraged primarily when service packs, hotfixes, and other additions are configured via the SharePoint Products and Technologies Configuration Wizard.  Anytime a SharePoint farm is updated with a patch or hotfix, the wizard is run on each server by a local administrator.</p>
<p>An examination of the <strong>LAYOUTS</strong> folder on one of my farm members provided some indirect support for this notion.  In my <strong>LAYOUTS</strong> folder, I found the <strong>layouts.sitemap.search.xml</strong> file, and it was dated 3/25/2008.  I believe (I’m not positive) that this file was deployed with the <a href="http://blogs.msdn.com/sharepoint/archive/2008/07/15/announcing-availability-of-infrastructure-updates.aspx" target="_blank">SharePoint Infrastructure Updates</a> in the middle of 2008, and those updates introduced a number of new search admin pages for MOSS.  Since the contents of the <strong>layouts.sitemap.search.xml</strong> file include quite a few new search-related navigation nodes, my guess is that the <strong><a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">ApplyApplicationContentToLocalServer</a></strong> method was leveraged to merge the navigation nodes for the new search pages when the configuration wizard was run.</p>
<p>In the meantime, if you happen to find a way to use this method in a multi-server deployment scenario that doesn’t involve the configuration wizard, I’d love to hear about it!  The caveat, of course, is that it has to be a best-practices approach – no security changes, no extra manual work/steps for farm administrators, etc.</p>
<h3>Additional Reading and References</h3>
<ol>
<li>MSDN: <a href="http://technet.microsoft.com/en-us/library/cc298466.aspx" target="_blank">Caching In Office SharePoint 2007</a></li>
<li>CodePlex: <a href="http://blobcachefarmflush.codeplex.com/" target="_blank">MOSS 2007 Farm-Wide BLOB Cache Flushing Solution</a></li>
<li>Jan Tielens: <a href="http://weblogs.asp.net/jan/archive/2008/04/16/adding-breadcrumb-navigation-to-sharepoint-application-pages-the-easy-way.aspx" target="_blank">Adding Breadcrumb Navigation To SharePoint Application Pages, The Easy Way</a></li>
<li>MSDN: <a href="http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spwebservice.applyapplicationcontenttolocalserver.aspx" target="_blank">SPWebService.ApplyApplicationContentToLocalServer Method</a></li>
<li>TechNet: <a href="http://technet.microsoft.com/en-us/library/cc263445.aspx" target="_blank">Plan for administrative and service accounts (Office SharePoint Server)</a></li>
<li>Red Gate Software: <a href="http://www.red-gate.com/products/reflector/" target="_blank">.NET Reflector</a></li>
<li>CodePlex: <a href="http://blobcachefarmflush.codeplex.com/SourceControl/changeset/view/53851#856355" target="_blank">UpdateLayoutsSitemapTimerJob class</a></li>
<li>Vincent Rothwell: <a href="http://blog.thekid.me.uk/archive/2007/01/17/configuring-the-breadcrumb-for-pages-in-layouts.aspx" target="_blank">Configuring the breadcrumb for pages in _layouts</a></li>
</ol>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/sharepointinterface.wordpress.com/163/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/sharepointinterface.wordpress.com/163/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/sharepointinterface.wordpress.com/163/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sharepointinterface.com&amp;blog=7883095&amp;post=163&amp;subd=sharepointinterface&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sharepointinterface.com/2009/06/06/the-applyapplicationcontenttolocalserver-method-and-why-it-comes-up-short/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/ed5effd4d8ce9db816d15726b0220750?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">spmcdonough</media:title>
		</media:content>

		<media:content url="http://sharepointinterface.files.wordpress.com/2009/06/breadcrumb_example.jpg" medium="image">
			<media:title type="html">Application Page Breadcrumb Example</media:title>
		</media:content>

		<media:content url="http://sharepointinterface.files.wordpress.com/2009/06/layouts-sitemap.jpg" medium="image">
			<media:title type="html">A SharePoint Site&#039;s LAYOUTS SiteMap File</media:title>
		</media:content>
	</item>
	</channel>
</rss>
