Showing posts with label SharePoint 2010. Show all posts
Showing posts with label SharePoint 2010. Show all posts

Thursday, August 13, 2015

Sync Excel Tables to a SharePoint List

Update: This doesn't work anymore with the release of Excel 2016. All previous versions of Excel still support it.

I have this requirement as part of a large process automation project for an international company operating in construction. OK, well the requirements never come in that clear - "sync" is not used. The goal is to have a SharePoint 2013 list, populated with data from an Excel 2007 spreadsheet.

Then part of the data would be picked up by a workflow and some of the data will be edited with human interaction during the process. At the end, the data should be in a compatible format to use with a reporting system such as SSRS or PowerPivot for SharePoint Server. That's another topic.

There are several approaches that we can take to achieve the first and most important goal - get the spreadsheet data into a SharePoint list. While the data can be easily exported from Excel (2013) to a SharePoint list quite quickly, there's no way to update it through Excel afterwards. It's a one-off solution which won't add value to this project at all.

I'll just show how that simple option works in Excel 2013 (it works in previous versions, too).

Before starting anything, please have in mind that you can only get the data into a SharePoint list if it's formatted as a table, that won't work for just about any spreadsheet. But we'll start with "any spreadsheet" :) In our scenario, we have a group of employees that might be new hires and we need to get them in a list, so we can possibly start a workflow that will do all the things associated with the new hires - e.g. assign them a telephone number, create an account in Active Directory, etc. The workflow is another topic which we won't discuss, but the main point is that's a common scenario.
Organizations usually transition from paper-based process through Excel spreadsheets to an automated software solution at the end.

Today we are lucky to have 7 new hires across different departments. We got this nice little spreadsheet from HR and we want to create a pilot list called "Employees" in our brand new SharePoint Online environment. It will work in the same way if the environment was SharePoint Server 2013 on-premise anyway.

First we'd format this as a table, in order to be able to even get to the "Export" button:


We now have the Export button, under the "Table Tools" section on the ribbon and we can choose the "Export Section to SharePoint List" option. 


You get prompted for the URL of the SharePoint site and the name of the list that would be created for the table data:


A summary of the fields that will get imported. 


Nice to know is that only one the following types will be assigned to the columns in SharePoint:

  • Text (single line)
  • Text (multiple lines)
  • Currency
  • Date/time
  • Number
  • Hyperlink


If a column has cells with different data types, Excel applies a data type that can be used for all of the cells in the column. For example, if a column contains numbers and text, the data type in the SharePoint list will be text.

Here are the results when that sync finishes. A nice little message in Excel:


A newly created list in our target SharePoint site:

Our employees are ready to jump into the complex workflow process to follow :) More on that will follow in one of the next posts likely if/when we get this project rolling out live. Now it's only a PoC.


More on this basic one-way sync can be found on this Excel 2007 Support article


Now let's talk about the second solution... which will enable us to store the Excel data... and sync it from Excel anytime at a later stage. Out of the box that's not available in Excel or SharePoint.
But there's a good add-in for Excel 2007 (great as our customer is on Excel 2007, and I've found it working well on Excel 2013, too). The add-in was available for Excel 2007 and later on deprecated.
You can still find it here and use it (for free of course) if it matches your organization's needs.

When you download and extract this, you simply get a macro-enabled Excel 2007 workbook called SynchronizeWSSandExcel.xlam. Start that one and enable macros. Then get your table in. Don't forget to format it as a table, as in the previous approach, the same requirement is valid here.

