Issue creating subsites when a built-in field is modified


June 30, 2014 - 14:26, by Steven Van de Craen - 1 Comments

One of our site collections in a migration to SharePoint 2013 experienced an issue with creating sub sites:

Sorry, something went wrong
The URL 'SitePages/Home.aspx' is invalid.  It may refer to a nonexistent file or folder, or refer to a valid file or folder that is not in the current Web.

Drilling down in the ULS logs we noticed these:

System.Runtime.InteropServices.COMException: <nativehr>0x81020030</nativehr><nativestack></nativestack>The URL 'SitePages/Home.aspx' is invalid.  It may refer to a nonexistent file or folder, or refer to a valid file or folder that is not in the current Web., StackTrace:  
at Microsoft.SharePoint.SPListItem.AddOrUpdateItem(Boolean bAdd, Boolean bSystem, Boolean bPreserveItemVersion, Boolean bNoVersion, Boolean bMigration, Boolean bPublish, Boolean bCheckOut, Boolean bCheckin, Guid newGuidOnAdd, Int32& ulID, Object& objAttachmentNames, Object& objAttachmentContents, Boolean suppressAfterEvents, String filename, Boolean bPreserveItemUIVersion)   
at Microsoft.SharePoint.SPListItem.UpdateInternal(Boolean bSystem, Boolean bPreserveItemVersion, Guid newGuidOnAdd, Boolean bMigration, Boolean bPublish, Boolean bNoVersion, Boolean bCheckOut, Boolean bCheckin, Boolean suppressAfterEvents, String filename, Boolean bPreserveItemUIVersion)   
at Microsoft.SharePoint.Utilities.SPUtility.ProvisionWikiPageHomePage(SPFile wikiPage)   
at Microsoft.SharePoint.Utilities.SPUtility.EnsureWikiPageHomePage(SPWeb web, ProvisionWikiPage provisionWikiPage)   
at Microsoft.SharePoint.SPWikiPageHomePageFeatureReceiver.FeatureActivated(SPFeatureReceiverProperties properties)   
at Microsoft.SharePoint.SPFeature.DoActivationCallout(Boolean fActivate, Boolean fForce)   
at Microsoft.SharePoint.SPFeature.Activate(SPSite siteParent, SPWeb webParent, SPFeaturePropertyCollection props, SPFeatureActivateFlags activateFlags, Boolean fForce)

System.Data.SqlClient.SqlException (0x80131904): Parameter '@tp_Author' was supplied multiple times.   
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)   
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)   
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)   
at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)   
at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)   
at System.Data.SqlClient.SqlDataReader.TryNextResult(Boolean& more)   
at System.Data.SqlClient.SqlDataReader.NextResult()   
at Microsoft.SharePoint.SPSqlClient.ExecuteQueryInternal(Boolean retryfordeadlock)   
at Microsoft.SharePoint.SPSqlClient.ExecuteQuery(Boolean retryfordeadlock)  ClientConnectionId:1237a76d-2050-4ad5-82cd-cc9610f95061

The tp_Author gave an entry point into troubleshooting this issue. A quick loop through the fields on the web and then looking for ColName="tp_Author" revealed only the out of the box “Author” field being present. But it was modified at some point in history because the Group was different and there was a Version attribute present.

One can quickly test this behaviour on a clean new site collection and updating the field with powershell:

$w = Get-SPWeb http://intranet
$f = $w.Fields.GetFieldByInternalName("Author")
$f.Update()

The schema xml will look as follows:

<Field ID="{1df5e554-ec7e-46a6-901d-d85a3881cb18}" Name="Author" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Author" Group="_Hidden" ColName="tp_Author" RowOrdinal="0" Type="User" List="UserInfo" DisplayName="Created By" Sealed="FALSE" ReadOnly="TRUE" Version="1" />

And also it will now be impossible to create any sites in the site collection (exception is the ‘blank’ site but it has the same issues once you activate the “Wiki page home page” feature and edit/save a page).

Solution

Luckily the product team has provided a method named Microsoft.SharePoint.SPField.RevertCustomizations() that will undo the changes and restore the site creation functionality.

$f.RevertCustomizations()
HTH


SharePoint: How to troubleshoot issues with Save as template


May 23, 2014 - 14:32, by Steven Van de Craen - 0 Comments

