tag:blogger.com,1999:blog-233202842024-02-19T21:49:28.813+11:00Alan Coulter - Eat, Live, Breath SharePointAlan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.comBlogger58125tag:blogger.com,1999:blog-23320284.post-67714538985613493972020-08-20T17:50:00.000+10:002020-08-20T17:50:41.458+10:00Office 365 Groups not showing up in Outlook<p>I had a request recently from a client of mine, who was not seeing all of the Office 365 Groups (that had Microsoft Teams instances) showing up in Outlook.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJYZ_Exd1t5BQhLRIwQ-qim6ygxjui4On0QaLZGPgL4uuHeuks4hyphenhyphenyk0NfN-5Jm37Z4CJG3MKaa-U4C2lk_eAbuh0ECLMcVBqNkJtzN9EJVJrk5mwXauCepaN60s4r6ITDZKitQ/s212/CurrentGroupsInOutlook.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="212" data-original-width="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJYZ_Exd1t5BQhLRIwQ-qim6ygxjui4On0QaLZGPgL4uuHeuks4hyphenhyphenyk0NfN-5Jm37Z4CJG3MKaa-U4C2lk_eAbuh0ECLMcVBqNkJtzN9EJVJrk5mwXauCepaN60s4r6ITDZKitQ/s0/CurrentGroupsInOutlook.png" /></a></div><p><br /></p><p>Typically within the Outlook client (and web version for that matter) in the left hand menu you see a 'Groups' section, with Groups that you have joined underneath it.</p><p>The client had tried all sorts of things within the Outlook client, including going into Manage Groups | All, and then rejoining each the groups (that they were in fact already an owner of). In some cases, when attempting to join the group, they would get the error 'Your request could not be sent. Please try again later'.</p><p>Their main 'All Staff' also would not show up, which meant that people couldn't easily create a company event (luckily I had the group calendar app on their Intranet home page, so they could add events that way).</p><p>I found the article <a href="#" id="https://petri.com/hiding-office-365-groups-exchange-clients " name="https://petri.com/hiding-office-365-groups-exchange-clients ">https://petri.com/hiding-office-365-groups-exchange-clients</a> which stated '<b>Office 365 will hide groups created by Teams from Outlook by default</b>'. I understand that this may have been a strategy from Microsoft to stop the clogging up of Microsoft Groups showing up in Outlook, but my company was quite small and needed to show all of their groups.</p><p>To fix the issue, I first ran:</p><p><b>Import-Module ExchangeOnlineManagement</b></p><p>I then ran <b>Connect-ExchangeOnline -UserPrincipalName "<email address>" -ShowProgress $true</b>.</p><p>Once connected, I ran:</p><p><b>Get-UnifiedGroup -ResultSize Unlimited | Select DisplayName, Alias, PrimarySmtpAddress, HiddenFromExchangeClientsEnabled</b> </p><p>This listed each of the groups, showing that in fact that many were configured to be hidden from the Exchange client (HiddenFromExchangeClientEnabled attribute).</p><p>I then ran <b>Set-UnifiedGroup -Identity "<group name>" -HiddenFromExchangeClientsEnabled:$false</b> against each group that needed to be exposed.</p><p>After exiting Outlook and starting it again, the list of groups then showed up. As a side benefit, as the All Staff group was now showing up, people could easily enter company events through the Calendar area of Outlook.</p><p><br /></p>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-20903705303471565152019-07-22T19:21:00.000+10:002019-07-23T11:44:02.105+10:00Splitting up PnP files so that LogicApps/FunctionApps do not time outI am a big fan of Microsoft Patterns and Practices (PnP) and use it both from a scripting perspective (PowerShell) and web development perspective (PnPJS).<br />
<br />
Recently I was involved in building an automated project site provisioning process for a client, using LogicApps and FunctionApps. I had generated a number of PnP templates for a site (e.g. 1 for site columns/content types, 1 for lists, 1 for features and 1 for pages/navigation) using the Get-PnPProvisioningTemplate -out template.pnp -Handlers <required as="" columns="" contenttypes="" handlers="" nbsp="" p="" site="" such=""><br />
As my plan was to store the PnP templates within SharePoint, the file extensions must be .pnp and not .xml (.xml will not work). Within the document library I stored a 'sequence' field, which basically dictated which PnP templates should be applied and in what order. The LogicApp then iterated this library and called various FunctionApps to first apply the necessary PnP file and (later) to add custom web parts.<br />
<br />
If you did not know, the default timeout on a Function App is only 2 minutes (and PnP provisioning can be slow). This can be increased up to 10 minutes by navigating to 'Platform Features | Kudo | Debug Console | PowerShell' within the Azure console, navigating into the 'site | wwwroot', then clicking the pencil icon next to host.json and adding the functionTimeout JSON property to 10 minutes.<br />
E.g.<br /><span style="font-family: "courier new" , "courier" , monospace;">
{<br />
"version": "2.0",<br />
"functionTimeout": "00:10:00"<br />
}</span><br />
<br />
Sometimes however, this 10 minute timeout still isn't enough, particularly if you have a large number of content types and lists in the site. In order to fix this you have to 'hack' the Lists PnP file, so that you split it up into multiple (smaller) List PnP files. To do this, here are the steps:<br />
<br />
1) Copy your PnP file to a temporary folder.<br />
2) Change the file extension from .pnp to .zip.<br />
3) Within the 'files' folder, edit the XML file and strip out the number of lists to be provisioned<br />
4) As you will be saving these updates to a new PnP filename, it is important that the files-map.xml file in the ProvisioningTemplate folder is updated to match the new PnP filename, except with the .xml extension. For example, if I was going to name my PnP file ProjectSiteTemplateLists1.pnp, the files-map.xml file would look like:<br />
</required><br />
<span style="font-size: x-small;"><pnpfilesmap xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="clr-namespace:OfficeDevPnP.Core.Framework.Provisioning.Connectors.OpenXML.Model;assembly=OfficeDevPnP.Core"></pnpfilesmap></span><br />
<span style="font-size: x-small;"> <pnpfilesmap .map=""></pnpfilesmap></span><br />
<span style="font-size: x-small;"> <x:string x:key="bd2bb305-c37e-40cf-a184-cd3755b2354f.resx">ProjectSiteTemplateLists.en-US.resx</x:string></span><br />
<span style="font-size: x-small;"> <x:string x:key="3adc20bb-b7c0-4724-a3f3-fb3429420063.xml">ProjectSiteTemplateLists1.xml</x:string></span><br />
<span style="font-size: x-small;"> </span><br />
<span style="font-size: x-small;"></span><br />
<br />
<required as="" columns="" contenttypes="" handlers="" nbsp="" p="" site="" such="">
5) Within Windows Explorer, navigate back to the root where you had extracted the files initially. Select all of the files and create a zip file from it (I use 7-zip, but you could just use the Windows Send To Zip file option).<br />
6) Rename the .zip file to ProjectSiteTemplateLists1.pnp.<br />
7) Repeat the process to create the other list pnp files (i.e. by starting with the full PnP file again).<br />
<br />
I hope this helps someone. Often you don't do this sort of thing often, but when you do it is important that it is done correctly, as otherwise you will get a nasty 'Apply-PnPProvisioningTemplate : The Provisioning Template URI ProjectSiteTemplateLists1.xml is not valid'.<br />
</required>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-3365049831318265042018-04-24T11:27:00.000+10:002018-04-24T11:27:12.142+10:00List of Issues Experienced with SharePoint January 2018 CUAt one particular client site, after we applied the January 2018 CU to their SharePoint 2013 environment, we found that one site column, which was used in multiple site collections, all of a sudden had a space in its internal name (which is not valid). For the end user, this was preventing them from creating new Document Sets within a library. What I found was that even though the offending field wasn't in the Document Set Content Type that they were trying the use, the fact that the invalid field was associated with the list (via another content type), during the process of creating the document set it throws an internal error "The schema for field with this name is wrong or missing. Field 'Meeting Type'". As the Document Set errors were not discovered until several days after the patch was applied, we could not roll back to the snapshot taken prior to the CU being applied. To fix the issue (as we didn't want to wait for Microsoft Support), we created a new field, added it to the Content Type, removed the offending field, then had to go into every library and physically remove the old field from there also.<br />
<br />
Another issue we experienced with the Jan 201 CU was that also SharePoint thought the User Profile Sync service was started, under the covers in the Services.msc snap-in, it was not (even though it was set to Automatic). The underlying error in the Event log was 'Detection of product '<guid>', feature 'PeopleILM' failed during request for component '<second guid="">'. This was due to the Network Service not having access to the C:\Program Files\Microsoft Office Servers\15.0\SQL\DatabaseSetttings.sql file. By giving the Network Service account read/execute rights to the 15 folder, the Synchronization service was able to be started and we were able to do profile imports again.</second></guid><br />
<br />
Note that for another customer, were I had setup a SharePoint/Project Server 2016 environment, the January 2018 CU ships with a corrupt resource file 'PWA.en-us.resx', which prevents you from administering projects (i.e. all action buttons in the ribbon are disabled). To fix this, we overwrote the file with a copy of the PWA.resx file.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-62670996271281935802018-01-25T11:24:00.000+11:002018-01-25T11:24:00.858+11:00Date Range Comparisons within Nintex WorkflowI recently was tasked to amend a document submission/review workflow, where documents could only be submitted (via changing a status to 'Ready for Review') during a particular window. Typically the window was only for a certain day each month, between 7am and 7pm.<br />
<br />
I first started by creating a separate list, which would contain a single list item that had a 'Date From' and 'Date To' field. I then added a query list action with a CAML query of:<br />
<br />
<Query><br />
<Lists><br />
<List ID="{D5DA2C78-F280-4A30-9D9D-FD43997B5B08}"/><br />
</Lists><br />
<ViewFields><br />
<FieldRef Name="ID"><br />
</ViewFields><br />
<Where><br />
<DateRangesOverlap><br />
<FieldRef Name="DateFrom" /><br />
<FieldRef Name="DateTo" /><br />
<Value IncludeTimeValue="TRUE" Type="DateTime"><br />
<Today/><br />
</Value><br />
</DateRangesOverlap><br />
<Where><br />
<Query><br />
<br />
Note: I substituted <Now/> for <Today/> and also a Workflow variable for the current date time (derived from a Calculate date action) to see if it made any difference.<br />
<br />
I found that if the submission date was on a different day to today, the logic would work fine and not return any results (which is what I was checking for after the query list action). However, if the current datetime was outside of the window (which was today), it would return a result, even if the time was outside of the window. <br />
<br />
I found the article <a href="https://community.nintex.com/thread/3213">https://community.nintex.com/thread/3213</a>, where Paul Svetleachni said:<br />
"The time is used to calculate if one period of time turns into next day or not. Thus only calculated based on actual day and hours are used if it is next day or not. So, filtering by specific hour/min/second is not possible, it is only used to determine if next day is added or subtracted based on calculation of date."
So I tried various attempts using a set a condition action (based on <a href="https://community.nintex.com/thread/10160?commentID=32146#comment-32146">https://community.nintex.com/thread/10160?commentID=32146#comment-32146</a>), which didn't work for me. I amended this logic to the following, but still no luck:<br />
<br />
Condition: If any value equals value<br />
Where: "Workflow Data" - "Current Datetime"<br />
is greater than "Workflow Data" - "DateTo"<br />
<br />
OR<br />
<br />
Condition: If any value equals value<br />
Where: "Workflow Data" - "Current Datetime"<br />
is less than "Workflow Data" - "DateFrom"<br />
<br />
In the end I decided to convert the dates into numbers, then do my comparison that way, which WORKED!<br />
<br />
Steps to reproduce:<br />
1. Build String to populate Workflow variable "CurrentTimeAsNumberString". The formula for this was:<br />
fn-FormateDate({Common:CurrentDate},"yyyyMMdd")fn-FormatDate({Common:CurrentTime},"HHmm")<br />
<br />
This produced a string that looked like "201801250915"<br />
<br />
2. Convert the CurrentTimeAsNumberString workflow variable to CurrentTimeAsNumber, using the Convert value action (where "Input" is CurrentTImeAsNumberString and "Store result in" is CurrentTimeAsNumber).<br />
<br />
3. Repeat the Build String action, this time to populate the "DateFromAsNumberString" using the formula:<br />
fn-FormateDate({WorkflowVariable:DateFrom},"yyyyMMdd")fn-FormatDate({WorkflowVariable:DateFrom},"HHmm")<br />
<br />
4. Convert DateFromAsNumberString to DateFromAsNumber using the convert value action.<br />
<br />
5. Repeat the Build String action, this time to populate the "DateToAsNumberString" using the formula:<br />
fn-FormateDate({WorkflowVariable:DateTo},"yyyyMMdd")fn-FormatDate({WorkflowVariable:DateTo},"HHmm")<br />
<br />
6. Convert DateToAsNumberString to DateToAsNumber using the convert value action.<br />
<br />
7. Update the set condition action shown above to use the numbers instead of dates in the comparison:<br />
<br />
Condition: If any value equals value<br />
Where: "Workflow Data" - "CurrentTimeAsNumber"<br />
is greater than "Workflow Data" - "DateToAsNumber"<br />
<br />
OR<br />
<br />
Condition: If any value equals value<br />
Where: "Workflow Data" - "CurrentTimeAsNumber"<br />
is less than "Workflow Data" - "DateFromAsNumber"<br />
<br />
<br />
I hope this helps someone, as I was pulling my hair out trying to figure out why such a simple thing such as a data range comparison doesn't work naturally within SharePoint (and therefore Nintex Workflow).Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-50980262945619631082017-02-23T18:49:00.001+11:002017-02-23T18:49:26.248+11:00Installing SharePoint 2013 on Windows 2012 R2 with .NET 4.6.1I ran into an issue today whereby my SharePoint installer would crash after all of the prerequisites were installed and I tried to run setup.exe. After delving a little deeper I found the article <a href="https://support.microsoft.com/en-us/help/3087184/sharepoint-2013-or-project-server-2013-setup-error-if-the-.net-framework-4.6-is-installed">https://support.microsoft.com/en-us/help/3087184/sharepoint-2013-or-project-server-2013-setup-error-if-the-.net-framework-4.6-is-installed</a>.<br />
<br />
Microsoft's original response to this problem was to postpone the installation of .NET 4.6.1 until after you've installed SharePoint - well that doesn't help me when the server image already has it baked in.<br />
Then Microsoft came out with a fix, which required a DLL file to be copied into the updates directory of the installation media (i.e. copy everything to a local directory, then copy in the dll file). See <a href="https://download.microsoft.com/download/3/6/2/362c4a9c-4afe-425e-825f-369d34d64f4e/svrsetup_15-0-4709-1000_x64.zip">https://download.microsoft.com/download/3/6/2/362c4a9c-4afe-425e-825f-369d34d64f4e/svrsetup_15-0-4709-1000_x64.zip</a> for SharePoint 2013 patch file.<br />
<br />
In my case it still wasn't working, but I later discovered that it was because I was also trying to slipstream a Cumulative Update into the installation (which I normally do to speed up the installation process and remove the need for multiple PSConfig operations).<br />
<br />
So the morale to the story - if you want to use this fix, you can't slipstream any updates into the installation also.<br />
<br />
FYI, to find out what version of .NET is actually installed on a Windows 2012 Server, follow the steps at <a href="https://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396#net_d">https://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396#net_d</a>.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-28599636599538369702016-11-16T16:49:00.003+11:002016-11-16T16:49:52.896+11:00Displaying a random SharePoint Search result using Display TemplatesOn a recent project I had the requirement to randomly display a staff profile on the home page of the Intranet. The staff profile would provide some basic details of the person (with a head shot), then on clicking the item the user would be redirected to a page that displayed a bunch of fun questions and the person's response to each question. The web page used its own custom page layout and associated content type to store all of the answers.<br />
<br />
Now we've probably all seen various custom developed web parts in the past, utilising calls to the User Profile Service or some other list via CAML queries. We've probably also seen Content Query Web Part solutions. For this project I was determined to leverage search as much as possible, reducing the continual queries to the backend data source. So my technical challenge was not in getting the results (as search query rules/result sources do a good job of that); but rather randomly selecting an item to display from the result pool.<br />
<br />
So in order to make this magic happen, I went about with the idea of creating a custom group display template (i.e. to generate the seed) and a custom item template, whose job was to render the item if it was told to do so. So how do you do this? Quite simply, you add your own variables to the Search context!<br />
<br />
In your control template, you put the following :<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><!--#_</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> var randomItem = 0; // default to first item returned from search</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> try {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> var totalResults = ctx.ListData.ResultTables[0].ResultRows.length; //get the total number of results returned</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if (!isNaN(totalResults))</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> randomItem = Math.floor(Math.random() * totalResults);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ctx.RandomItemNumber = randomItem; // prime our own variable for the Item display template</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> catch (err) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> console.log(err);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">_#--></span><br />
<br />
Then in your item template, you put the following around the outer part of the display template:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><!--#_</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> var showItem = true; // default to showing the item</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> try</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if (ctx.CurrentItemIdx != ctx.RandomItemNumber) {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> showItem = false;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> catch (err)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> console.log(err);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> if (showItem)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> _#--></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">...Your Item output rendering goes here...</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><!--#_</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">_#--></span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span>
<span style="font-family: inherit;">I hope this helps someone - it took a little bit of playing around to discover how to get this working, but in the end it was really quite simple.</span>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-59121130918456504202015-03-27T11:34:00.002+11:002015-03-27T11:34:41.310+11:00Get all Office 365 Video Channels, Groups and Delve Boards with RESTsource: <a href="http://www.vrdmn.com/2015/01/get-all-office-365-video-channels.html">http://www.vrdmn.com/2015/01/get-all-office-365-video-channels.html</a><br />
<br />
Office 365 has introduced 3 new portals recently: Videos, Groups and Delve. Behind the scenes, the architecture of Videos and Groups is such that each Video channel is a site collection and so is each Group. For Delve boards, each board is saved as a Tag and when you add a document to a board, the document is tagged with the name of the board.<br />
<br />
If you are working on a solution for Office 365 and want to integrate Videos, Groups or Delve, here is how you can get a list of all of them using the SharePoint REST API:<br />
<br />
1) Get all Office 365 Video Channels with REST API:<br /><span style="font-family: consolas, "liberation mono", menlo, courier, monospace; font-size: 12px; line-height: 16.79px; white-space: pre;"><span style="color: blue;"></span></span><a href="https://siteurl.sharepoint.com/_api/search/query?querytext='contentclass:sts_site WebTemplate:POINTPUBLISHINGTOPIC'&SelectProperties='WebTemplate,Title,Path'&rowlimit=50" target="_blank">https://siteurl.sharepoint.com/_api/search/query?querytext='contentclass:sts_site WebTemplate:POINTPUBLISHINGTOPIC'&SelectProperties='WebTemplate,Title,Path'&rowlimit=50</a> <br />
<br />
2) Get all Office 365 Groups with REST API:<br /><a href="https://siteurl.sharepoint.com/_api/search/query?querytext='contentclass:sts_site WebTemplate:Group'&SelectProperties='WebTemplate,Title,Path'&rowlimit=50" target="_blank">https://siteurl.sharepoint.com/_api/search/query?querytext='contentclass:sts_site WebTemplate:Group'&SelectProperties='WebTemplate,Title,Path'&rowlimit=50</a> <br />
<br />
3) Get all Delve Boards with REST API:<br /><a href="https://siteurl.sharepoint.com/_api/search/query?querytext='(Path:"TAG://PUBLIC/?NAME=*")'&Properties='IncludeExternalContent:true'&selectproperties='Path,Title'&rowlimit=50" target="_blank">https://siteurl.sharepoint.com/_api/search/query?querytext='(Path:"TAG://PUBLIC/?NAME=*")'&Properties='IncludeExternalContent:true'&selectproperties='Path,Title'&rowlimit=50</a>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-80698080877966569192015-03-27T11:24:00.001+11:002015-03-27T11:24:00.990+11:00SharePoint 2010 Public Site Navigation not working on latest version of Safari for the MacThe link below provides the fix, which is an update to the compat.browser file.<br />
<a href="http://blog.sharepointexperience.com/2014/10/did-safari-or-ios-8-break-your-sharepoint-2010-site/"><span style="text-decoration: underline;">http://blog.sharepointexperience.com/2014/10/did-safari-or-ios-8-break-your-sharepoint-2010-site/</span></a>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-34257684325455722882012-10-24T17:16:00.000+11:002012-10-24T17:24:31.495+11:00onclick attributes do not fire on custom search XSLT on a Publishing pageI had a requirement for a client this week to create a search solution for a custom list (for Contractors). Basically the client wanted to use SharePoint Search and a custom XSLT to render the list items. The two challenges I faced (without reverting to full on development):
<br />
<ol>
<li>Make the results sort by the Company name. Note that OOB, the Core Search Results web part does not support this. It only supports sorting by date or relevance (which is the default). </li>
<li>Open the results in a modal popup window, rather than redirecting the whole page to the list item. </li>
</ol>
<br />
To solve point 1, I found the blog entry <a href="http://ddkonline.blogspot.com.au/2011/12/sharepoint-2010-modifying-core-search.html">http://ddkonline.blogspot.com.au/2011/12/sharepoint-2010-modifying-core-search.html</a> which allowed me to change the sort order to company.
<br />
The second problem was more frustrating to solve. I thought that within the XSLT I would add the onclick element, calling a function to load the given URL into a SharePoint modal window. But every time I tried, the onclick event just wouldn't fire. I went back to simple onclick="alert('hello')" and it still didn't work. Within the body of the page I added straight links, switched to HTML mode and added the onclick events there, but every time I did this, SharePoint would strip it out. The blog entry at <a href="http://blog.mastykarz.nl/tracking-links-google-analytics-sharepoint-2010-mavention-google-analytics-links-tracking/">http://blog.mastykarz.nl/tracking-links-google-analytics-sharepoint-2010-mavention-google-analytics-links-tracking/</a> then gave me a clue. Basically SharePoint was blocking basic onclick events from firing or removing them all together. So to solve the problem, I removed the onclick attributes, then embedded a jquery function within the XSLT to iterate through all links and add the onclick event. This time it worked. FYI, below is the XSLT block: <span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:text disable-output-escaping="yes">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><![CDATA[
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><script type="text/javascript" src="/_layouts/Inflow/cqwp.js"></script>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><script type="text/javascript">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">$(document).ready(function () {
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> if ($("#results-table").length) {
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> $("#results-table a").click(function() {
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> openDialog($(this).attr('href'));
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> return false;
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> });
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> }
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">});
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></script>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">]]>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></xsl:text>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><div class="srch-results" accesskey="W">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><table id="results-table" border="1">
<tr><th>Company</th><th>Active / Inactive</th><th>Full Name</th></tr>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:apply-templates select="All_Results/Result">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><!-- The xsl-sort needs operate upon a single field - it doesn't work if the sort has to evaluate child nodes-->
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:sort select="company" />
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></xsl:apply-templates>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></table>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></div>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:call-template name="DisplayMoreResultsAnchor" />
</xsl:template></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><!-- This template is called for each result -->
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:template match="Result">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:variable name="id" select="id"/>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:variable name="currentId" select="concat($IdPrefix,$id)"/></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">
<xsl:variable name="url" select="url"/>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><tr><td>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><a id="{concat($currentId,'_Title')}">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:attribute name="href">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:value-of select="$url"/>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></xsl:attribute>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:attribute name="title">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:value-of select="company"/>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></xsl:attribute>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:value-of select="company"/></span><span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></a>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></td></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><td></span><span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><xsl:value-of select="activeinactive" /></td></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><td><xsl:value-of select="fullname" /></td></span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></tr>
</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"></xsl:template>
</span><br />
<div>
</div>
Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-27669860545100287942012-09-24T12:30:00.000+10:002012-09-24T12:30:08.536+10:00How to fix “Add Host to Workflow Farm problem” when installing Windows Azure Workflow in SharePoint2013 Preview<p>I had this issue today when installing Windows Azure Workflow in my SharePoint 2013 environment. </p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP2NlJC8FVhSRVNpdbJXqKXIB1-vZUoKlZlskqzbwMnCcHBZ_niCOWYwtl1X7NqiyCuFEeBlrdKUrI3n8grxgorR5eZHEczD6q5EAJ5lMMZ9J4d7Xp-LubYm1k81-LfyW5UKg-7Q/s1600/072312_0544_howtofixadd1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="142" width="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP2NlJC8FVhSRVNpdbJXqKXIB1-vZUoKlZlskqzbwMnCcHBZ_niCOWYwtl1X7NqiyCuFEeBlrdKUrI3n8grxgorR5eZHEczD6q5EAJ5lMMZ9J4d7Xp-LubYm1k81-LfyW5UKg-7Q/s320/072312_0544_howtofixadd1.png" /></a></div>
<p>In my case, the error message was as follows:<br/>
System.Management.Automation.CmdletInvocationException: Could not successfully create management Service Bus entity 'WF_Management/WFTOPIC' with multiple retries within timespan of 00:02:05.5769235. ---> System.TimeoutException: Could not successfully create management Service Bus entity 'WF_Management/WFTOPIC' with multiple retries within timespan of 00:02:05.5769235. ---> System.UnauthorizedAccessException: The remote server returned an error: (401) Unauthorized. Authorization failed for specified action: Manage..TrackingId:3e0f0351-14d0-4620-b80e-c506156b6f7a,TimeStamp:9/24/2012 1:15:07 AM ---> System.Net.WebException: The remote server returned an error: (401) Unauthorized.</p>
<p>Other posts talk about ensuring your RunAs account uses a FQDN. E.g. sp_content@wingtip.com, which I had been doing. Instructions from CriticalPathTraining also say that this account should have dbcreator and securityadmin rights at the SQL level, that TCPIP should be enabled through SQL Configuration Manager, and that the RunAs account is a member of the local administrator group (which it was).</p>
<p>To fix this, I first went to each of the workflow databases and explicitly set the membership for the sp_content database so that it had db_owner and also was a member of the respective application roles that had been created for each database. E.g. Store.Operators and Store.Administrators in the SbManagementDB database. I then logged into the SharePoint server as the sp_content account and re-ran the Workflow configuration to join the existing farm. This time it worked!</p>
Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-41905842356085939702011-07-24T12:58:00.002+10:002011-07-24T13:16:16.917+10:00SharePoint Search Exception: The server did not provide a meaningful replyRecently I had to configure search sometime after the initial build, which was done using AutoSPInstaller. To ensure consistency of approach, I created a slightly modified version of AutoSPInstallerMain.ps1 and also XML AutoSPInstallerInput files. The only real difference in the XML file was that I was instructing AutoSPInstaller to provision search, and also that I was instructing it to not provision Central Admin (as this was already provisioned and I have experienced the script failing when CA had already been created). The main difference in the AutoSPInstallerMain.ps1 was that I commented out a lot of the entries in the Setup-Services function (i.e. to only run StartSearchQueryAndSiteSettingsService and CreateEnterpriseSearchServiceApp). <br /><br />Shortly after the installation/configuration of Search, users were experiencing a correlation exception when performing searches. The ULS log returned the error 'Internal server error exception: System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error.'. Subsequent messages also included 'A runtime exception was detected. Details follow. Message: Thread was being aborted'.<br /><br />To fix this issue I had to do the following:<br />1) On each SharePoint Server, modify the permissions to the C:\Windows\Temp directory to ensure that the WSS_WPG group had both read and write access (by default after the Search installation, this group only had read access)<br />2) Restart the 'SharePoint Server Search 14' search on each server.<br /><br />Once this was done, search began to work. Hope this helps someone.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-29850066506877030832011-05-07T23:00:00.002+10:002011-05-07T23:16:25.565+10:00Upgrading a Custom Search Results XSLT from 2007 to 2010Whilst upgrading a public web site that I had previously created in SharePoint 2007, during testing I noticed this strange number appearing at the end of my upgraded search results page. After the last result I was seeing a number like 68050. This number changed as I performed more searches. <br />I hadn't touched my custom search results XSLT at all during the upgrade, so I was wondering why this number started appearing. To troubleshoot, I first edited the search results page and changed the XSLT so that I could see the Search Results XML. The XSLT looked like:<br /><br /><?xml version="1.0" encoding="UTF-8"?><br /><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><br /><xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/><br /><xsl:template match="/"><br /><xmp><xsl:copy-of select="*"/></xmp><br /></xsl:template><br /></xsl:stylesheet><br /><br />This revealed to me 2 new elements right before the end of the </all_results> tag. The extra elements were 'totalresults' and 'numberofresults'.<br /><br />As SharePoint 2010 now uses Federated Search Locations with custom XSLT allocated to each location, I decided to look to see what the OOB 'Local Search Results' location was doing. Turns out that it now includes a couple of extra XSLT templates:<br /><br /><xsl:template match="TotalResults"><br /></xsl:template><br /><xsl:template match="NumberOfResults"><br /></xsl:template><br /><br />So I added these to extra XSLT templates into my custom XSLT and voila! No more strange number at the end of my search results.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com2tag:blogger.com,1999:blog-23320284.post-90990007981793753772011-04-20T21:44:00.002+10:002011-04-20T21:56:08.303+10:00What to do when Content Deployment failsI had to help out some guys from Accenture today with the setup of content deployment for a global SharePoint 2010 Internet site. Basically the first content deployment from the Authoring to Production environment didn't send across all of the published pages. As a result, settings like 'Welcome Page' were lost. Further content deployments did not seem to help or fix what was previously broken. As SharePoint's content deployment is incremental by default (UI) I created a full content deployment job through PowerShell, but then we started seeing the error 'Unable to import folder _catalogs/masterpage/Forms/Page Layout. There is already an object with the Id <Guid> in the database from another site collection'.<br /><br />I used my friend Google and found <a href="http://blog.qumsieh.ca/2010/07/26/content-deployment-errors-in-sharepoint-2010/">this</a>, which helped me solve the problem.<br /><br />So it seems that information about what has been deployed before is not contained within the Authoring environment, but the destination environment, and deleting the site collection and re-creating it with an empty template doesn't help. In my case I deleted the web application entirely and re-created it through script. In the article, you can also detach and re-attach the content database through Central Admin.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-5824463968992553682011-03-29T17:35:00.002+11:002011-03-29T17:43:39.144+11:00Fixing the Health Analyzer SPTraceV4 issueWithin a SharePoint farm configuration (multiple servers), the SharePoint Health Analyzer will first complain that the SPTraceV4 account should not be running as a local service. If you manually fix this by setting a domain account for the trace service (on each server) and restarting the service, sometimes you will still get the message 'Built-in accounts are used as application pool or service identities' within the Health Analyzer. To fix this, do the following:<br /><br />1) Create the Trace Account (e.g. DOMAIN\svc-SP_TRC) as a managed account.<br />2) Start up the SharePoint 2010 Management Shell in administrator mode<br />3) Type the following Powershell script:<br /><br />$servicename = "SPTraceV4"<br />$managedaccountname = "DOMAIN\svc-SP_TRC" <br />$farm = Get-SPFarm<br />$SPTimerv4 = $farm.Services | Where {$_.Name -eq $servicename}<br />$SPTimerV4NewAccount = Get-SPManagedAccount $managedaccountname<br />$SPTimerv4.ProcessIdentity.CurrentIdentityType = "SpecificUser"<br />$SPTimerv4.ProcessIdentity.ManagedAccount = $SPTimerV4NewAccount<br />$SPTimerv4.ProcessIdentity.Update()<br /><br />4) Goto to each server in the farm and restart the tracing service. Then do an IISRESET /noforce on each SharePoint Server<br />5) Open up Central Administration, view the problem report and re-analyze the built-in accounts Health Analyzer message. <br />6) Close the report message and refresh the page. The error should now be gone.<br />7) If you have moved your logs to another (e.g. non-System) drive, on the directory where logs are to be written to, ensure that the nominated domain Trace account has full read/write permissions to it. You may have to restart the trace service and do an IISRESET again to notice that activity is now being written to the LOGS directory. Note that this approach also fixes the issue where you see lots of log file entries, all 0KB in length.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-23762109300692923002010-09-23T12:15:00.002+10:002010-09-23T12:18:29.743+10:00SharePoint 2010 Branding FrustrationsThis is not a solution to anything, just a place to vent my anger. I hate it how SharePoint 2010 page layouts go against basic CSS best practices. The biggest issue for me at the moment is that the page layouts are rendered once again in nested tables and that nearly every web part zone has an ID of "_invisibleIfEmpty". Come on guys! It is not that hard!Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com1tag:blogger.com,1999:blog-23320284.post-83846371064947212532010-07-21T18:04:00.003+10:002010-07-21T18:07:50.987+10:00Search Delegate Control in SharePoint 2010Currently I am in the process of upgrading a SharePoint 2007 Internet site to 2010. One of the things that had me stuck initially was that after I did the upgrade and created a 2010 specific master page, my search delegate control was not showing up. I finally figured out that search delegate controls must have the Web Application feature scope in order to work. For my 2007 site, it was using Site Collection level scope.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-69741566789592847002010-05-24T15:05:00.002+10:002010-05-24T15:13:19.180+10:00Prerequisite install gotchas when installing with no Internet connectivityI am installing a SharePoint 2010 environment at the moment for a client where Internet access from the SharePoint box is blocked. I have found that even though I installed the compulsory prereq components, unless you install all of the prereqs, the prerequisite install function fails (e.g even though the speech components are optional, the prereq installer will fail if it doesn’t find them already installed). A bigger issue is that Microsoft currently has 3 versions of the prerequisite item 'SQL 2008 R2 Analysis Services ADOMD.NET' available, where only the one at <a href="http://go.microrosft.com/fwlink/?LinkID=160390" target="_blank">http://go.microrosft.com/fwlink/?LinkID=160390</a> will work because of the registry settings it makes (which the prereq installer looks for). The correct version of SQLSERVER2008_ASADOMD10.msi is 6924KB. The versions <strong>that don’t work</strong> are <a href="http://go.microsoft.com/fwlink/?LinkID=188442&clcid=0x409" target="_blank">http://go.microsoft.com/fwlink/?LinkID=188442&clcid=0x409</a> (SQL 2008 R2, which is 7099KB) or <a href="http://go.microsoft.com/fwlink/?LinkId=130651" target="_blank">http://go.microsoft.com/fwlink/?LinkId=130651</a> (SQL 2008, which is 4416KB).Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-46342744183512493702009-05-28T15:43:00.002+10:002009-05-28T15:53:32.076+10:00Performing Long Running Tasks in SharePointOccasionally you may have a custom action that takes a while to run. On one of my recent projects we had just this need. Basically we wanted to convert an ordinary out of the box document library into a 'Projects' Document library. This involved setting the properties of the library (e.g. versioning, content types, enforce checkout etc), adding new content types to the library, setting up workflows for the library and applying event handlers.<br />The way that we did this was to create an Application page (under layouts), which got called by the custom action. Within the OnLoad of this page, we had the following:<br /><br /> using (SPLongOperation operation = new SPLongOperation(this.Page))<br /> {<br /> try<br /> {<br /> operation.LeadingHTML = "Convert to Project Documents library";<br /> operation.TrailingHTML = "Please wait while your document library is being prepared for project use.";<br /> operation.Begin();<br /><br /> // your code goes here<br /><br /> operation.End(string.Format("{0}&ConversionStatus={1}", this.CurrentRequestUrlAndQuery, FormSubmitStatus.Success.ToString()));<br /> }<br /> catch (Exception ex)<br /> {<br /> // record the error<br /> operation.End(string.Format("{0}&ConversionStatus={1}", this.CurrentRequestUrlAndQuery, FormSubmitStatus.Fail.ToString()));<br /> }<br /> }<br /><br />How easy is that? SharePoint Rocks!Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-60422677149603112792009-05-28T14:10:00.000+10:002009-05-28T14:50:57.210+10:00Creating SharePoint Timer JobsIn my current project, I have been developing a bunch of functionality around project space provisioning. As part of this, I decided that as there were a lot of activities to be performed when creating and configuring the new site, developing a SharePoint Timer Job was the best option.<br /><br />So lesson learnt #1 - You can't programmatically create a timer job from a site collection feature. The reason for this is that typically the application pool that looks after the site does not have permission to write to the configuration database. Creating a Timer Job requires you to be able to write the timer job definition into the configuration database, so if your application pool doesn't have the rights, then the creation of the job will fail.<br /><br />So basically you have to create a Web Application level feature (i.e. activated through Application Management tab of Central Admin) with a feature receiver method that creates the timer job. E.g.<br /><br /><?xml version="1.0" encoding="utf-8"?><br /><Feature Id="2DEA0BA9-A8D1-4475-AD0B-8FE25EBF65A2"<br />Title="Project Spaces Provisioning Timer Job"<br />Description="Add timer job required for project space provisioning."<br />Version="12.0.0.0"<br />Hidden="FALSE"<br />Scope="WebApplication"<br />DefaultResourceFile="core"<br />ReceiverAssembly="Collaboration.Projects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d76123a549458435"<br />ReceiverClass="Collaboration.Projects.FeatureCode.ProjectProvisioningTimerJob"<br />xmlns="http://schemas.microsoft.com/sharepoint/"><br /><elementmanifests><br /></feature><br /><br />Creating the timer job in code is actually quite simple. Below is the feature activation/deactivation code:<br /><br />using Microsoft.SharePoint;<br />using Microsoft.SharePoint.Administration;<br />using Collaboration.Projects.Provisioning;<br />namespace Collaboration.Projects.FeatureCode<br />{<br /> /// <summary><br /> /// Creates the timer job that runs the site creation process for confirmed requests in the provisioning request list<br /> /// </summary><br /> public class CollabProjectProvisioningTimerJob : SPFeatureReceiver<br /> {<br /> public override void FeatureActivated(SPFeatureReceiverProperties properties)<br /> {<br /> SPWebApplication application = properties.Feature.Parent as SPWebApplication;<br /> DeleteProvisioningJob(application);<br /> // install the job<br /> ProjectSpaceCreationTimerJob provisioningJob = new ProjectSpaceCreationTimerJob(application);<br /> SPMinuteSchedule schedule = new SPMinuteSchedule() { BeginSecond = 0, EndSecond = 59, Interval = 30 };<br /> provisioningJob.Schedule = schedule;<br /> provisioningJob.Update();<br /> }<br /> public override void FeatureDeactivating(SPFeatureReceiverProperties properties)<br /> {<br /> DeleteProvisioningJob(properties.Feature.Parent as SPWebApplication);<br /> }<br /> public override void FeatureInstalled(SPFeatureReceiverProperties properties)<br /> {<br /> }<br /> public override void FeatureUninstalling(SPFeatureReceiverProperties properties)<br /> {<br /> }<br /> /// <summary><br /> /// Deletes the provisioning job if it exists<br /> /// </summary><br /> /// <param name="application"></param><br /> private void DeleteProvisioningJob(SPWebApplication application)<br /> {<br /> foreach (SPJobDefinition job in application.JobDefinitions)<br /> {<br /> if (job.Name == ProjectSpaceConstants.ProvisioningJobName)<br /> job.Delete();<br /> }<br /> }<br /> }<br /> }<br /><br /><br />Now the ProjectSpaceCreationTimerJob class just inherits from SPJobDefinition. Below is a code snippet (note that the Execute method is the actually code that gets executed when the job runs).<br /><br />using System;<br />using System.Net;<br />using System.Web;<br />using Microsoft.SharePoint;<br />using Microsoft.SharePoint.Administration;<br />using Collaboration.Projects.Resources;<br />using Collaboration.Provisioning;<br />using Collaboration.Common;<br />using System.Text;<br /><br />namespace Collaboration.Projects.Provisioning<br />{<br /> public class ProjectSpaceCreationTimerJob : SPJobDefinition<br /> {<br /> public ProjectSpaceCreationTimerJob() : base() { }<br /> public ProjectSpaceCreationTimerJob(SPWebApplication web)<br />: base(ProjectSpaceConstants.ProvisioningJobName, web, null, SPJobLockType.Job)<br /> {<br /> this.Title = ProjectSpaceConstants.ProvisioningJobName;<br /> }<br /><br /> public override void Execute(Guid targetInstanceId)<br /> {<br /> // your code goes here<br /> base.Execute(targetInstanceId);<br /> }<br /> }<br />}<br /><br />Hope this helps. I've written it down here so that I remember it in the future.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com1tag:blogger.com,1999:blog-23320284.post-61433443411215127082008-11-06T10:41:00.000+11:002008-11-06T10:50:24.044+11:00Access is denied. Check that the Default Content Access Account has access to this content.I had the following error on an Extranet site that I setup recently:<br />The start address <<a href="https://abc.def.com/">https://abc.def.com</a>> cannot be crawled.<br />Access is denied. Check that the Default Content Access Account has access to this content, or add a crawl rule to crawl this content. (0x80041205).<br /><br />I had read on other blogs that the trick was to login to the Index Server as the MOSS Search account, check that you can access the site, and verify the proxy/exclusions had been setup correctly. This normally works, but it didn't for me this time. And it certainly wasn't permissions as the search account had full read access to the site through the Application Policy interface within Central Admin.<br /><br />In the end, I found that a registry change and a reboot of the server was required to fix it. See <a href="http://support.microsoft.com/kb/896861">http://support.microsoft.com/kb/896861</a>. I used Method 1 (Disable loopback check) to fix the problem. That is:<br /><br />1. Click Start, click Run, type regedit, and then click OK.<br />2. In Registry Editor, locate and then click the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa<br />3. Right-click Lsa, point to New, and then click DWORD Value.<br />4. Type DisableLoopbackCheck, and then press ENTER.<br />5. Right-click DisableLoopbackCheck, and then click Modify.<br />6. In the Value data box, type 1, and then click OK.<br />7. Quit Registry Editor, and then restart your computer.<br /><br />I hope this helps. It frustrated the living daylights out of me at the time.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-60304134296357885982008-04-28T10:12:00.000+10:002008-04-28T10:17:54.051+10:00Fixing the Search Settings Forbidden (403) ErrorLast week I installed hotfix 941653 and hotfix 950292 (post SP1) to a client site to fix the dreaded Error: 'length' is null or not an object that occurs with Office 2003 Standard edition and MOSS Content Types. Unfortunately, not only did the problem remain (i.e. the hotfix fixed nothing), but I started to get 403 (Forbidden) errors when I tried to navigate to Search Settings page. <br />To fix this problem, I had to do the following:<br /><strong>From the index server</strong> (I've got a front-end web server and a backend index server, both 64 bit):<br /><strong>stsadm -o search -action stop -f<br /></strong>then I did<br /><strong>stsadm -o search -action start -role indexquery<br /></strong>then I did a:<br /><strong>stsadm -o execadmsvcjobs<br /></strong>Then I went back to the <strong>front end web server</strong>, navigated to the Shared Services Admin page, selected the SSP site, then from its context menu selected 'Edit Properties'. Then from the screen I reselected what the Index server was. After this, on the front end server I did a <strong>stsadm -o execadmsvcjobs</strong>. Then search started working again (but as the index was blown away, I had to do a full reindex).Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com1tag:blogger.com,1999:blog-23320284.post-62905737760523469882008-04-04T10:36:00.000+11:002008-04-04T11:05:59.221+11:00Fiddler2 and Pipeboost are your friend!To my surprise this week, one of the sites that I am helping with went live (deployed by the customer). One of the comments from the customer was 'it is quite slow'. Well to help identify what was going on, I brought out my trusty friends - Fiddler2 and Pipeboost. <br /><br /><span style="font-size:130%;color:#3366ff;"><strong>Fiddler2<br /></strong></span>Basically, Fiddler is an IE add-on that monitors what comes down the wire to the browser whenever you request a page. In includes all the details about what types of files are downloaded (jpg, swf, css, js etc) and how long it takes. It even provides a pie chart to show what file types are causing the biggest payload. My first test on the site was with all of my cache cleared (so that I measure the performance of the first time visitor to the site). Yes it was definitely slow. My second request was done without clearing the cache. In this report however, it showed that although the flash files were being cached, All of the images stored in the SiteCollectionImages library were not. <br /><br />So Fiddler helped me to identify that the BlobCache had not been configured on the server. This is a setting in the Web.Config file. It helps IIS to store images that are stored in SharePoint (and therefore in the backend database) to the local file system. Thus making subsequent requests for those resources a whole lot quicker (because a SharePoint database request is not required). The syntax for BlobCache is as follows:<br /><br /><blobcache location="C:\blobCache" path="\.(gifjpgpngcssjsswf)$" max enabled="true" style="font-size:10;"><br /><span style="font-size:130%;color:#3366ff;"><strong>Pipeboost (</strong></span><a href="http://www.pipeboost.com/"><span style="font-size:130%;color:#3366ff;"><strong>www.pipeboost.com</strong></span></a><strong><span style="color:#3366ff;"><span style="font-size:130%;">)</span><br /></span></strong>Pipeboost helped me to identify whether or not IIS Compression had been configured on the production server. As most of you would know, browsers such as IE can handle compression. There is a handshake that goes on between the server and the browser to see whether the browser supports compression. If it does, then IIS compresses the contents (thus reducing the payload) and sends it to the browser, where it is decompressed and displayed to the user. There are two types of content that can be compressed - Static (like images) and Dynamic (like ASPX pages). Static compressioncan compress the file as well as stores it in the Temporary Internet Files directory, so that it can be served up quicker next time. Dynamic waits for the ASPX to return its content, then it just sends that page compressed back to the browser (i.e. it doesn't store it in the Temporary Internet Files location).<br /><br />There is a great article at <a href="http://www.dotnetjunkies.com/Article/16267D49-4C6E-4063-AB12-853761D31E66.dcik" target="_blank">http://www.dotnetjunkies.com/Article/16267D49-4C6E-4063-AB12-853761D31E66.dcik</a> that explains how to setup IIS Compression. At the end of this article, it talks about Pipeboost, which can tell you whether or not the payload returned from the web server is compressed (i.e. via IIS Compression).Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com1tag:blogger.com,1999:blog-23320284.post-70348000033866569502008-04-04T10:18:00.000+11:002008-04-04T10:30:54.242+11:00Strange Behaviour when Editing a SharePoint Search Resuls PageAs part of the the work that I do with my own company (MS-Advantage), I get to work on a lot of interesting projects, as well as work with a lot of interesting partner/development companies.<br />For example, currently I am doing some work on the side with a Graphic Design company who have been charged with developing the branding for a global web site. I basically provide them with guidance on how to best use and develop with SharePoint, while they do the leg work of developing the master pages and page layouts.<br /><br />While I was working on the project yesterday, the customer indicated that the Search results page was returning sites and list information that they did not want to appear. To resolve the issue, I went into the search results page, edited the core results web part to add an additional query to the results (Query2 and isdocument:1, which basically says 'only show pages or documents'). <br /><br />Well I checked in a draft version of the search results page and started to test that it worked. As the results returned was exactly what I was after, I then published the page (so that it would get picked up in that night's content deployment job). After publishing the page however, every time I navigated to the search results page (even without providing a search keyword), the search results that I had previously used while testing were still being displayed. I tried to roll back to previous versions, but that didn't help. In the end I had to open up the page in SharePoint Designer, AND TO MY HORROR SharePoint had injected the results HTML into my web page. Once I deleted this and saved it, I was then able to re-publish the page.Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0tag:blogger.com,1999:blog-23320284.post-49267454647133710872008-04-04T10:10:00.000+11:002008-04-04T10:17:03.670+11:00SharePoint Deployment Guide and ChecklistWhile I was at the SharePoint Conference in Seattle, I attended a session on 10 Steps to Governance (presented by Brian Cook and Joel Olesen). Just before the session started, Microsoft were handing out a little pocket guide called the SharePoint Deployment Guide and Checklist. It contained lots of useful information about governance plans, deployment checklists and deployment team roles.<br /><br />When I showed it to a few guys I work with, they thought 'hey, where can I get a copy'. Well, I found it online at <a href="http://office.microsoft.com/download/afile.aspx?AssetID=AM102552101033">http://office.microsoft.com/download/afile.aspx?AssetID=AM102552101033</a>.<br /><br />So enjoy!Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com2tag:blogger.com,1999:blog-23320284.post-67999235042074417032008-03-09T21:00:00.000+11:002008-03-11T15:02:48.786+11:00SharePoint Conference catchup with Heather SolomonWhile I was at the SharePoint Conference in Seattle, I caught up with Heather Solomon (SharePoint branding MVP) from SharePointExperts.com.<br /><p align="center"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzMxIBWnXa_PLZiTnVC5LziX6rqYNAGcXzH8P_jtzdRQZoAuo33ES8ovCTFYyMx0MeQI5tQpa0MDj7ZO2wqL3-r7wgN6l2CduQGwCdbnfsHCEKi_pDJjTPRuNJFV3E-pSWKRdkDA/s1600-h/heathersolomon.jpg"><img id="BLOGGER_PHOTO_ID_5175681952541688978" style="CURSOR: hand" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzMxIBWnXa_PLZiTnVC5LziX6rqYNAGcXzH8P_jtzdRQZoAuo33ES8ovCTFYyMx0MeQI5tQpa0MDj7ZO2wqL3-r7wgN6l2CduQGwCdbnfsHCEKi_pDJjTPRuNJFV3E-pSWKRdkDA/s320/heathersolomon.jpg" border="0" /></a></p>Below are some of the tips and tricks that we discussed (and some of my own tips):<br /><ol><li>Explore using CSS to customize the OOTB navigation controls before you go out venturing on creating your own.</li><li>Incorporate the @import to include your CSS in your Master Pages. Heather's opinion is that you should only use the alternate CSS option to tweak particular areas.</li><li>Store your CSS and branding images on the web server. Images go in their own directory under 'Template\Images'. The CSS file should be stored inside a directory under 'Styles' (under the 12 hive).</li><li>Package your branding in Solution Package/Feature. Check out<br /><a href="http://codeplex.com/stsdev">http://codeplex.com/stsdev</a> for a Visual Studio Project Template for this (developed by Ted Patterson and Andrew Connel)</li><li>On the development machine, turn off custom errors in the web.config (<br />set Callstack = False. Set CustomErrors=Off)</li><li>Apart from using Alternate Stylesheets, Themes can also be used to help brand the Application.master template (remember you can't actually change the HTML structure though)</li><li>Meeting Workspaces do not pick up your custom master page. There is some special code in the meeting workspace master page that renders the multiple meeting navigation that you normally see on the left hand side. You need to create a separate masterpage for the meeting workspace, then create a feature stapling to the meeting workspace to change its default master page.</li><li>Blogs and Wikis use different styles, so be careful</li><li>Take advantage of contextual selectors (e.g. div#mydiv ms-SPLink {...} )</li><li>The word specificity (which I can never pronounce in meetings) basically means that a number is derived from the way in which an element is styled. Sometimes you see styles overriding others when you see things like class names sitting right next to the element. Think of the number as A-B-C. For each ID that you use, you add 1 to A. For every class you use, you add 1 to B. Then for a base class definintion, you add 1 to C. So p#largetext ul.mylist li has a specificity of 1-1-1 (or 111). If I just set a style on li (corresponding to a specificity of 1), the specificity with the highest number would be applied to the element.</li><li>Don't go crazy with classes. Use IDs more often and classes sparingly. That way in your CSS, you can use contextual selectors to define a style. E.g. div#mydiv table tr td a { font-family: Verdana }. In this example I haven't used classes at all. I am basically finding the element by starting at the ID level first.</li><li>Heather mentioned that in the past, she has seen SharePoint Designer take grouped styles (e.g. h1, h2, h3 ....) and separate them to h1 {} h2 {} etc (so adding more lines than what is necessary). Heather uses 'Top Style Pro 3.5' to author her CSS, but she hasn't tested opening up a CSS stored in the 'Style Library' areas (remember that she prefers to have the CSS stored on the web server).</li></ol>Alan Coulterhttp://www.blogger.com/profile/08776140590565586512noreply@blogger.com0