Then go to the Design tab under Table Tools and you'll find a brand new button - "Publish and allow Sync":
When you click it, the dialog box looks similar to the previous one, but it's a 1-step process this time. Doesn't get any sweeter than this (I'll just call my list New Hires as the Employees is already taken):


The outcome is the same as solution 1:



But we now have the ability to change the data... let's say Jack D needs to move from the IT department to Developers, we can change that and then synchronize the changes to the SharePoint list from Excel without the need to even open SharePoint. You just change the cell data, use the "Synchronize with SharePoint" option and your list will be updated.








In one of the next blog posts I'll talk about a couple of other approaches.. which are in fact the a lot more sophisticated and, but involve a significant cost that involves the need of SharePoint Server Enterprise Edition and a 3rd party workflow product or some custom coding to call the Excel Web Services.









Tuesday, August 4, 2015

Issues when requesting the Search Results page with no query in SharePoint 2010

After some vacation time in July I'm back to share some of the experiences with SharePoint, this time from the backlog I have for posting here. Although SharePoint 2010 mainstream support will expire soon (Oct 13, 2015) there are still a number of customers using it.

For one of our clients, we've had to design a custom big shiny button that leads to their Search Center (read: Results page) but without the need for users to type in any query before hitting the button. Something similar to this, in the middle of a Publishing page where we've removed the default Search Box webpart on the client's request.



That's a quick and easy thing, if we don't count the numerous design iterations that we've done of course. Once implemented in the test environment though, we have faced some issues.

Whenever you try to search for a keyword, nothing happens. Your Search Query box is reset to empty. So you try again... and again. This was a very intermittent behavior, after some time... it will eventually work. It was also working always for admin accounts. The ULS logs would show:

System.Runtime.InteropServices.COMException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.    at Microsoft.SharePoint.Library.SPRequestInternalClass.ValidateFormDigest(String bstrUrl, String bstrListName)     at Microsoft.SharePoint.Library.SPRequest.ValidateFormDigest(String bstrUrl, String bstrListName) 7ee02ec8-2297-4816-b3c8-b31f0150d81d

Initially one would think to disable the Web Page Security Validation on the web application... which is totally not a good idea and brings more issues when trying to save site as templates, etc.

After a lot of digging, I've found no way of fixing this, so we've changed the behaviour of the Search button to not go to the results page directly with no query, but instead require the user to input a query before that. 

Now that works fine and everyone's happy. Not sure if this is by design, but out of the box Search Webparts would require you to type your query before you can go to the results, so it might be.

Friday, June 19, 2015

The Query String (URL) Filter Connections

That is a quite useful webpart... as MVP Laura Rogers  blogged in a series of posts a while ago.
I'll just mention what happens when you try to move it over, as it simply doesn't work as you'd expect it to work.

Today I've tried to bring accross a Team Site from SharePoint 2013 On-premise to SharePoint Online by using ShareGate Migration. *Almost* everything went well and I decided to do some sanity checks on basic functionalities of the site.

The one thing that's heavily used is a Client List solution that is implemented in the following way:

Page A: A web part page, containing a number of List View webparts, each of them containing different pieces of information related to specific clients, let's say client documents and key contacts.

Client Documents and Key Contacts, for example are separate lists, each of which has an identical column, called "Client" of type "Choice" Each item in those lists is associated with one client only.

Page B: A page with only one list view webpart, visualizing a list called "Clients", with a search box and some groupings which are collapsed so that the whole list of clients is not displayed by default.

The "Clients" lits has a column called "Link", of type guess what (Yes, Hyperlink or Picture of course) which supposed to take you to information for *only* that client on Page A by filtering all webparts on Page A, based on their "Client" column's value - it should be matching the value inserted in "Link". That is achieved through the Query String (URL) Filter webpart.

The format of the link is:  http://intranet/sites/teamA/clientlist.aspx?Client=NameofTheClient.

When this is clicked (that's what people do when they find the needed result), they're taken to Page A (clientlist.aspx) and view all info related to the client, with all other clients' data filtered out. Great, isn't it?

So, that was working well on the SharePoint 2013 on-prem, but not in Office 365 as I've tested it now post-migration.

The Query String (URL) Filter webpart is inserted on Page A. It's only visible in Edit Mode and it was visible on the page when I went to edit it. But the functionality that we used to have on premise was not working, when clicking on the "Link" column on Page B, I was taken to Page A, but totally unfiltered and seeing a bunch of data for a number of clients - not what I needed in order to find something quick. And the reason struck me immediately:



It seems the webpart connections are not brought over! I've tried exporting the webpart and importing it manually - still the same thing. The only thing that came over is the "source" of the filter parameter. Let's imagine that one was gone too, so we'd start nice and clean by readding our webpart:

Go to "Add Web Part" and locate the Query String (URL) Filter under the Filters category:

That's how the vanilla version looks like:

Open the tool pane to configure it and choose a meaningful name of your choice for the filter and the parameter that you'll be passing in the query (in our case Client):

Now we've got to add the connections. In our case those are 10+ lists but for the example, let's say we'd just need to apply the value to the Client Documents list:


On the next screen, choose "Get Filter Values From" and press the "Configure" button:


Choose the target list column that you'd like to use for filtering:


Done. The webpart will now show you the connection(s) rather than the annoying "Unconnected" warning:


Hope that was useful for you if you're tasked with migrating some solutions based on these webparts in your daily work. The interesting outstanding question is where are these connections stored when they're not coming over with the webpart itself? I'll be glad if someone posts a comment with an answer on that mistery.













Thursday, May 7, 2015

Cannot Edit Content Query Webpart

One of our clients who use SharePoint 2010 as a publishing solution (Internet) had an issue where they suddenly couldn't edit a content query webpart on a publishing page. The webpart can be added and displayed correctly, but not edited. It's slightly customized, containing a predefined query that's grabbing items from a list. Trying with a vanilla CQWP didn't make any difference though. Creating a new page and trying the same still did not succeed.

Whenever they tried to edit the webpart, they'd get Unexpected Error.


Looking at the ULS logs, I stumbled upon this:

System.Xml.XmlException: Reference to undeclared entity 'nbsp'. Line 1027, position 40.   
 at System.Xml.XmlTextReaderImpl.Throw(Exception e)    
 at System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(String name, Boolean isInAttributeValue, Boolean pushFakeEntityIfNullResolver, Int32 entityStartLinePos)    
 at System.Xml.XmlTextReaderImpl.ResolveEntity()    
 at System.Xml.XmlLoader.LoadEntityReferenceNode(Boolean direct)    
 at System.Xml.XmlLoader.LoadNode(Boolean skipOverWhitespace)    
 at System.Xml.XmlLoader.LoadDocSequence(XmlDocument parentDoc)    
 at System.Xml.XmlDocument.Load(XmlReader reader)    
 at System.Xml.XmlDocument.LoadXml(String xml)    
 at Microsoft.SharePoint.Publishing.WebControls.CmsDataFormWebPart.GetXslFile(String templateFileUrl)    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart.createItemStyleList()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart.get_ItemStyleList()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart.createAllSlotNames()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryWebPart.get_AllSlotNames()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.createFieldsToDisplayControlGroup()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.createConfigureLayoutSectionControls()    
 at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.CreateChildControls()    
 at System.Web.UI.Control.EnsureChildControls()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Control.PreRenderRecursiveInternal()    
 at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

So it seems somebody tried to insert an interval somewhere along the customizations. Looking further into the error, it seems it comes from the ItemStyle stylesheet. I grabbed it from the farm and saw there was   at one location. By default, the   would not be rendered when inserted in the XSL.

There are three quick ways to overcome this.

1. Change   to &#160

2. Change &nbsp to <![CDATA[&nbsp;]]>

3. Insert this in the XSLT file:

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>

We chose solution 1 and it works like a charm. Content Query webparts can now be edited,.

Friday, March 27, 2015

Deleted User Profile - How to Relink MySite (SharePoint 2010)

I've had a very interesting case on a SharePoint 2010 environment. A user's account was deleted accidentally by their internal AD team on Friday the 13th :) The account got recreated, but when the user tried to open MySite, they got "Access Denied" when clicking on "Contents".

I've made sure the user is the Site Collection Admin, checked every possible permission level and even re-added it just in case. No luck.

With the Farm Admin account, I was able to see the Contents of this user at all times.

I've come up with the following approach after a few hours of IIS / ULS logs reading that were simply showing 401 when this particular user tried to access their own MySite.

- Deleted the MySite (ensured we've got a fresh backup).
- The user then recreated a blank MySite.
- I've restored the backup with the Restore-SPSite command.

At this stage, I was able to see the contents with the Farm Admin account again, but when the user tried, he got the following error:

The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.

And the respective ULS log entry:

The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.
 at Microsoft.SharePoint.SPGlobal.HandleThrottleException(COMException comEx)    
 at Microsoft.SharePoint.Library.SPRequest.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)    
 at Microsoft.SharePoint.SPWeb.GetSiteData(SPSiteDataQuery query)    
 at Microsoft.SharePoint.WebPartPages.AggregationWebPart.RunQuery(SPSiteDataQuery query)    
 at Microsoft.SharePoint.WebPartPages.UserDocsWebPart.GetEligibleItems()    
 at Microsoft.SharePoint.WebPartPages.AggregationWebPart.RenderWebPart(HtmlTextWriter writer) Inner Exception: The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.  
 at Microsoft.SharePoint.Library.SPRequestInternalClass.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)    
 at Microsoft.SharePoint.Library.SPRequest.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)