On an upgrade project to SharePoint 2013 we ran into an issue where a specific site couldn’t be saved as a template (with or without content). You get the non-descriptive “Sorry, something went wrong” and “An unexpected error has occurred” messages. Funny enough the logged Correlation Id is totally absent from the ULS logs, so no help there.

What you can do next is turn on advanced debugging mode by configuring the following entries in the web.config of the SharePoint site:

  • Turn on the call stack (CallStack="true")
  • Disable custom errors in Visual Studio (<customErrors mode="Off" />)
  • Enable compilation debugging (<compilation debug="true">)

http://msdn.microsoft.com/en-us/library/ee231550.aspx

If you then retry your action you’ll find additional information in the Event Log or on the page.

Exception information:
    Exception type: InvalidOperationException
    Exception message: Error generating solution files in temporary directory.
   at Microsoft.SharePoint.SPSolutionExporter.ExportWebAsSolution()
   at Microsoft.SharePoint.SPSolutionExporter.ExportWebToGallery(SPWeb web, String solutionFileName, String title, String description, ExportMode exportMode, Boolean includeContent, String workflowTemplateName, String destinationListUrl, Action`1 solutionPostProcessor, Boolean activateSolution)
   at Microsoft.SharePoint.ApplicationPages.SaveAsTemplatePage.BtnSaveAsTemplate_Click(Object sender, EventArgs e)
   at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

What this means is that the export operation ran into an issue. We can find the partial export in the temporary directory

Temporary Export Location

If you investigate the contents of the “SPSolutionExporter” folder, you’ll eventually find the issue. In our case the XML generation aborted on the Expiration Policy of one of the Content Types.

image 

So while your issue might be different, this method should provide you with more insight on the issue and take appropriate action.

Addendum

The Content Type/Policy issue in our setup was caused due to a corrupt XmlDocument that describes the changes made to Information Policies. By removing this invalid XmlDocument we were able to save the site as template:

using (SPSite site = new SPSite(url))
{
    using (SPWeb web = site.OpenWeb())
    {
        foreach (SPContentType ct in web.ContentTypes)
        {
            ct.SchemaXmlWithResourceTokens = Regex.Replace(ct.SchemaXmlWithResourceTokens, @"<XmlDocument NamespaceURI=""microsoft.office.server.policy.changes"">.+?</XmlDocument>", "");
            ct.Update();
        }
    }
} 


Fixing SharePoint DCOM errors the easy way - revised


May 8, 2014 - 16:17, by Steven Van de Craen - 0 Comments

Tagline: Fix your SharePoint DCOM issues with a single click ! - revised for Windows Server 2012 and User Account Control-enabled systems
Update 8/05/2014: Scripts were revised to work with Windows Server 2008 R2 and Windows Server 2012 with User Account Control enabled.
Original post: Fixing SharePoint DCOM errors the easy way
Direct download: DCOMFIX-revised.zip

Problem

The dreaded DCOM error (10016, DistributedCOM, Local Activation, IIS WAMREG admin Service) has seen the light ever since SharePoint 2007. It carried over to SharePoint 2010 and now it seems to SharePoint 2013 as well.

image

Manually

Fixing it isn’t all that hard. You have to identify the DCOM app based on the GUID, identify the user(s) affected and then modify the Local Activation permissions accordingly.

Windows Server 2008 R2 and higher made that a bit harder. You first have to set the permissions of the DCOM app in the registry, but that requires changing the owner, granting permissions on the registry key, granting local activation, and then undoing your permission and owner change on the registry key (keep things tidy, you know).

image

Automation

Here’s a new set of scripts that have been tested against Windows Server 2008 R2 and Windows Server 2012 with User Account Control enabled.

Note that the APPID and USER (can be user or group) in both files are currently configured for the IIS WAMREG admin Service and the IIS_IUSRS builtin group. You can change these if you want.

  • get_dcom_perms.cmd: returns the currently configured set of permissions for the DCOM object. This script can be run without elevated permissions
  • set_dcom_perms.cmd: checks if running with elevated permissions and will configure the permissions for the DCOM object for the specified user or group
  • DComPerm.exe: provided as sample source code by Microsoft, but I’ve included a compiled version in the download. It takes various parameters to list, set or remove permissions on various DCOM objects
  • SetACL.exe: a free tool for automating the management of Windows permissions. Website: http://helgeklein.com/setacl/

 

If you run set_dcom_perms.cmd without elevated permissions it will notify you of this:

set_dcom_perms.cmd non elevated

if you run it elevated it will execute the changes requeste:

User Account Control

set_dcom_perms.cmd elevated

Download


SharePoint 2013: CreatePersonalSite fail when user license mapping incorrectly configured


May 5, 2014 - 13:49, by Steven Van de Craen - 0 Comments

Last week I was troubleshooting a farm with ADFS where MySite creation failed. The ULS logs indicated that the user was not licensed to have a MySite.

04/29/2014 17:34:10.15 w3wp.exe (WS12-WFE1:0x031C) 0x1790 SharePoint Portal Server Personal Site Instantiation af1lc High Skipping creation of personal site from MySitePersonalSiteUpgradeOnNavigationWebPart::CreatePersonalSite() because one or more of the creation criteria has not been met. [SPWeb Url=https://mysite.domain1.com/Person.aspx?accountname=i:05.t|adfs|ventigrate.test@domain1.com] https://mysite.domain1.com/Person.aspx?accountname=i:05.t|adfs|ventigrate.test@domain1.com]Self-Service Site Creation == True Can Create Personal Site == False Is user licensed == False Storage&Social UPA Permission == True Site or Page or Web Part is in design mode == False c0048c9c-234d-700b-502b-52356264cbda

As it turns out, this message was correct, since User License Management had been enabled recently by a colleague of mine, while preparing to roll out Office Web Apps to a subset of users.

It seems that if you enable the licensing functionality in SharePoint 2013, you need to have a license mapping for the “Standard” license in order to have MySite functionality.

New-SPUserLicenseMapping

I quickly came up with the following script that would add “all authenticated users” to the “Standard” license.

$claimString = "c:0(.s|True"
$cpm = [Microsoft.SharePoint.Administration.Claims.SPClaimProviderManager]::Local
$claim = $cpm.DecodeClaim($claimString)
$lmap = New-SPUserLicenseMapping -Claim $claim -License Standard 
$lmap | Add-SPUserLicenseMapping

This adds a mapping as can be seen in the following screen (number #3 is the one relating to the above script)

Get-SPUserLicenseMapping 

A big note on this: make sure to have the correct casing! At first I used “c:0(.s|true” but since its value type is String this fails to match.

Claim Spy

If you want to get a quick overview of claims for a user you can drop a page in the layouts-folder called claimspy.aspx (body: see below) and have a user navigate to /_layouts/claimspy.aspx. It just outputs all known claims for the current token. Feel free to improve the page and do proper deployment through solution packages and such Winking smile

<%@ Page Language="C#" %>
<%@ Assembly Name="Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" %>
<%@ Import Namespace="Microsoft.IdentityModel.Claims" %>

<script type="text/C#" runat="server">
    protected override void OnLoad(EventArgs e)
    {
        try
        {
            IClaimsIdentity identity = (IClaimsIdentity)Context.User.Identity;

            if (null != identity)
            {
                repeater1.DataSource = identity.Claims;
                repeater1.DataBind();
            }
        }
        catch (Exception ex)
        {
            Response.Write(ex.ToString());
        }
    }
</script>

<html>
    <body>
        <table>
            <thead>
                <tr>
                    <td><strong>Issuer</strong></td>
                    <td><strong>OriginalIssuer</strong></td>
                    <td><strong>ClaimType</strong></td>
                    <td><strong>Subject</strong></td>
                    <td><strong>Value</strong></td>
                    <td><strong>ValueType</strong></td>
                </tr>
            </thead>
            <tbody>
                <asp:Repeater ID="repeater1" runat="server">
                    <ItemTemplate>
                        <tr>
                            <td><nobr><%# Eval("Issuer") %></nobr></td>
                            <td><nobr><%# Eval("OriginalIssuer") %></nobr></td>
                            <td><nobr><%# Eval("ClaimType") %></nobr></td>
                            <td><nobr><%# Eval("Subject") %></nobr></td>
                            <td><nobr><%# Eval("Value") %></nobr></td>
                            <td><nobr><%# Eval("ValueType") %></nobr></td>
                        </tr>
                    </ItemTemplate>
                </asp:Repeater>
            </tbody>
        </table>
    </body>
</html>

HTH!


SharePoint 2013: Workflows failing on start


April 29, 2014 - 12:10, by Steven Van de Craen - 0 Comments

Recently I helped out a colleague with an issue in a load balanced SharePoint 2013 environment with Nintex Workflow 2013 on it. All the workflows that were started on WFE1 worked fine, but all started on WFE2 failed on start with the following issue logged to the SharePoint ULS logs:

Load Workflow Class: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: The requested Performance Counter is not a custom counter, it has to be initialized as ReadOnly.

at System.Diagnostics.PerformanceCounter.InitializeImpl()

at System.Diagnostics.PerformanceCounter..ctor(String categoryName, String counterName, String instanceName, Boolean readOnly)

at System.Workflow.Runtime.PerformanceCounterManager.CreateCounters(String name)

at System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService.OnStarted()

at System.EventHandler`1.Invoke(Object sender, TEventArgs e)

at System.Workflow.Runtime.WorkflowRuntime.StartRuntime()

at Microsoft.SharePoint.Workflow.SPWinOeHostServices..ctor(SPSite site, SPWeb web, SPWorkflowManager manager, SPWorkflowEngine engine) -

-- End of inner exception stack trace ---

at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)

