<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Craig Campbell - PFE</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/craig_campbell/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/craig_campbell/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:47:45 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Convert host-named site collection to Web application</title>
      <link>https://docs.microsoft.com/archive/blogs/craig_campbell/convert-host-named-site-collection-to-web-application</link>
      <pubDate>Thu, 29 May 2014 14:11:00 GMT</pubDate>
      <dc:creator><![CDATA[CraigCa]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/craig_campbell/2014/05/29/convert-host-named-site-collection-to-web-application/</guid>
      <description><![CDATA[You've identified a host-named site collection in your environment where application pool isolation...]]></description>
      <content:encoded><![CDATA[<p>You've identified a host-named site collection in your environment where application pool isolation has become important. To achieve this level of isolation, you will need to create a new Web application with its own Application pool.</p>
<p>I've created a PowerShell script to illustrate one way of doing this. This script can be downloaded from the TechNet Gallery located here: <a href="https://gallery.technet.microsoft.com/office/Migrate-host-named-80d73c79">https://gallery.technet.microsoft.com/office/Migrate-host-named-80d73c79</a></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>The Visible property cannot be set on Web Part</title>
      <link>https://docs.microsoft.com/archive/blogs/craig_campbell/the-visible-property-cannot-be-set-on-web-part</link>
      <pubDate>Thu, 15 May 2014 09:13:26 GMT</pubDate>
      <dc:creator><![CDATA[CraigCa]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/craig_campbell/2014/05/15/the-visible-property-cannot-be-set-on-web-part/</guid>
      <description><![CDATA[I recently had a customer experiencing an issue with editing Web parts on a SharePoint 2013 page....]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: trebuchet ms,geneva;">I recently had a customer experiencing an issue with editing Web parts on a SharePoint 2013 page. The typical dropdown menu used to edit and delete the Web part was missing and replaced by a double arrow used for minimizing (collapsing) the Web part. It felt like a user permission issue, so we went through the permissions for the user logged into the browser, but ultimately didn't see any issue with the user's permission. Also while trying to edit the page that contained the Web parts, we would get an error with a Correlation ID. Looking at the ULS logs, we noticed this error:</span></p>
<p><span style="font-family: courier new,courier;"><strong>The Visible property cannot be set on Web Part 'g_e9a9fae6_096a_4133_ae61_75e63a6a9b23'.&nbsp; It can only be set on a standalone Web Part.</strong></span></p>
<p><span style="font-family: courier new,courier;"><strong>Stack Trace: </strong></span><br /><span style="font-family: courier new,courier;"><strong>[InvalidOperationException: The Visible property cannot be set on Web Part 'g_e9a9fae6_096a_4133_ae61_75e63a6a9b23.&nbsp; <span id="#h3" class="KeywordHighlight">It can only be set on a standalone Web Part</span>.]</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.WebControls.WebParts.WebPart.PreRenderRecursiveInternal() +2706778</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Control.PreRenderRecursiveInternal() +222</strong></span><br /><span style="font-family: courier new,courier;"><strong>&nbsp;&nbsp; System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)</strong></span></p>
<p><span style="font-family: trebuchet ms,geneva;">This particular Web part was an OOTB Documents Web part, so we could rule out any custom development issues. We ultimately decided to assume the permissions for the application pool account for this particular Web application was corrupt in some way. Our solution was to temporarily change the service account to a different managed account and then change it back so that SharePoint will reapply the necessary permissions. </span></p>
<p><span style="font-family: trebuchet ms,geneva;">The fix in our case:</span></p>
<p><span style="font-family: trebuchet ms,geneva;">From <strong>Central Administration</strong>:</span></p>
<ol>
<li><span style="font-family: trebuchet ms,geneva;">click <strong>Security</strong> and then <strong>Configure service accounts</strong>. </span></li>
<li><span style="font-family: trebuchet ms,geneva;">Select the application pool from the list of application pools.</span></li>
<li><span style="font-family: trebuchet ms,geneva;">Select a different managed account from the one listed.</span></li>
<li><span style="font-family: trebuchet ms,geneva;">Click OK. </span></li>
<li><span style="font-family: trebuchet ms,geneva;">Repeat steps 1-4 selecting the appropriate managed account this time around. </span></li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>A behind-the-scenes look at MissingWebPart errors from the "Missing server side dependencies" health analyzer rule</title>
      <link>https://docs.microsoft.com/archive/blogs/craig_campbell/a-behind-the-scenes-look-at-missingwebpart-errors-from-the-missing-server-side-dependencies-health-analyzer-rule</link>
      <pubDate>Fri, 27 Sep 2013 07:47:00 GMT</pubDate>
      <dc:creator><![CDATA[CraigCa]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/craig_campbell/2013/09/27/a-behind-the-scenes-look-at-missingwebpart-errors-from-the-missing-server-side-dependencies-health-analyzer-rule/</guid>
      <description><![CDATA[Recently I was helping a customer with a review of their SharePoint Server 2010 environment when I...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: 'trebuchet ms', geneva;">Recently I was helping a customer with a review of their SharePoint Server 2010 environment when I noticed a ton of "Missing server side dependencies". Most notably were missing Web parts and even more notable was that they were OOTB Web parts. The entries were listed like this:</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">[MissingWebPart] WebPart class [1ce3ddc9-1d7f-3ecb-b9d3-ee015154456b] is referenced [3] times in the database [WSS_Content_4992], but is not installed on the current farm. Please install any feature/solution which contains this web part. One or more web parts are referenced in the database [WSS_Content_4992], but are not installed on the current farm. Please install any feature or solution which contains these web parts.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">[MissingWebPart] WebPart class [7494019e-cc3c-dc3d-88ee-f9782d55ba37] (class [Microsoft.SharePoint.Publishing.WebControls.TableOfContentsWebPart] from assembly [Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]) is referenced [1] times in the database [WSS_Content_4992], but is not installed on the current farm. Please install any feature/solution which contains this web part. One or more web parts are referenced in the database [WSS_Content_4992], but are not installed on the current farm. Please install any feature or solution which contains these web parts.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">There are tons of information on the <a title="Internet " href="https://blog.scoreman.net/2010/11/solution-to-missing-server-side-dependencies-8d6034c4-a416-e535-281a-6b714894e1aa/" target="_blank">Internet</a>&nbsp;regarding missing server side dependencies for the Central Administration content database with fixes like enabling SharePoint Foundation Search, click on those two pages for Search administration and then rerun the rule. I could not find any legitimate solution for this issue regarding a normal Team site content database.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">My first thought was that somehow the Publishing feature would be the culprit, but after deactivating and reactivating the Publishing Feature, rerunning the rule, the errors persisted. This then led me down the path of looking at the WFE servers in the farm for the existence of these features/solutions. I was able to locate the .webpart files and features containing a lot of the Web parts in the SharePoint Root directory.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">I started digging into the Health Analyzer rule for "Missing server side dependencies" and information learned from that exploration is shared here to provide a better understanding of how missing server side dependencies appear in the health analyzer.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">The first thing I wanted to know is what controls the missing server side dependencies rule. This information is stored in the Central Administration site under the List HeathRules. From here, you can edit a few properties about the rule. For example, its Title, Scope (whether to run against ANY or ALL servers in the farm), Schedule, whether its enabled, Repair Automatically and Version. That's great, but where is the meat of the rule? Turns out what I needed was stored in Hidden fields of the list. To get this information, I created a Console Application using Visual Studio to iterate the HealthRules list, pulling out the Fields Collection of the "Missing server side dependencies" rule.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: 'trebuchet ms', geneva;">One property in particular is the one we're after:</span></p>
<pre class="scroll"><code class="html">&lt;Field ID=\"{7dd0a092-8704-4ed2-8253-ac309150ac59}\" Name=\"HealthRuleType\" DisplayName=\"Type\" Type=\"Text\" Description=\"The rule type specifies the fully-qualified assembly name of the rule class.\" Group=\"_Hidden\" SourceID=\"https://schemas.microsoft.com/sharepoint/v3/fields\" StaticName=\"HealthRuleType\" AllowDeletion=\"FALSE\" Hidden=\"TRUE\" Required=\"TRUE\" ColName=\"nvarchar3\"/&gt;</code></pre>
<p><span style="font-family: 'trebuchet ms', geneva;">The field contains the value of:</span></p>
<pre class="scroll"><code class="html">Microsoft.SharePoint.Administration.Health.ContentDatabaseCorruption, Microsoft.SharePoint.Health, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</code></pre>
<p>&nbsp;</p>
<p><span style="font-family: 'trebuchet ms', geneva;">Now, we have something to work with. I pull the Microsoft.SharePoint.Health.dll out of the GAC and use the open-source de-compiler <a title="JetBrains dotPeek" href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;ved=0CCwQFjAA&amp;url=http%3A%2F%2Fwww.jetbrains.com%2Fdecompiler%2F&amp;ei=PJdFUovdC8ngiALFvoD4BA&amp;usg=AFQjCNEHe70QThI6ntTvsyBhZHuW4K5F2A&amp;bvm=bv.53217764,d.cGE" target="_blank">JetBrains dotPeek</a> to look at the source code. This is a synopsis of my code review.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">The&nbsp;</span><span style="font-family: 'courier new', courier;">ContentDatabaseCorruption&nbsp;</span><span style="font-family: 'trebuchet ms', geneva;">class contains a <span style="font-family: 'courier new', courier;">Check()</span> method that returns a <span style="font-family: 'courier new', courier;">SPHealthCheckStatus</span> object. This method create a <span style="font-family: 'courier new', courier;">SPWebServiceCollection</span> object and performs a <span style="font-family: 'courier new', courier;">foreach</span> loop, basically getting at all of the <span style="font-family: 'courier new', courier;">SPWebApplication</span> objects in the collection. It then creates a <span style="font-family: 'courier new', courier;">SPContentDatabaseCollection</span>, iterates over the collection and then calls this bit of code:</span></p>
<p>&nbsp;&nbsp;</p>
<pre class="scroll"><code class="csharp">SPContentDatabaseIntegrity databaseIntegrity = new SPContentDatabaseIntegrity(db.WebApplication, db, true, SPManager.Instance.Log);<br /> <br />databaseIntegrity.Check(true);<br /> <br />if (databaseIntegrity.TestResults.Count &gt; 0)<br /> <br />this.m_sbInfo.AppendLine(databaseIntegrity.GetResult());</code></pre>
<p>&nbsp;</p>
<p>&nbsp;<span style="font-family: 'trebuchet ms', geneva;">As you can see, we then have to review the </span><span style="font-family: 'courier new', courier;">SPContentDatabaseIntegrity</span><span style="font-family: 'trebuchet ms', geneva;"> class to see what's going on in there. In the </span><span style="font-family: 'courier new', courier;">SPContentDatabaseIntegrity</span><span style="font-family: 'trebuchet ms', geneva;"> class, it does a lot of stuff, but what's interesting to us is the </span><span style="font-family: 'courier new', courier;">Check()</span><span style="font-family: 'trebuchet ms', geneva;"> method which is overloaded taking a Boolean parameter of whether it's coming from the health analyzer.</span></p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp"> this.CheckMissingWebTemplates();<br /> this.CheckMissingFeatures();<br /> this.CheckOrphanedSites();<br /> this.CheckSetupFiles();<br /> this.CheckWebParts();<br /> this.CheckEventReceiverAssemblies();<br /> if (calledFromHealthRule)<br /> return;<br /> this.AssertValidMaxRowOrdinalInAudTable();<br /> this.CheckListSchemaLimits();</code></pre>
<p><span style="font-family: 'trebuchet ms', geneva;">As you can see, it performs all of these checks for each content database for each Web application. We'll focus on the <span style="font-family: 'courier new', courier;">this.CheckWebParts();</span> method for this blog post.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">One of the first steps is to declare the SQL command used for the rest of the routine. I'm sure this will look familiar to those that have had to troubleshoot these issues in the past.</span></p>
<p>&nbsp;</p>
<pre class="scroll"><code class="mysql">SELECT tp_WebPartTypeId, COUNT(1), tp_Assembly, tp_Class FROM AllWebParts<br /> <br /> (NOLOCK) WHERE tp_WebPartTypeId IS NOT NULL AND tp_SolutionId IS NULL<br /> <br /> GROUP BY tp_WebPartTypeId, tp_Assembly, tp_Class</code></pre>
<p><span style="font-family: 'trebuchet ms', geneva;">This query actually varies based on the SchemaVersion, but is not that important here.&nbsp;</span></p>
<p>&nbsp;<span style="font-family: 'trebuchet ms', geneva;">The next step is important and I had never thought this played into the rule, but it is a crucial piece to recognize. Using the </span><span style="font-family: 'courier new', courier;">Microsoft.SharePoint</span><span style="font-family: 'trebuchet ms', geneva;"> assembly it creates a new </span><span style="font-family: 'courier new', courier;">Microsoft.SharePoint.ApplicationRuntime.SafeControls</span><span style="font-family: 'trebuchet ms', geneva;"> object passing in the Web application and the Default zone of the Web application. At this point, I'll give you the solution to the problem I was having.</span></p>
<p>&nbsp;<span style="font-family: 'trebuchet ms', geneva;">When the SharePoint Timer job starts and based on the Scope of the rule (Any Server), it will sometime vary which Server in the farm the rule is applied against. In my case, the Application server was always the server to be picked. Back up in the <span style="font-family: 'courier new', courier;">ContentDatabaseCorruption.Check()</span> method, it creates the <span style="font-family: 'courier new', courier;">SPWebServiceCollection</span> by passing in <span style="font-family: 'courier new', courier;">SPFarm.Local</span>:</span></p>
<p>&nbsp;</p>
<pre class="scroll"><code class="csharp">SPWebServiceCollection serviceCollection = new SPWebServiceCollection(SPFarm.Local);</code></pre>
<p>&nbsp;</p>
<p><span style="font-family: 'trebuchet ms', geneva;">This will return the current server farm object. Because this server wasn't running the Web application role, the IIS Website doesn't exist. Moreover, the web.config file it expects to find to create the SafeControls object didn't exist either.</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">To avoid this issue, either start the Web application role on each server in the farm or replicate the virtual directory structure for each Web application to every server not hosting the Web application role. I would choose the former so it doesn't become a maintenance task each time you create a new Web application.&nbsp;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: 'trebuchet ms', geneva;">Bottom line: This health analyzer rule uses the results of the T-SQL query above and looks for a SafeControl entry that matches the GUID (tp_WebPartTypeId), assembly name (tp_Assembly) and type name (tp_Class).</span></p>
<p><span style="font-family: 'trebuchet ms', geneva;">If no match is found, it determines if the Assembly or Type name is not null. If this evaluates to true, it appends this to the text that you see in the list. Otherwise, it just omits this information from the entry. From here, it adds the entry to a Generic List and moves on the next record. In a later post, I will cover the other missing server side dependencies tests.&nbsp;</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
  </channel>
</rss>