Now... the list view treshold was set to 5000 for non-admins (default) and 20 000 for admins (again default). I've lifted it to 20 000 for non-admin users as well, just to find out it doesn't matter. No luck.

I've even decided to make the user a Farm Admin for a minute... again nothing changes.
Whenever he tried to access any of the libraries in "My Site", Unexpected error. The webpart "SharePoint Documents" still saying the stupid message about the List View Tresohld.

Maybe I should have mentioned that there are nowhere near 5000 items in that user's MySite in total.

So... next steps.

- Deleted the User Profile from SharePoint.
- Issued an Incremental Sync to import it - it didn't import.
- Issued a Full Sync - not imported again.
- Recreated the User Profile in SharePoint manually with all the properties

And still at the same stage...

Finally... I've decided to use the Export/Import instead of Backup and Restore and I did not use the -IncludeUserSecurity on purpose... as I am thinking that the old account is still referred to somewhere in the site permissions and that's causing all the headaches. Boom! All working fine now after the Import.

The only downside would be that the "SharePoint Documents" webpart which is the default one visible when you go to "Contents" under MySite will be showing no documents... as when I've used the Export method with the Farm Admin account now all documents show as modified by this account. Anyway once the user edits (or just check-out / check-in) a few documents, this webpart populates again and there's finally nothing more to worry about. Just be careful when deleting AD accounts :)