at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)

at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)

at System.Reflection.Assembly.CreateInstance(String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)

at Microsoft.SharePoint.Workflow.SPWorkflowManager.LoadPluggableClass(String classname, String assembly, Object[] parameters)

If you look up this issue you’ll find a lot of references to SharePoint 2007, but it seems that this is still possible in a SharePoint 2013 / Windows Server 2012 environment as well.

Cause

An incorrect registration of the Windows Workflow Foundation performance counters will cause this. You can easily verify this by opening up perfmon, adding a counter and looking for the category “Windows Workflow Foundation”.

perfmon - Add Counters

Solution

Register the performance counters on each affected server:

lodctr C:\Windows\Inf\Windows Workflow Foundation 3.0.0.0\perfcounters.ini

That restores the counters and will make your workflows start again!


SharePoint Saturday Belgium 2014 - Content Enrichment in SharePoint Search


April 28, 2014 - 15:06, by Steven Van de Craen - 0 Comments

Last Saturday I delivered a session on “Content Enrichment in SharePoint Search” on the Belgian SharePoint Saturday 2014, showing how to configure it, its potential and some development tips and tricks. Although it was a very specific and narrow topic there was a big audience for it. We even had to bring in extra chairs to have everyone seated.

If you missed my session (shame on you!) or you want to read up on it again, below is my deck and demo code.

Slides

SPSBE 2014 Content Enrichment in SharePoint Search

 

Code

The demos showed the basic configuration, how to use WCF Routing to overcome the biggest limitation, how to debug using Fiddler by configuring the proxy, how to debug by attaching to the noderunner process, etc. The final demo would extract bank account numbers from indexed documents and store them in dedicated Managed Properties to increase findability when searching on one of these numbers.

» SPSBE2014.ContentEnrichmentInSearch.zip

Disclaimer: you’re free to use this code as you desire, but I’m not taking responsibility should it blow up your server or make babies cry.

 

Community Red heart

I think we can all agree that SPSBE2014 was a huge success. A big applause for the organisers, the speakers and the attendees for making it all happen. It goes to show that the our SharePoint Community is really great, so show them some love on http://www.biwug.be or http://twitter.com/biwug.


SharePoint 2013 search open in client


March 26, 2014 - 16:26, by Steven Van de Craen - 1 Comments

Issue

SharePoint 2013 search results uses Excel Calculation Services to open workbooks found in the search results, despite having "open in client" specified on the Document Library and/or the Site Collection level. Notice the URL pointing to _layouts/xlviewer.aspx at the bottom of the screen. In this scenario I only have SharePoint Server 2013 installed without any Office Web Apps servers.
Searching a workbook

 

Initial solution

In my previous encounter with this issue I used a custom Search Result Type with Display Template in order to control the link that is rendered for the search result item.

Item_Excel_Client.html

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> 
<head>
<title>Excel Client Item</title>