Friday, February 27, 2015

"Object doesn't support property or method 'addEventListener'"

I've just been advised about an issue by two of our customers who are using a form that we've developed in InfoPath and deployed as a solution almost a year ago. It was all working smoothly.

What they're both getting today when trying to fill-out the form is:



I've tested on my dev environment and I could not reproduce the issue with Chrome or IE10 although I have the same version of the solution.

It turned out both customers have upgraded to IE11 and the issue did not exist in Chrome for them.

Both customers are still on SharePoint 2010, so I was eager to turn on the Compatibility View on IE11 and boom, it worked.

A quick research led me to this post and I was very surprised that it also applies to SharePoint 2013. Adding the site URL to the Compatibility  View is a quick and easy workaround, but that really shouldn't be the default behaviour, Microsoft. That breaks a lot of other things, for instance if you're using HTML5 on that site (which is very common nowadays), that would not work and it's a big trade-off. Hopefully that gets addressed within a hotfix anytime soon.

Thursday, February 5, 2015

Nintex Workflow calling a web service fails because of SSL Trust

We're using a Nintex Workflow for sending some email notificatoins for a SharePoint 2010 customer.
The workflow has a "Call web service" action which is calling the top level Nintex Web Service at https://rootsitecollection/_vti_bin/NintexWorkflow/Workflow.asmx. Suddenly this has stopped working. The error we see logged when checking the workflow history is that one:


The SSL certificate is valid and has not expired, however we've just recently renewed it.
It's a DigiCert SSL certificate whcih is imported properly and assigned in IIS as it should be.
Now, for some reason it seems it's not trusted by the Nintex Workflow, but what's really happening backstage is that the SharePoint farm is not trusting that one, as it only trusts its local Root certificate by default. I saw the previous Root certificate of the SSL that we've renewed  was added in the Trust manually, however the root CA has changed (the vendor has done that on purpose after one of the SSL bugs discovered recently I believe)  so I've decided to add the new Root CA to the trusted root authorities of the farm:

foreach ($cert in (Get-ChildItem cert:\LocalMachine\Root))
{
    if (!$cert.HasPrivateKey)
    {
        New-SPTrustedRootAuthority -Name $cert.Thumbprint -Certificate $cert
    }
}

That worked. If you don't want to run the whole workflow, you can just get to the action that calls the Web Service and run it (the workflow has to be in Edit mode), good practice is to export it first.

Tuesday, February 3, 2015

Content Type Publishing missing

I've been creating and publishing content types for a small reorganization project on a SharePoint 2010 Intranet. What I found in only one of the site collections, my newly created content type was not available even after publishing it and manually running the relevant timer jobs: Content Type Hub and Content Type Subscriber. I also found the Content Type Publishing from the Site Collection Administration section is missing!