<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:MasterPageDescription msdt:dt="string">Displays a result tailored for Microsoft Excel documents.</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#SearchResults;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:ManagedPropertyMapping msdt:dt="string">'Title':'Title','Path':'Path','Description':'Description','EditorOWSUSER':'EditorOWSUSER','LastModifiedTime':'LastModifiedTime','CollapsingStatus':'CollapsingStatus','DocId':'DocId','HitHighlightedSummary':'HitHighlightedSummary','HitHighlightedProperties':'HitHighlightedProperties','FileExtension':'FileExtension','ViewsLifeTime':'ViewsLifeTime','ParentLink':'ParentLink','FileType':'FileType','IsContainer':'IsContainer','ServerRedirectedURL':'ServerRedirectedURL','ServerRedirectedEmbedURL':'ServerRedirectedEmbedURL','ServerRedirectedPreviewURL':'ServerRedirectedPreviewURL'</mso:ManagedPropertyMapping>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>
<body>
    <div id="Item_Excel_Client">
<!--#_ 
        if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
            var id = ctx.ClientControl.get_nextUniqueId();
            var itemId = id + Srch.U.Ids.item;
            var hoverId = id + Srch.U.Ids.hover;
            var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Excel_HoverPanel.js";
            $setResultItem(itemId, ctx.CurrentItem);
            ctx.CurrentItem.csr_Icon = Srch.U.getIconUrlByFileExtension(ctx.CurrentItem);
            ctx.CurrentItem.csr_OpenApp = "excel";
            ctx.CurrentItem.csr_Path = ctx.CurrentItem.Path;
            ctx.currentItem_ShowHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
            ctx.currentItem_HideHoverPanelCallback = Srch.U.getHideHoverPanelCallback();
_#-->
            <div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="ExcelItem" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">
                _#=ctx.RenderBody(ctx)=#_                
                <div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div>
            </div>
<!--#_ 
        } 
_#-->
    </div>
</body>
</html>

Item_Excel_Client.js

/* This file is currently associated to an HTML file of the same name and is drawing content from it.  Until the files are disassociated, you will not be able to move, delete, rename, or make any other changes to this file. */

function DisplayTemplate_89a1689efe684e93be8c5bdaa1e46b07(ctx) {
  var ms_outHtml=[];
  var cachePreviousTemplateData = ctx['DisplayTemplateData'];
  ctx['DisplayTemplateData'] = new Object();
  DisplayTemplate_89a1689efe684e93be8c5bdaa1e46b07.DisplayTemplateData = ctx['DisplayTemplateData'];

  ctx['DisplayTemplateData']['TemplateUrl']='~sitecollection\u002f_catalogs\u002fmasterpage\u002fDisplay Templates\u002fSearch\u002fItem_Excel_Client.js';
  ctx['DisplayTemplateData']['TemplateType']='Item';
  ctx['DisplayTemplateData']['TargetControlType']=['SearchResults'];
  this.DisplayTemplateData = ctx['DisplayTemplateData'];

  ctx['DisplayTemplateData']['ManagedPropertyMapping']={'Title':['Title'], 'Path':['Path'], 'Description':['Description'], 'EditorOWSUSER':['EditorOWSUSER'], 'LastModifiedTime':['LastModifiedTime'], 'CollapsingStatus':['CollapsingStatus'], 'DocId':['DocId'], 'HitHighlightedSummary':['HitHighlightedSummary'], 'HitHighlightedProperties':['HitHighlightedProperties'], 'FileExtension':['FileExtension'], 'ViewsLifeTime':['ViewsLifeTime'], 'ParentLink':['ParentLink'], 'FileType':['FileType'], 'IsContainer':['IsContainer'], 'ServerRedirectedURL':['ServerRedirectedURL'], 'ServerRedirectedEmbedURL':['ServerRedirectedEmbedURL'], 'ServerRedirectedPreviewURL':['ServerRedirectedPreviewURL']};
  var cachePreviousItemValuesFunction = ctx['ItemValues'];
  ctx['ItemValues'] = function(slotOrPropName) {
    return Srch.ValueInfo.getCachedCtxItemValue(ctx, slotOrPropName)
};

ms_outHtml.push('',''
); 
        if(!$isNull(ctx.CurrentItem) && !$isNull(ctx.ClientControl)){
            var id = ctx.ClientControl.get_nextUniqueId();
            var itemId = id + Srch.U.Ids.item;
            var hoverId = id + Srch.U.Ids.hover;
            var hoverUrl = "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Excel_HoverPanel.js";
            $setResultItem(itemId, ctx.CurrentItem);
            ctx.CurrentItem.csr_Icon = Srch.U.getIconUrlByFileExtension(ctx.CurrentItem);
            ctx.CurrentItem.csr_OpenApp = "excel";
            ctx.CurrentItem.csr_Path = ctx.CurrentItem.Path;
            ctx.currentItem_ShowHoverPanelCallback = Srch.U.getShowHoverPanelCallback(itemId, hoverId, hoverUrl);
            ctx.currentItem_HideHoverPanelCallback = Srch.U.getHideHoverPanelCallback();
ms_outHtml.push(''
,'            <div id="', $htmlEncode(itemId) ,'" name="Item" data-displaytemplate="ExcelItem" class="ms-srch-item" onmouseover="', ctx.currentItem_ShowHoverPanelCallback ,'" onmouseout="', ctx.currentItem_HideHoverPanelCallback ,'">'
,'                ',ctx.RenderBody(ctx),'                '
,'                <div id="', $htmlEncode(hoverId) ,'" class="ms-srch-hover-outerContainer"></div>'
,'            </div>'
); 
        } 
ms_outHtml.push(''
,'    '
);

  ctx['ItemValues'] = cachePreviousItemValuesFunction;
  ctx['DisplayTemplateData'] = cachePreviousTemplateData;
  return ms_outHtml.join('');
}
function RegisterTemplate_89a1689efe684e93be8c5bdaa1e46b07() {

if ("undefined" != typeof (Srch) &&"undefined" != typeof (Srch.U) &&typeof(Srch.U.registerRenderTemplateByName) == "function") {
  Srch.U.registerRenderTemplateByName("Item_Excel_Client", DisplayTemplate_89a1689efe684e93be8c5bdaa1e46b07);
}

if ("undefined" != typeof (Srch) &&"undefined" != typeof (Srch.U) &&typeof(Srch.U.registerRenderTemplateByName) == "function") {
  Srch.U.registerRenderTemplateByName("~sitecollection\u002f_catalogs\u002fmasterpage\u002fDisplay Templates\u002fSearch\u002fItem_Excel_Client.js", DisplayTemplate_89a1689efe684e93be8c5bdaa1e46b07);
}

}
RegisterTemplate_89a1689efe684e93be8c5bdaa1e46b07();
if (typeof(RegisterModuleInit) == "function" && typeof(Srch.U.replaceUrlTokens) == "function") {
  RegisterModuleInit(Srch.U.replaceUrlTokens("~sitecollection\u002f_catalogs\u002fmasterpage\u002fDisplay Templates\u002fSearch\u002fItem_Excel_Client.js"), RegisterTemplate_89a1689efe684e93be8c5bdaa1e46b07);
}

 

Then I pushed the Display Template and Result Type automatically to all Site Collections, because I wanted a uniform experience.

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction:SilentlyContinue

function DropFile([Microsoft.SharePoint.SPWeb]$spweb, [string]$fileName, [byte[]]$fileContents)
{
    $spfolderUrl = $spweb.Url + "/_catalogs/masterpage/Display Templates/Search";
    $spfolder = $spweb.GetFolder($spfolderUrl);
    $spfile = $spweb.GetFile("$spfolderUrl\$fileName");
    
    if ($spfile.Exists)
    {
        $spfile.CheckOut();
    }

    $spfile = $spfolder.Files.Add($fileName, $fileContents, $true);
    
    if ($spfile.CheckOutType -ne "None")
    {
        $spfile.CheckIn("");
    }

    $spfile.Publish("");
    $spfile.Approve("");
    
    Write-Host " > Display Template Provisioned."
    
    return $spfile;
}