This site was created using the Blank Site template (#STS1). All others were using the Team site and they were able to benefit from the publishing of content types without any issues.
The blank site template, for some reason is lacking one feature -  TaxonomyFeatureStapler.

Now I thought can I afford the luxury to recreate the whole site just because of that? Absolutely not... so I looked around for ways to workaround this:


stsadm -o activatefeature -id 73EF14B1-13A9-416b-A9B5-ECECA2B0604C -url http://toplevelsiteurl

That worked great.

There's also another solution, described in Bill Crider's blog here, but I haven't tested it.

Wednesday, January 7, 2015

Nintex Analytics causing massive load on SQL

Nintex Analytics is a 3rd party product running on SharePoint (installed as a solution) which is used by some of our customers that are still on SharePoint 2010.I won't go into details about the product, Joel Oleson already did a great review on it a while ago. Nintex are not developing this anymore and the support will be retired on 1st July, 2015, so I've decided to share one of my very few real-world experience cases with it. Meanwhile, there is an alternative product for SharePoint 2013 - HarePoint Analytics for the people that used and loved Nintex Analytics.

The environment:

  • SharePoint 2010 Standard - 1 APP, 1 WFE
  • Nintex Workflow running on both servers
  • Nintex Analytics running on the APP server

...All sharing the same SQL box... which was running fine for 3 years.

One wonderful day we started getting complaints from users that their Intranet is running slow, server graphs showed 100 % CPU on the SQL box since a couple of minutes. That trend has continued and the only process eating it was the one for the SQL Server itself.

I ran a report of the most CPU-expensive queries on the server and found the following:

SELECT @WebCount = COUNT_BIG(DISTINCT w.ObjectId)
 FROM dbo.DimSPObjectsSites o with (readuncommitted)
  INNER JOIN (SELECT DISTINCT ObjectId, ObjectTypeId, EventTypeId FROM dbo.FactAuditData with (readuncommitted) WHERE IntervalId >= @IntervalStart AND IntervalId < @IntervalEnd) f          
   ON  f.ObjectId = o.ObjectId
   AND f.ObjectTypeId = o.ObjectTypeId
   AND f.EventTypeId = 3
  INNER JOIN dbo.DimSPWebs w with (readuncommitted)
   ON w.ObjectId = o.SPWebId
   AND w.WebTemplate = @WebTemplate




That query is making use of the following 3 database indexes:


dbo.FactAuditData.IX_FactAuditData
dbo.DimSPObjectsSites.IX_DimSPObjectsSites
dbo.DimSPWebs.IX_DimSPWebs_WebTemplate


...which are all in the Nintex Analytics Content Databases... so I've started stopping the Nintex Analytics Services that are basically Windows services running on the SharePoint server one by one.. after stopping the Nintex Analytics Data Management Service... the CPU time dropped immediately to the recent levels we've been observing.




I've tried a few other bits and pieces like reconfiguring the reports in terms of data to retain, purging intervals and so on but every time I started the Data Management Service, in a minute the SQL Server was getting hammered (100 % CPU).

I've raised this with the Nintex Support and they've sent me the following SQL query to create a stored procedure:

CREATE PROCEDURE [dbo].[CfgIndexInformation]
AS
BEGIN
SET NOCOUNT ON
DECLARE @indexCounter int,
@maxIndexes int,
@partitioncount bigint,
@schemaname sysname,
@objectname sysname,
@indexname sysname,
@objectid int,
@indexid int,
@partitionnum bigint,
@frag float,
@partitions bigint

DECLARE @work TABLE
(
indexNumber int identity(1,1),
objectId int,
indexId int,
partitionNum bigint,
fragmentation float
)

DECLARE @tables TABLE
(
tableName sysname,
indexName sysname,
fragmentation float
)

INSERT @work (objectId, indexId, partitionNum, fragmentation)
SELECT s.object_id,
s.index_id,
s.partition_number,
s.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') s
WHERE s.avg_fragmentation_in_percent > 10.0 AND s.index_id > 0

SET @maxIndexes = @@ROWCOUNT
SET @indexCounter = 1

WHILE @indexCounter <= @maxIndexes
BEGIN

SELECT @objectid = objectId, 
@indexid = indexId, 
@partitionnum = partitionNum, 
@frag = fragmentation
FROM @work
WHERE indexNumber = @indexCounter

SELECT @objectname = o.name, 
@schemaname = s.name
FROM sys.objects o
INNER JOIN sys.schemas s 
ON s.schema_id = o.schema_id
WHERE o.object_id = @objectid

SELECT @indexname = name 
FROM sys.indexes
WHERE object_id = @objectid 
AND index_id = @indexid

SELECT @partitioncount = count (*) 
FROM sys.partitions
WHERE object_id = @objectid 
AND index_id = @indexid

INSERT @tables
SELECT @schemaname + '.' + @objectname, @indexname, @frag

SET @indexCounter = @indexCounter + 1
END

SELECT * FROM @tables ORDER BY fragmentation DESC, tableName, indexName

END

Then I ran the newly created stored procedure (exec CfgIndexInformation) to get information on the Indexes fragmentation. The indexes used by the most expensive query I found earlier were gragmented at 95%, 91% and 66% respectively. I stopped and disabled all the Nintex Analytics services and ran exec dbo.CfgIndexRefresh against all the Nintex Analytics content databases as per the support team advice.

That has decreased the fragmentation a lot and we've managed to run the Nintex Analytics fine after that. The long-term solution is to schedule the index refresh on a monthly basis to avoid reoccurences of that.

Thursday, December 11, 2014

Bamboo World Clock & Weather Web Part stopped working today

We are using a 3rd party webpart for displaying weather and clocks for a few customers on SharePoint 2010. The webpart is also available for 2007 and 2013. This has unexpectedly stoped working today (2nd time in the last 2 months). Usually it works quite alright and for a free solution, there's no better alternative. More info in the Bamboo website.

The webpart looks like that when working (just a basic example, there's lots of configuration you could do on the looks of it, what is displayed, sizing and formatting):



Today, I've proactively noticed that the webpart looks like this as I was doing other work for one of the clients that have this in place:


Some quick analysis shows the feed that it used just doesn't exist anymore. It was located here. Now all it says is:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<weatherdata xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<weather errormessage="Access denied: Please contact weather@microsoft.com if you need access to this API."/>
</weatherdata>

The previous time we've had issues with that webpart, we've just upgraded it as per their recommendations (that includes redeploying the solution and readding the webpart to all pages where you've used it before) and it started working again. I guess a change in the MSN Weather API.
Today, that's not an option as we're running the latest version.

The good news is the webpart has an out of the box option to get the feed from Yahoo instead.
So I've tried that and it worked like a charm. Hopefully that will last longer than the MSN one :)





Friday, December 5, 2014

How to redirect a page in SharePoint with JavaScript

There are many ways to redirect a page in SharePoint - embedding code in the page itself, or using some tools that need to be installed on the web front-ends. The code might not be an option for everyone (you need Visual Studio) and the tools have their additional administration overhead.

If you don't have any URL rewrite modules like Helicon or the free one from Microsoft or you simply don't want to use such tools, here's an easy script that will help you redirect users from a SharePoint page to any location.

Just add that in a Content Editor Web part and that should be all working.

<script type="text/javascript">
window.location = "http://<the desired URL here>"
</script>

Hope you find that helpful.

SharePoint 2010 / 2013 and OWA 2010 / 2013 impacted - Security Bulletin coming

Microsoft have just released an advanced notification on that yesterday. It seems we'd need to be applying those updates next week, once they're released on Tuesday, 9th of December. I'll update the article once we apply those to test environments and see if there are any considerations to be taken prior to applying them.

Here's the list of impacted software, concerning all SharePoint people out there:

Microsoft Office Services and Web Apps

Microsoft SharePoint Server 2010
Bulletin Identifier
Bulletin 3
Aggregate Severity Rating
Microsoft SharePoint Server 2010 Service Pack 2
Word Automation Services
(Important)
Microsoft SharePoint Server 2013
Bulletin Identifier
Bulletin 3
Aggregate Severity Rating
Microsoft SharePoint Server 2013
Word Automation Services
(Important)
Microsoft SharePoint Server 2013 Service Pack 1
Word Automation Services
(Important)
Microsoft Office Web Apps 2010
Bulletin Identifier
Bulletin 3
Aggregate Severity Rating
Microsoft Office Web Apps 2010 Service Pack 2
Microsoft Web Applications 2010 Service Pack 2
(Important)
Microsoft Office Web Apps 2013
Bulletin Identifier
Bulletin 3
Aggregate Severity Rating
Microsoft Office Web Apps 2013
Microsoft Office Web Apps Server 2013
(Important)
Microsoft Office Web Apps 2013 Service Pack 1
Microsoft Office Web Apps Server 2013 Service Pack 1
(Important)

Source: https://technet.microsoft.com/library/security/ms14-dec

Wednesday, December 3, 2014

How to change the opening behavior of Calendar items in a Calendar Overlay view

Today I've had another interesting requirement to change the behavior of a SharePoint 2010 calendar, which was built using the Calendar Overlay view to address the need of multiple departments to be able to view all events in the organization. Each department was set with their own calendar, so the quickest choice was to use the Calendar Overlay view. That is quite limited, by the way, but that's a whole different story. You can't have more than 10 calendars and more than 9 different colors assigned to the calendars. You can, however easily customize the colors to your own choice. The final results looks like that:




Now, the user story is they find it annoying that whenever they click on a calendar item, it always loads in a new tab and when they click the "Close" button on it, it leaves the overlay view on the screen and that makes one additional tab open in their  browser.

No out-of-the-box way to change that unfortunately, but everything's possible with a little JavaScipt / jQuery - that will do the exact trick - it'll make the events load in a pop-up window in the same tab:

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
_spBodyOnLoadFunctionNames.push('calendarEventLinkIntercept');

function calendarEventLinkIntercept()
{
if (SP.UI.ApplicationPages.CalendarNotify.$4a)
  {
    var OldCalendarNotify = SP.UI.ApplicationPages.CalendarNotify.$4a;
    SP.UI.ApplicationPages.CalendarNotify.$4a = function () 
      {
        OldCalendarNotify();
        bindEventClickHandler();
      }
  }
  if (SP.UI.ApplicationPages.CalendarNotify.$4b)
  {
    var OldCalendarNotify = SP.UI.ApplicationPages.CalendarNotify.$4b;
    SP.UI.ApplicationPages.CalendarNotify.$4b =  function () 
      {
        OldCalendarNotify();
        bindEventClickHandler();

      }  
  }
}

function bindEventClickHandler() {
$('.ms-acal-rootdiv a').click(function(){EditLink2(this,'WPQ2');return false;});
}
</script>

Add that in a Content Editor Web part on your Calendar list overlay page and you're done.
The tricky bit: This only addresses the opening behavior when the user clicks on an item title. If they double click on the calendar field, the event still loads in a new window. I think that's also possible to change, but not worth the effort in researching and developing.

Tuesday, December 2, 2014

How to change the Web Part Title URL behavior

With my morning cup of coffee I decided to start with something fairly simple (as a requirement) - it's in fact quite fresh as I had to do it for a client yesterday. It sounded like a 5 minute job, at the end it turned out more interesting. I've done this on 2010 and tested on 2013 as well - same behavior.

The requirement is to make just one specific webpart title URL to open in a new window while keeping all others (if any) loading in the same browser window. I am referring to the "Title URL" property, that is set in the Advanced section when you edit the web part.


There's no out of the box option to configure that, you could remove the URL, or point it to the page itself by changing it to #, but no way to make it open in a new window by adding "_blank" or something.

We can, however use a tiny piece of JavaScript to achieve that (tell SharePoint to do a specific thing when someone clicks on a specific URL) and we have a couple of options doing that thanks to jQuery.

Depending on whether that webpart is reused in many sites or web apps, you need to decide which method is the right one for you, You can do it globally with a full trust solution. That would have a wide impact on all web apps that have the solution deployed.
Let's assume you already have some branding solution in place which has a ccustomizations file in a .js format, you can add that piece of code in there. We are using the onload function here to ensure the site has fully loaded. If you have other JavaScript / jQuery customizations in the site that's the preferred method of calling jQuery to avoid any conflicts. The downside is that it will load only after all images are fully loaded, including some banner ads, etc.

In those example scripts I'm using the Microsoft CDN hosted version of the jQuery library, you can, however download a copy and store it locally on your site. Please make sure you use the https:// prefix in the reference if your site is accessed through SSL.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
window.onload = function() {
    if (window.jQuery) {
        jQuery(document).ready(function () {
                                jQuery('a[href^="http://www.contoso.com (replace with your URL)"]').click(function () {
                                jQuery(this).attr("target", "_blank");
                                });

                });
 </script>

The second way (more granular) is to store the script as a .js file in SharePoint and apply that on the page level by using the Content Editor webpart to call it. Here we're using the statement known as the ready event. This ensures that the code will run as soon as the document is ready for manipulation. Preferred method if we don't experience any conflicts with other customizations when trying to load it that way. Executes straight away without loading all the images first.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
$(document).ready(function(){
  $('a[href^="http://www.contoso.com (replace with your URL)"]').click(function() {
    $(this).attr("target","_blank");
  });
});
 </script>

You can also do that for all web part title URLs, the script will look like this:

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.0.js"</script><script>
$(document).ready(function(){
$("h3.ms-WPTitle a").attr("target","_blank");
 });
 </script>

That's it. You can then export/import your CEWP and reuse it on any other page quickly. Don't forget to set its Chrome type to None so you don't actually display it on the web page.