function CreateSearchResultType([Microsoft.SharePoint.SPWeb]$spweb, [string]$spfileUrl)
{
    $ssa = Get-SPEnterpriseSearchServiceApplication
    $owner = Get-SPEnterpriseSearchOwner -Level SPSite -SPWeb $spweb
    $excelRIT = Get-SPEnterpriseSearchResultItemType -Owner $owner -SearchApplication $ssa | Where Name -eq "Microsoft Excel"
    $rules = $excelRIT.Rules
    $dispProps = $excelRIT.DisplayProperties
    $sptemplateUrl = "~sitecollection/$spfileUrl";
    
    Write-Host $sptemplateUrl;

    Get-SPEnterpriseSearchResultItemType -Owner $owner -SearchApplication $ssa | Where Name -eq "Microsoft Excel (Client)" | Remove-SPEnterpriseSearchResultItemType -Owner:$owner -SearchApplication $ssa -Confirm:$false
    $rit = New-SPEnterpriseSearchResultItemType -Name "Microsoft Excel (Client)" -Owner $owner -SearchApplication $ssa -Rules $rules -DisplayProperties $dispProps -DisplayTemplateUrl $sptemplateUrl
    
    Write-Host " > Search Result Type Created."
    
    return $rit;
}

#########################################

$cd = gl
$fileNames = @("Item_Excel_Client.js", "Item_Excel_Client.html");

Get-SPWebApplication "http://mywebapp" | Get-SPSite -Limit ALL | ForEach {
    $spsite = $_;
    $spweb = $spsite.RootWeb;

    Write-Host $spsite.Url

    # Upload File(s)
    $fileNames | foreach {
        $fileName = $_;
        $fileContents = [System.IO.File]::ReadAllBytes("$cd\$fileName");
        $spfile = DropFile $spweb $filename $fileContents;
    }

    # Register Search Result Type
    $fileUrl = $spfile.Url.Replace(".html", ".js");
    CreateSearchResultType $spweb $fileUrl;
}

Better solution

Recently I stumbled upon the “Preferences” link at the bottom of the search result page. This allows each user to control how links in the search results should be opened.

Search preferences

 

This actually changes the experience for the given user immediately… awesome! I did some digging and it seems to be saved globally to the Search Service Application (Proxy), so all Web Applications and Site Collections making use of the same SSA should give the user a uniform experience.

The question still stands whether this setting can be pushed out programmatically to a specific user or group of users. I was thinking along the lines of the following script, but no luck so far.

$web = Get-SPWeb http://intranet
$ctx = [Microsoft.SharePoint.SPContext]::GetContext($web)
$pref =[Microsoft.Office.Server.Search.Administration.UserPreference]::GetUserPreference($false, $ctx)
$pref

HTH


SharePoint and PowerShell remoting


February 28, 2014 - 13:30, by Steven Van de Craen - 2 Comments

In my current project I’m dabbling with PowerShell to query different servers and information from different SharePoint 2010 farms in the organization. This blog contains a brief overview of the steps I took in order to get a working configuration.

Enable remoting and credential pass-through

You need to enable remoting and also credential pass-through. The latter is important because your SharePoint statements will need to authenticate to the SQL Server containing your SharePoint databases, or all your statements will fail with an access denied.

Enable-PSRemoting

I did this on both the “client” and the “server”, because my client can actually be queried itself as well…

Enable-WSManCredSSP -Role Client –DelegateComputer MYSERVER01

I ran this on the “client”.

Enable-WSManCredSSP –Role Server

I ran this on the “server”.

CredSSP allows the credentials to pass-through (double hop) . There’s a security note in the TechNet article;

Caution: CredSSP authentication delegates the user's credentials from the local computer to a remote computer. This practice increases the security risk of the remote operation. If the remote computer is compromised, when credentials are passed to it, the credentials can be used to control the network session.

» Enable-PSRemoting: http://technet.microsoft.com/en-us/library/hh849694.aspx

» Enable-WSManCredSSP: http://technet.microsoft.com/en-us/library/hh849872.aspx

Force PSVersion 2.0

If you have multiple versions of PowerShell then most likely new instances will be using the latest version. There is a common issue regarding SharePoint 2010 Management Shell and PowerShell 3.0 (or above) outlined here: http://support.microsoft.com/kb/2796733.

Microsoft SharePoint is not supported with version 4.0.30319.17929 of the Microsoft .Net Runtime.

If you’re seeing this issue when remoting you can create a new PSSessionConfiguration on the “server” and have “clients” reference it.

Register-PSSessionConfiguration -Name PS2 -PSVersion 2.0

I ran this on the “server” in a PowerShell 3.0 prompt.

» Register-PSSessionConfiguration: http://technet.microsoft.com/en-us/library/hh847899.aspx

Invoke-Command / Enter-PSSession

There’s but one thing that remains, and that is to see if it worked. Make sure to specify CredSSP and the reference to the PSSessionConfiguration object.

Invoke-Command -ComputerName MYSERVER01 -ConfigurationName PS2 -Authentication CredSSP –Credential MYDOMAIN\myuser -ScriptBlock { asnp Microsoft.SharePoint.PowerShell; Get-SPFarm }

» Invoke-Command: http://technet.microsoft.com/en-us/library/hh849719.aspx

» Enter-PSSession: http://technet.microsoft.com/en-us/library/hh849707.aspx

 

Happy remoting!


Excel REST API not refreshing data


February 20, 2014 - 07:00, by Steven Van de Craen - 0 Comments

We’re using the Excel REST API in SharePoint 2010 to visualize some graphs directly on a web page. The information is stored in an Excel workbook in a document library and that had connections to backend data stores. The connection settings inside the workbook were configured with credentials inside the connection string. However we noticed that the graphs on the web page would not update unless we opened and saved the workbook.

Trusted File Locations

There’s a setting in your Trusted File Locations (in the configuration of the Excel Service Application) that you have to check, in order to have the REST API update the connections.

Allow External Data Using REST 

Unattended Service Account

Even if you have credentials inside the connection string, you’ll still need to configure an Unattended Service Account because the ECS engine will impersonate that user to “open” the workbook.

This is quite accurately logged in the ULS logs, but somehow we missed it at first:

02/10/2014 10:50:59.25  w3wp.exe (0x2268)        0x0540  Excel Services Application            Excel Calculation Services             c35r                Medium               CredentialsProvider.GetCredentials: the following exception occurred when trying to acquire the unattended account credentials: Microsoft.Office.Excel.Server.CalculationServer.Interop.ConnectionException: Exception of type 'Microsoft.Office.Excel.Server.CalculationServer.Interop.ConnectionException' was thrown.     at Microsoft.Office.Excel.Server.CalculationServer.SecureStoreHelper.GetSecureStoreCredentials(Request request, String secureStoreApplicationId, Boolean delegateUser)     at Microsoft.Office.Excel.Server.CalculationServer.UnattendedAccount.GetCredentialsFromStore(Request request)     at Microsoft.Office.Excel.Server.CalculationServer.UnattendedAccount.GetCredentials(Request request)     at Microsoft.Office.Excel.Server.CalculationServer.CredentialsProvider.GetCredentials(Request request, ConnectionInfo connInfo, String dataConnectionName, Credentials& credentials)            38a5d8ad-09a0-45eb-af89-ebf908bee2fc

02/10/2014 10:50:59.25  w3wp.exe (0x2268)        0x0540  Excel Services Application            External Data     3237       Information                Unable to establish connection using only the connection string. If a username and password are saved in the connection string, they may not be correct, or the Unattended Service Account may not be configured. [Session: 1.V23.619PvoW1uPgVeMNVtZtgxpi90.5.en-US5.en-US73.-0060#0000-10-00-05T03:00:00:0000#+0000#0000-03-00-05T02:00:00:0000#-006036.227417de-0d92-42c3-ad24-3f32334d87e21.N User: 0#.w|domain\user1]         38a5d8ad-09a0-45eb-af89-ebf908bee2fc

Configuring an Unattended Service Account is a matter of setting up a Secure Store Service Application and Target Application, and then configure the Excel Service Application to use that Application ID for Unattended Service Account.

Secure Store Service Application

Excel Unattended Service Account

Now we finally have up-to-date graphs on our web page without opening and saving the workbook.


Nintex Workflow and emailing to groups


February 19, 2014 - 15:08, by Steven Van de Craen - 0 Comments

Nintex Workflow is able to send emails via the Send notification action.

Nintex Workflow - Send notification

A question often asked is if it can send emails to SharePoint groups or Active Directory groups. The answer is; Yes it can!

There are some things you need to know though…

Send to an Active Directory group

You can use AD security groups, but they must have a (dummy) email value configured or the workflow will fail on this.

The email will only be sent to the direct users in the AD group. Nested AD groups will be ignored.

Send to a SharePoint group

This works about the same as AD groups. The email will be sent to direct users in the SharePoint group, and to direct users of any nested AD group in the SharePoint group. It won’t go into nested AD groups of the AD group though (same as above).

Also, you cannot nest SharePoint groups.

 

HTH


 Next >>