Tuesday, August 29, 2017

Enable SharePoint Designer & code snippets in Office 365

I recently had to setup a new Office 365 tenant.

One of the first things I noticed was that SharePoint Designer was disabled, and could not find an option anywhere to enabled it.

Another problem caused by this is trying to add code snippets to pages, ending up with the message:

"This HTML cannot be inserted because you don't have access to add scriptable Web Parts in this site. Please contact your administrator if you think you should have rights to do so."



After searching for a while I found a solution using SPO.

1. Download and install SharePoint Online Management Shell

2. Load up the newly installed SharePoint Online Management Shell console

3. Run the following code snippet (after setting up your tenant details)


Wednesday, January 4, 2017

Using bookmarklets to instantly export webparts and other abilities

I've recently bumped into a blog post with mention of a tool that would convert a piece of JavaScript (that you would otherwise store in the server on in the browser through user scripts) to a bookmark!

This way, whenever you want to run a big chunk of code in your browser that would affect the currently opened website, you can simply push a button and off you go.

This is known as a "bookmarklet".

"A bookmarklet is a bookmark stored in a web browser that contains JavaScript commands that add new features to the browser."

The concept is simple:

  1. Develop a script that would add some function to the existing website (but will be executed on demand instead)
  2. Go to the Bookmarkleter page to convert the script
  3. Drag-and-drop the bookmark (or create it yourself) with the new "link"


Examples of SharePoint bookmarklets:


My very own "SPDevTools"

This script will inject several buttons near the SharePoint ribbon with several functions, such as:

  • Display the file:// url for the current location (so that it can be quickly opened in explorer in non-IE browsers)
  • Display the site template ID
  • Refresh the page (no postback)
  • Get a link to the current page (handy in iframes)
  • Sign in as a different user (feature removed in SP2013)




Anatoly Mironov's Webpart Exporter

A long way has come since we used other methods to export webparts, such as:


  • Opening the URL: /_vti_bin/exportwp.aspx?pageurl=http://mysite/SitePages/Home.aspx&guidstring=WEBPARTIDGUID
  • manually inject AllowExport="true" in the html of the WebpartID element while in edit mode, which brings back the Export contextual menu option


This new method, bookmarlet supported of course, will actually find all the webparts in the current page and allow you to export every single one of them with a simple click.



Dan Saedén's Web Properties Updater

This other handy piece of code will display all the current Web's properties, and allow you to add, edit or remove any of them very easily.



Bonus
There is also a great Google Chrome plugin - "ChromeSPEditor" - that can manage UserCustomActions and Web Properties.


References

https://en.wikipedia.org/wiki/Bookmarklet

https://chuvash.eu/2015/10/21/export-any-web-part-using-a-bookmarklet/

http://www.rlvision.com/blog/edit-sharepoint-property-bags-with-sppropertybag-js-bookmarklet/

http://sharepoint.stackexchange.com/questions/199542/is-there-a-way-to-reference-jquery-inside-my-master-page-without-having-to-modif/199579

Wednesday, August 10, 2016

Working around X-Frame-Options for iframes

The problem:

One of the first things we noticed after migrating to SharePoint 2013 was that our iframes have stopped working, giving the error:

"Refused to display 'http://contoso/pages/home.aspx' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'."


Quickly we could see that this is in fact a security mechanism to prevent click-jacking and others:

"The X-Frame-Options HTTP response header can be used to indicate whether or not a browser should be allowed to render a page in a frame or iframe. Sites can use this to avoid Clickjacking attacks, by ensuring that their content is not embedded into other sites."

Soon we realized that, starting SharePoint 2013, an HTTP Module is adding the header "X-Frame-Options" by default, with the value "SAMEORIGIN".

This is effectively preventing the rendering of pages outside the scope of the current web application.



The (attempted) solution:

So what to do?
At first we though we could fiddle around with the IIS by adding a new header.

But since the old header is still there, we end up getting two header entries.




The (actual) solution(s):

After some more research, we finally found some options:

WSP SOLUTION
Ventigrate has a WSP farm solution in CodePlex that "will prevent SharePoint from trying to inject the header in the first place". It gets the job done, at the cost of having to deploy yet another (Full Trust) solution into the farm


ALLOWFRAMING
Use AllowFraming in a Master Page or specific page/app that we want to enable embedding for. In cases where this actually works, this can potentially be one of the best workarounds.

<WebPartPages:AllowFraming ID="AllowFraming" runat="server" />


URL RULE
Install URL Rewrite in IIS and setup a new rule to remove the header (as proposed here)


LOAD BALANCING SETTINGS
For servers being load-balanced, there is typically an easier way, which is to setup in the configuration of the load balancer that this header should not be used (F5, etc.)


Needless to say, take all this with a grain of salt, and understand what X-Frame-Options actually is, and that removing it can potentially open up your website for malicious intents.


The aftermath:

The header issue is now worked out (hopefully), but we may not exactly be in "the clear" just yet.

In my case I was iframing a SharePoint 2013 page inside a SharePoint 2010 site. So I discovered the hard way that "it's not possible to trigger a different rendering mode in a child iframe in IE9" as mentioned by this StackOverflow post and documented here.



So now I could use iframes, but my SharePoint 2013 frame was rendering not in IE10 but in the same mode as the main site (IE8).

To further extend my problem, the jQuery version being used in the iframed site was v2, which BTW is NOT supported in IE8.

There are many ways around this, like having 2010-mode site collections in 2013 or conditionally loading the necessary jQuery version, but I just wanted to alert for this particularity of IE9+ and iframes.


Takeaways:


  • SharePoint 2013 introduces X-Frame-Options header which will prevent the embedding of iframes to external websites
  • Simply adding the header in IIS is not enough of a solution in order to work around this (potentially works outside the SharePoint ecosystem)
  • AllowFraming is a great way of supporting iframes on specific pages or sites
  • Internet Explorer 9+ now prevents the embedding of an iframe in a different rendering mode than it's parent (in another words, it uses the parent's rending mode)
  • jQuery v2 is not supported in IE8 (or any IE version in a page with IE8 rendering mode)



Links:

X-Frame-Options,

https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options

Discussions,

http://sharepoint.stackexchange.com/questions/56644/how-can-i-configure-x-frame-options-allow-from-on-my-sharepoint-installation

http://sharepoint.stackexchange.com/questions/72987/is-there-a-way-to-disable-x-frame-options-response-header-or-at-least-modify-it

Monday, March 14, 2016

#SharePoint #2010 | Caveats when upgrading master page to IE9 (with solutions)

Problem:
One of the biggest issues with branding is our "friend", Internet Explorer.
When we talk about SharePoint, specially SharePoint 2010, we are typically bound to one version of Internet Explorer, where everything works great, but as soon as we move to another version, all hell breaks loose.

In practice, this happens when we change this line,

< meta http-equiv="X-UA-Compatible" content="IE=8" />

to something like

< meta http-equiv="X-UA-Compatible" content="IE=9" />


Why would you do this?
Well, among other things, you get access to CSS3. Otherwise, even if you have IE9+ installed, you will not get CSS3 because the browser will be rendering in IE8 mode. Many other limitations of IE8 will apply as well.

Should you do this?
Ideally, no. This raises issues as soon as this is enabled and I'm sure not all issues have been found.
However, in a small and/or public facing application, where only a few areas, easily testable, are available, this can be achieved using the code fixes provided below.

What happens?

  • Rich text editors break (form.js)
    • IE8 handles "document.frame" differently (replace curly brackets with square)
  • People pickers break (entityeditor.js)
    • 'data' is not properly serialized
Example:




Solution:

The solution, at least for these two javascript errors, is to override the ootb functions that are breaking.

So we will create a form.ie9fix.js and a entityeditor.ie9fix.js and reference them on our master page, in the < head > area.

form.ie9fix.js




entityeditor.ie9fix.js


Resouces;

form.ie9fix.js

entityeditor.ie9fix.js

Monday, June 29, 2015

#SharePoint | Value cannot be null, parameter name: g

Problem:

Moving documents in SharePoint can be a difficult task at times.
One of the biggest challenges is keeping previous document versions.
In some cases, it works if you simply move the documents from one place to the other, while using explorer views (nb: only works for MOVE operation, not for COPY).

In other cases, explorer view, site content and structure and even 3rd party tools will fail to accomplish this.
One of the reasons - and the one explained in this post - is a problematic field schema. More specifically, the lack of a certain attribute on a certain type of field, that will prevent the operation from running successfully, resulting in screens such as the ones below.






    
        http://.../Demo Document 001.docx: Value cannot be null. Parameter name: g
    




Solution:

In this case, it appears that we have a field with type "User", which does NOT have the attribute "List" set to "UserInfo", which seems to be a must.
Although we might not have problems adding and editing documents without this attribute, we will definitely have problems with migrations, import/export, etc., in the future.

To solve this, I have a script with two steps.

1) identify fields of type "User" in the document library

The script outputs four entries or fields. three of them are internal fields, and one is our custom field.

function PrintFields($web, $listName)
{
 $lib = $web.Lists.TryGetList($listName)
 if($lib -eq $null)
 {
  throw "List $listName does not exist!"
 }
 Write-Warning "Displaying User fields for list $listName"
 write-host ""
 
 $lib.Fields | where-object {$_.Type -eq "User"} | select InternalName, Type, SchemaXml | format-list 
}



2) Add the missing attribute (SPField.SetAttribute)

function EditFieldXML($lib, $targetField)
{
 try
 {
  $fld = $lib.Fields.GetFieldByInternalName($targetField)
 }
 catch
 {
  write-warning "Field $targetField does not exist!"
  write-host ""
  return
 }
 Write-Host Current field definition $fld.SchemaXml
 write-host $newLine
 $fld.Sealed = $false
 $fld.PushChangesToLists = $true
 $fld.Update()
 $schema = [xml]$fld.SchemaXml
 $schema.Field.SetAttribute("List","UserInfo")
 $fld.SchemaXml = $schema.PSBase.OuterXml
 $fld.PushChangesToLists = $true
 $fld.Update()
 Write-Host New Field definition $fld.SchemaXml
}




Complete source code here

Related links
http://sharepoint.stackexchange.com/questions/62731/move-publishing-site-between-subsites-using-manage-content-and-structure

http://blog.jussipalo.com/2009/06/moss-unable-to-import-custom-spfields.html

Friday, April 3, 2015

Mobile development opportunities

I was recently asked about the differences between the major mobile development markets what opportunities are there for developers.
After some research to fill-in the gaps, I have came up with a comparison table.


mobile development plan
storepriceprice for companiesdurationmobile apps (2014)languageref
google play$25$25one-time1.3MJavahere
windows store$19$99one-time300KC#here
apple store$99$1991 year1.2MObjective-C / Swifthere

What this table tells us, is that we have right away some big differences. If you are a typical Microsoft-oriented developer, you may opt with the windows store. You will get one of the best access fees (only $19) and you will be able to develop using the frameworks that you are used to.
Being a still growing market, there is a larger chance to create new apps that haven't been thought up before.

If you want to enter the Apple ecosystem, many bloggers recommend that you start with Objective-C. But you should know that you have to pay a minimum of $99 every year, and if you have a published app, it will be removed from the store as soon as you stop paying. Apple is also known for having one of the most rough validation procedures, where most "silly" apps will be blocked from entering the store. One could argue that there is a higher risk due to these prices, but this can also mean higher return of investment if you have a good product.

The Android / Play store is known for being more permissive. This can be an advantage and disadvantage at the same time. This store has cheap, life-time access, and the application approvals don't seem to be very thorough, so although it might be good for you, often we see news of viruses or hacks making their way into the store. But if Java is your comfort zone, creating a nice app with a good monetization plan could be the way to go.

How many apps per store?
A study has found that in 2014, the Google Play store was the one with the most apps, with around 1.3 million applications!

Is there a way to develop once and for all?
Yes, PhoneGap and Xamarin are just a few of the many options.
Check this stackoverflow comparison for more.

How can I make money?
Most markets will keep a 30% commission and let you keep 70%.
Here are a few monetization options:
  • Create apps with advertisements
  • Create one free (limited/adds) and one paid
  • Create a trial app (payment required to continue using)
  • Implement In-App purchases (e.g. "Gold coins")

Tuesday, March 31, 2015

Ultimate Debugging Enabler for SharePoint

Synopsys
On every new environment we often need to enabling custom errors, debug mode and other settings that will make your development environment spit-up all the exception in a human readable way.

What we don't usually we know is that, not only can be disable CustomErrors for SharePoint sites - just as we would for any .NET application - but there are also other things that we may need to take into considering in order to end up seeing something different than this:



Solution
Although we can see many different methods describing what, where and how to prepare an environment for debugging, the truth is that this procedure is not easy or straight-forward, and there doesn't seem to be a single place with all this information.
- different methods (CallStack, Debug, CustomErrors, AllowPageLevelTrace, Trace)
- different locations (IIS web.config, Template\Layouts, Template\Admin)

My proposal is to run a simple PowerShell script that will easily enable all the debugging attributes on all the necessary web.config locations, without harming the configuration files, and being able to revert the process to an original state.
As an added perk, a backup of the configuration file is made on every script execution (using the same format that regular backups use).
In case the debug mode was not changed, there will be no changes, to avoid having the pool recycle unnecessarily.

Script




Sources
http://blogs.msdn.com/b/voyage/archive/2014/09/02/enable-debugging-and-set-custom-errors-off-in-sharepoint.aspx

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

https://hughajwood.wordpress.com/2012/09/24/local-debugging-in-sharepoint/

http://blogs.prexens.com/Lists/Posts/Post.aspx?List=7a299699-f8da-4559-920c-bda481608691&ID=8

https://msdn.microsoft.com/en-us/library/0x5wc973%28v=vs.140%29.aspx

Monday, March 16, 2015

5 Conventions that can make our life easier

All my life I longed to work in a place were a list of rules were glued to the wall, saying what you can and cannot do, should or should not not, in your code. Doesn't have to be anything fancy like design patterns, life-cycle management, or unit testing, but the basic things that everyone should know, and keeping them in mind so they don't forget.

Because of the professional path (I guess), I was never told how to create my variables, what to name my methods, and to what extend I should use comments.
More and more I think that conventions are great because they allow everyone to do things in similar ways, ways that are recognized as good practice, and that will keep individuals from straying away and doing things "their way". Conventions are also good simply because we can create an organization-based list of rules so that everyone in the team speaks the same language and takes into consideration the same challenges (defaults for creating classes, pages, libraries, etc.).

With this in mind, I am going to lay down a few of this simple practices that help my everyday.


1. Write in English
This one goes out to those who, like me, don't speak English as their natural language.

Writing in English is great because, first, it is a convention that if everyone follows, everyone will be able to read each one's code. Other than that, well, it will be easier for you to sell your code if you want to, or just have someone read it to help you. In a globalized world, this is becoming a must, tough we sometimes forget or get lazy about it.

And yes, this applies to code comments as well!



2. Follow Naming Conventions
There are good generic conventions for variables, methods, classes and constants.
For each individual programming language, there are also some specifications.
E.g. for .NET, lowerCamelCase for variables and UpperCamelCase for methods:

Variables
float myWidth;

Methods
GetBackgroundColor()

Classes
class Raster;

Contants
MAX_PARTICIPANTS = 10;

Namespaces can also follow a convention, e.g.
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]


For PowerShell functions, it makes more sense to use the [Verb]-[Noun] convention for methods.
E.g. Add-DocumentToLibrary

If we run "get-command", we can see some common verbs, such as Get, Test, Update, Set, Start, Stop, New, and many others. Some may like his verb/noun signature just enough to use it on other languages.


3. Avoid spaces
Coming from an MS-DOS background, I am still used to keeping my folders with no spaces and low amount of characters. It is just easier for a script to go there without having strange characters in it, or requiring the usage of commas. Specially for the web, spaces are a huge no-no.

Some examples:

- Folders "\\computer\c$\file share"
\\computer\c$\file share VS \\computer\c$\fileShare

When you try to copy a link so you can send it to someone, the first link will break due to the space

- Websites and pages
http://site/site 1 vs http://site/site1

In some scenarios, the first url will have its space replaced by a "%20", which basically looks ugly.
In some other cases, the link may break as it did for the previous example

My advise is don't use spaces for websites, folders, or libraries.
For pages or views, sometimes it can make sense to separate two or more words. For those cases, use the hifen , "-", not the underscore, "_".
By doing this, you are also potentially improving SEO.

- SharePoint columns
If you worked with SharePoint, you know how bad can your columns' internal names look like
e.g. "Procedure Name" --> "Procedure_x0020_Name" or "Procedure%5Fx0020%5FName" (web)

Overall in SharePoint, it is a good practice to create something with a friendly name first, and then go back and change it (websites, lists, pages, views, columns).
It is also preferable to query "internal names" or "guids" instead of "display names", since the later are susceptible to change.


4. Refactor
It is common to hear, "if your code is more than one page long, it is too big".
I am not a fan of absolutes, but the idea is that if your method is becoming too big, than it probably does more than what it is selling.
It is usually good to split a function into several different functions in order to improve things such as:
- Reusability
- Unit testing
- Readability


5. Leverage helper methods
Common functions should go to a special place, where they can be easily reused.
Quite often you will end up doing repetitive code so you will want to refactor those "DownloadDocument" or "GetItem" methods to keep them generic enough so they can be reused, and at the same time, being able to copy them to other projects with little or no changes at all.

What many people are not aware of is the danger or creating static methods in static classes.
This is usually done so we can call a method without an instance of a class, but it goes down to what the method does. If you are relying on shared data, you may be in trouble.

Thursday, February 19, 2015

#Umbraco | Creating a contact form for dummies

As a .NET-based, MVC CMS, Umbraco sounds good right from the start.
However, for beginners, the easiest things may be hard to understand, specially if we want to get our hands dirty.

The post will cover the procedure to create a simple contact form in Umbraco, but also how to really integrate it with the platform, for those just starting to know the CMS.

1 - Provision your Umbraco environment
(check out my previous post, Installing Umbraco for the first time)

2 - Really understand the structure concept

The Model-View-Controller pattern is just one of the things you will have to get comfortable with.
The main challenge is to undertand how Umbraco structures its information, specially regarding pages, templates, view and master pages.

3 - Create a model
The model is the "Data Model" were we will need to setup the data structures and types to be used by our interacting elements.

Model (Models\ContactModel.cs):



4 - Create a controller
A controller is a piece of code that will handle the server side code.
The controller will reference the model to understand data structures, and will be referenced by views to create a link between the front end elements and the code behind.

Controller (Controllers\ContactController.cs):



5 - Create a partial view (UI) A partial view is an independent element, that displays html, css and others, while communicating with a controller for the execution of operations. It can be created by opening the /umbraco admin area and going to Settings > Partial Views and hit "Create".
Partial View (Views\Partials\ContactForm.cshtml):

6 - Create a document type & template (UI) If you have created your model, controller and partial view, you have almost everything you need, except there is no interaction with Umbraco just yet. You have functionality, but not structured functionality, like navigation and pages that show your features. This is what is really new when working with Umbraco. You will have to decide weather to create a specific document type for your future page, or use an existing document type, and just create a new template. From Umbraco: "Step 1 of any site is to create a "Document Type" – after a few installations you’ll become familiar with this terminology but at the start it might be a little bit bewildering. A Document Type is a data container in Umbraco where you can add data fields / attributes where the editor user can input data and Umbraco can use it to output it in the relevant part of a "template" (more on these later).  " The template is a .cshtml file, just as the partial view, except that the template will define the master page and render the view, usually with Html.RenderPartial(viewPath) Umbraco on templates. Procedure:
  • Next to "Master", create a new Document Type "Contact Form"
  • Agree to create a new Template with the same name
  • In "Home" Document Type, check "Contact Form" in "Allowed templates"
  • In "Home" Document Type, check "Contact Form" in "Allowed child node types"
  • In Templates, set the Master template of "Contact Form" to "Layout"
By now you should be able to create pages based on the contact form template, either in "Content" or under "Home". Template (Views/ContactForm.cshtml):

7 - Create a content page (UI) The page is, obviously, the endpoint for interaction with the user. You will setup a friendly url, a page title, and the body contents, if any. A page is associated with a specific document type, and the templates available for that document type. You can create a page in the "Content" area, assuming you have already setup the proper document types and templates. 

Resources:
Quick and Easy Umbraco 7 Razor Contact Form

Umbraco 7 and MVC - Contact Form


UPDATE!
If you are looking for a full deliverable, you can find it here.
This is a fully documented plugin that also contains a precompiled dll that can be included in your projects.

Installing #Umbraco for the first time

Problem:

Installing a new CMS can be tricky, and Umbraco is no different.
There are many ways, but even the easiest path can be a bumpy road.
For this reason, I like to do things manually, and define a process that really works.


Solution:


1 - Setup SQL Server and SQL Server Management Studio

Umbraco will install a SQL Compact Database by default, but in my opinion it is better to start working with SQL Server from the very beginning.
While opening the site for the first time (Step 7), there will be a setting "Customize" to allow selecting an SQL Server and instance, as opposed to the default compact database in the AppData folder.

I personally installed, from web platform installer:
"SQL Server 2008 R2 Management Studio Express with SP1" (management studio)
"SQL Server Express 2008 R2 Service Pack 2" (sql server instance)

If you want to use SQL Server, now it is a good time to use Management Studio and create a new database.


2 - Setup the Visual Studio Solution / Project

Open up Visual Studio (make sure you do it as Administrator to avoid future problems) and create a new project, ASP.NET Web Application, using .NET Framework 4.5.



3 - Add Umbraco to the project

Go to Tools > NuGet Package Manager > Package Manager Console and type:


Install-Package UmbracoCMS


4 - Setup a proxy, if you need one

A proxy can be defined in the web.config file, adding the below:




5 - Deactivate LoaderLock to avoid "ProfileDB.cs" request error


Debug > Exceptions > Managed Debugging Assistants > uncheck "LoaderLock"

source




6 - Compile the solution

Make sure the solution is fully working and that a new build is generated.
If you have classes in the App_Code folder, they might need to be set with "Build Action" to "Compile", or move them altogether.


7 - Deploy Umbraco using SQL Server

- Run (F5) or add your path to an IIS application to start Umbraco
- You will need to click "Customize" and then setup the SQL Server settings
- Finally, you will need to select a template



8 - Configure the project as an MVC application

If you are trying to right-click "Models" or "Controllers", you will not get the usual "Add Controller" or "Add Model" contextual options.

The workaround for this is to add the guid,  "{E3E379DF-F4C6-4180-9B81-6769533ABE47};"
to your .csproj file, inside the following tags:

source

However, you might want to consider creating a different project to place these elements.


9 - Delete the "Install" folder

Umbraco recommends that once you have installed the application, delete the install folder to prevent problems in the future.


Known issues

I have experienced some issues myself, some of them resolved with running one or more of the following commands, but for those making their first instances of Umbraco, I definitely recommend backing up the site and database often, to be able to rollback to a working state.

Update-Package
Install-Package -Id  Microsoft.AspNet.WebHelpers
Install-Package Microsoft.AspNet.Mvc -Version 5.0.0

Other resources:
Setting up Umbraco with Visual Studio
Install Umbraco manually

Update:

Version 7.2.2 was throwing a "missing plugins folder" error when choosing certain site templates.
This can be fixed by creating a folder "App_Plugins" in the Umbraco root folder.

There you go!

Thursday, January 29, 2015

Using FontAwesome as an icon framework


When customizing the look and feel of a website, we often want to use specific, intuitive icons.
In some cases - such as content management platforms - these icons are already there, but they may not make sense for many reasons:
  • not completely meaningful
  • color does not match the site design
  • not flexible enough

Wouldn't it be great is there was a lightweight solution we could use, that doesn't involve any script, of even custom images?!

Well, there is. I have been using FontAwesome for a while now and I can say it is pretty impressive:
  • 100% CSS (no images, or scripts)
  • Supports IE8+ and other browsers
  • Its an icon framework with 500+ icons
  • Provides a consistent icon set
  • Supports features such as custom size, mouse over color, animated icons, rotation, etc.
  • Its free!
Now, the idea is that you embed, in your html, a tag with your markup.

e.g.
 

Here's a breakdown:
  • fa provides common icon styles
  • fa-camera-retro specifies the icon to be used
  • fa-3x enables to increase the original size 3 times

In this post,  I have confirmed that we can use this framework even without adding custom html, as long as we add a reference to font-awesome.min.css and include the font files.

div.github:before {
 content: "\f09b";
 font-family: FontAwesome;

 /* more styling for the icon, including color, font-size, positioning, etc. */
}

Using this other idea, considering the markup of a SharePoint site is already there, we can remove the existing icon, and add another one, not an image, but from FontAwesome.

/* disable default icon */
.ms-list-addnew-img20[src*="/_layouts/15/images/spcommon.png?rev=23"],
.ms-list-addnew-img16[src*="/_layouts/15/images/spcommon.png?rev=23"]
              {
               width:0; height:0;
               /*visibility:hidden;*/
              }

/* add new icon */
span.ms-list-addnew-imgSpan16:before,
span.ms-list-addnew-imgSpan20:before
/*.ms-list-addnew-img16[src*="/_layouts/15/images/spcommon.png?rev=23"]:before*/
             {
              /*icon framework*/
               content:"\f055";
               font-family:FontAwesome;
               /* custom icon size */
               font-size:20px;
             }

/* fix new icon position */
span.ms-list-addnew-imgSpan16,
span.ms-list-addnew-imgSpan20      {height:auto; width:auto;}

/* custom icon hover color */
span.ms-list-addnew-imgSpan16:hover,
span.ms-list-addnew-imgSpan20:hover     {color:red;}

Tuesday, November 25, 2014

#SharePoint | An "Open with Explorer" tale

Problem:

I started this mini-project saying to myself:
If I work with Firefox, why can't I get "Open with Explorer".



Soon I realized that I was in way over head.
SharePoint's tight coupling to Internet Explorer, on top of security mechanisms of the web, make trying this a bumpy road.
After many attempts failed, I eventually gave up, but not before I defined a workaround, which would allow me to have something similar, not "one-click" but almost...

Solution:

Some post-attempt observations:
- Trying to re-use the "built-in" functionality quickly seems to be a showstopper.
- Trying to call an URL with file:// seems to have worked in the past, but due to new browser security mechanisms, it no longer works

1. Install grease monkey
https://addons.mozilla.org/pt-PT/firefox/addon/greasemonkey/

2. Add a script
Click "New user script..." from the Grease Monkey context menu.

3. Include jQuery
http://stackoverflow.com/questions/859024/how-can-i-use-jquery-in-greasemonkey
Edit the script and in the end, add a few empty lines, then paste the below to start up.

var $ = unsafeWindow.jQuery;


4. Add a button to a website
http://stackoverflow.com/questions/18226598/how-to-add-a-button-dynamically-using-jquery


5. Open the current library in explorer

Now, the catch.
I'm not really starting the explorer window, but I am providing the means to do so.
I return a prompt with the exact UNC path of the library so I can easily copy-paste it into a "win+r" dialog, or in a plain explorer view, previously opened.
It may seem a bit "tweaky", but for me as a developer, I like it.
I mean, if I use other browsers on a day-to-day basis, why should I have to open IE, map a folder, or even browse folder by folder in the file system to do this?

click the new explorer icon

copy the URL

 paste it in a Win+R window

navigate through your current browser URL folder





Full script:


Pros
  • Get a link to the current SharePoint folder on any URL (not just document libraries)
  •  Works on all sites, without any custom code

Cons
  • Local, per browser setting
  • Doesn't open file explorer directly


Other useful links:
https://social.msdn.microsoft.com/Forums/en-US/a926fd9f-ec4c-4fb0-a7a0-8c2da0804f9c/open-with-explorer-in-sharepoint-2010-greyed-out?forum=sharepointgeneralprevious

http://sharepointhannah.wordpress.com/2013/04/26/using-the-open-in-explorer-link-on-sharepoint-2013/

http://sharepoint.stackexchange.com/questions/27319/how-do-i-enable-open-in-explorer

Update:
Moved to CodePlex at https://spdevtools.codeplex.com/

Monday, November 24, 2014

#SharePoint #PowerShell start script on steroids

I work with SharePoint, and I work with PowerShell.
PowerShell scripts can easily become messy and unstructured, hard to troubleshoot.
The same concepts as "regular" programming apply: helper methods/functions, encapsulation, abstraction, etc.
But the main purpose of PowerShell is still, to automate things that otherwise would take loooooong time to do manually.

With time, I came up with a starter script for every usage, generic enough to allow me to start doing specific stuff right away, while taking advantage of nice snippets of code.

I'm not trying to solve any outstanding issues or represent any best practices, just sharing what is for me a life saver, due to the following:

- Ever wanted to be able to click "run" (double-click) and don't care if you bump into permissions issues, or remember to "run as administrator"?

- If the script crashes, you know exactly why, when and where, and you can also ensure objects are still disposed

- You will be sure that your working path is the same as the path the script itself is located

- Easily enabled logging/output capabilities

- Clear distinction between reusable code and parameter calls

Here it is, for the whole world to see.

Have any interesting PowerShell snippets? Feel free to share!


Friday, October 24, 2014

#SharePoint | Leveraging data management options

In SharePoint, there are many options and APIs to move, copy, duplicate, export content from one place to the other.

Common scenarios involve performing tasks such as archiving, back-ups, or related actions that require fetching information from a source and sending it over to a destination.

This post enumerates a few of those options, along with their benefits and caveats.


Content Database

Context: Multiple Site Collections (.bak)

One of the most common means of backing up and/or migrating content is using the whole database.
Databases store pretty much all the content of one or more sites, and they are our best option for reproducing content, while maintaining all the integrity of the source.

Backups can be created by copying the physical .mdf and .log.mdf files, or by exporting the database into a .bak file.

This is a brief example procedure for backing up a content database:
  1. In SQL Server Management Studio, right-click the content database, choose Tasks, Backup
  2. Make sure to choose "Full" backup and "Add" a storage location
 To restore the database:
  1. In SQL Server Management Studio, create a new, empty database with a name of choice
  2. Right-click the new database and pick Tasks, Restore, Database
  3. Click "From device" and pick the .bak file
  4. Enable the "Restore" checkbox
  5. Go to Options and enable "Overwrite the exiting database (WITH RELPACE) so that you overwrite the newly created database with the backup database
  6. In a SharePoint Management Shell
    1. Dismount-SPContentDatabase [OldDatabaseName]
    2. Mount-SPContentDatabase [NewDatabaseName] -DatabaseServer [ServerName] -WebApplication [WebUrl]


Backup-SPSite / Restore-SPSite


Context: Single Site Collection, Multiple Web Sites(.bak)

This CmdLet enables us to export a whole site collection, maintaining its GUIDS.

"It preserves the GUID of every object except the GUID of the Site: when you restore the backup, SharePoint generates a new GUID for the site collection."

Restore-SPSite | Backup-SPSite


Export-SPWeb / Import-SPWeb

Context: Single Web Site or specific Web resources (e.g. List) (.cmp)

This CmdLet enables us to export a web site, or parts of a web site, such as a list.
There are some caveats to this approach, specially if you are looking for an exact replication of a site (e.g. reproduce a production environment).

"A major drawback of this operation is that it does not preserves workflows instances, associations, history and tasks."

Export-SPWeb | Import-SPWeb



Move-SPSite / Copy-SPSite

Context: Single Site Collection

This is a useful CmdLet for moving a site collection from one content database to another.

Move-SPSite | Copy-SPSite


SPFile.CopyTo / SPFile.MoveTo

Context: Single Item (List/Library)

This method is able to copy an item from a source list to a destination list.
It is meant for usage in Document Libraries, although it has been proven to work with list items as well (see link at the end).

SPFile.CopyTo | SPFile.MoveTo


RootFolder.Files.Add()

Context: Single Document Library Item

This is one of the best alternatives to CopyTo/MoveTo, as they don't always work, specially on lists with many custom fields and content types.
Adding a new item based on an existing item proved to be a good workaround when copying/moving items.

SPFileCollection.Add


SendTo

Context: Single Item (List/Library)

SendTo is a simple, yet functional way of moving items through the UI.
When we move an item, we have the option to keep it linked to the original item or create a new copy.


File Explorer

Context: Multiple Document Library Item

This is by far one of my favourites.
Although the option to open a list in explorer is only available in Internet Explorer, we can also map a folder to take advantage of this easily.
One of the best cases most people are unaware is that we can effectivelly move a document, while keeping all its metadata and versions, just as long as we actually "move" it, not "copy" it.
This may not be true for certain file types, such as PDFs.

Another nice perk is being able to hide specific files or folders, based on the windows "show hidden files and folders" setting.
SharePoint does this by default on items with their names start with an underscore.

$folder = (Get-SPWeb http://url).Folders["DocLib_Name"]
$folder.Properties["vti_winfileattribs"]="00000016"
$folder.Update()

$file = (Get-SPWeb http://url).GetFile("/doclib/file.extension")
$file.Properties["vti_winfileattribs"]="00000016"
$file.Update()

 

Site Content and Structure

Context: Site Collection / Multiple Document Library Item

This option is available under Site Actions, "Manage Content and Structure" in the UI.
It's not the most famous feature ever, but for some cases, it serves its purpose, which is to copy or move items within the same site collection.


Templates (Web, List)

Context: Single Web Site or Single List (.stp)

Templates in SharePoint (.stp, .wsp) are great ways of exporting content. They seem like a nice approach, but quickly we start identitying a few caveats:
  • Limited (customizable) content size

    "Site templates are saved from within a site as an .stp file that contains a set of all modified files and lists in the source site. The file can also contain content from the source site, such as list items and documents. By default, the maximum size of an .stp file is 10MB." [ref]

    Workaround: bump up to 100MB (maximum is 500)
    stsadm -o setproperty -propertyname max-template-document-size -propertyvalue 100000000
    


    or PowerShell [ref]

    $webservice = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
    $webservice.MaxTemplateDocumentSize = [new_value]
    $webservice.Update()
    

  • Only for Webs, not Sites
    Workaround: save each site individually and restore them individually
  • Dependencies

    One of the biggest challenges is dependencies.
    Whenever we save a template of a site, it stores references of the web and site scoped features.
    For lists, we also must ensure the same columns and content types exist, otherwise, we may be able to create the templates, but we won't be able to create lists based on that template later.

    Links:
    _layouts/savetmpl.aspx (available through the UI once the publishing feature is enabled)

    Example: Creating a new web based on a web template through PowerShell


    #see which templates are available
    $site = Get-SPSite http://weburl/sites/site1
    $templateName = $site.GetWebTemplates(1033) | where-object{$_.Title -eq "my_template_title"} | select Name
    #"{CCC38530-B9B3-418A-BB87-91CA7F626711}#my_template_title"
    #create a new web based on a template
    $web = New-SPWeb http://weburl/sites/site1/web1 -Name mynewweb -UseParentTopNav -Language 1033
    $web.ApplyWebTemplate($templateName)
    



Content Deployment Wizard

Context: Site Collection / Web Site / List

Nice open source tool from Codeplex.


"The SharePoint Content Deployment Wizard provides the means to deploy the following content:

- site collections
- webs
- lists
- folders
- list items (including files/documents)"

Content is exported using the Content Migration API as a .cmp file"



3rd Party Tools

Context: Many

AvePoint's DocAve, Metalogix's Content Matrix, Kalmstrom's SP Archive, and others, are powerful tools and enable doing a lot of the above things without any code, but they are often expensive and they are not always suitable for every task, specially smaller operations.




Sources

Difference between STSADM Export and Backup,
http://blogs.msdn.com/b/yvan_duhamel/archive/2009/05/18/some-key-differences-between-stsadm-export-and-backup-operations.aspx

http://sharepoint.stackexchange.com/questions/62152/sharepoint-2010-what-is-the-difference-between-backing-up-a-site-collection-and/62156#62156


Content Deployment Wizard,
http://spdeploymentwizard.codeplex.com/


Moving list items between folders,
http://sharepointstruggle.blogspot.se/2010/07/sharepoint-vs-powershell-moving-list.html


SPFile.CopyTo VS RootFolder.Files.Add
http://sharepoint.stackexchange.com/questions/78426/spfile-copyto-vs-rootfolder-files-add


How can you move a document with its version history to a new library?
http://sharepoint.stackexchange.com/questions/1278/how-can-you-move-a-document-with-its-version-history-to-a-new-library/1507#1507

Sunday, October 12, 2014

#SharePoint | Customize OOB Approval Workflow Email Body

Problem:
The out-of-the-box approval workflow sends a few emails.
Sometimes, the content of these emails is not be best so you will want to customize them.
One of these cases, is having the misleading "successfully" term even if a workflow is actually rejected.

Solution:

1. Open SharePoint Designer

2. Open the Site Collection root

3. Click "Workflows"

4. Right click the Approval Workflow and choose "Edit Workflow"

5. Click "Approval" 


6. Click “Change the completion conditions for this task process”

7. Click the value of CompletionReason













8. Customize the email body (e.g. remove "sucessfully")



















9. Save your changes

10. Click "Publish" and wait for the process to complete.
Next time you reject a workflow, you will be seeing something different.



Source: 

#SharePoint | Ribbon tabs missing after view customization

Problem:
It appears that once we customize a view (e.g. add a webpart), the "Documents" and "Library" tabs will now be hidden from the ribbon until you manually click the list view webpart.





Solution:
There is a way to invoke the ribbon through JavaScript by identifying the containing webpart.
This will automatically pick the "Documents" tab, so we will also be tweaking that so we can try to create an almost seamless behaviour as before by choosing the "Browse" tab instead.
One caveat of this approach is that we need to wait until the ribbon has loaded in order to run our code.



This was possible thanks to a few posts in stack exchange,
http://sharepoint.stackexchange.com/questions/73174/items-and-list-tabs-in-ribbon-dont-show-after-editing-page

http://sharepoint.stackexchange.com/questions/49003/showing-the-tab-on-button-click

Saturday, October 11, 2014

#SharePoint | Enabling Workflow Trace Logs

Problem:
Even though we may have changed customerrors to off in the various web.config files:
  • wwwroot
  • template\admin
  • template\layouts
We may still get pages like these, specially after the workflow starter page, IniWrkflIP.aspx.



Solution:
This article has a great step-by-step tutorial on how to enable debugging of workflows in SharePoint 2007.
However, this wasn't working for me, so after a few trial-and-error, I managed to get it to work simply by pasting the below in the web.config of the web application.

The .log document is created, but only when a workflow starts.
Apparently, if for some reason the workflow fails to start, nothing is ever logged.

  <!-- enable workflow tracing -->
  <system.diagnostics>
    <sources>
      <source name="System.Workflow.Runtime" >
        <listeners>
          <add name = "System.Workflow"/>
        </listeners>
      </source>
      <source name="System.Workflow.Runtime.Hosting">
        <listeners>
          <add name="System.Workflow"/>
        </listeners>
      </source>
      <source name="System.Workflow.Activities">
        <listeners>
          <add name="System.Workflow"/>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="System.Workflow"
           type="System.Diagnostics.TextWriterTraceListener"
           initializeData="c:\\temp\\WFTrace-w3wp.log"
           traceOutputOptions="DateTime,ProcessId"/>
    </sharedListeners>
    <switches>
      <add name="System.Workflow.LogToTraceListeners" value="1"/>
      <add name="System.Workflow.Runtime" value="All" />
      <add name="System.Workflow.Runtime.Hosting" value="All" />
      <add name="System.Workflow.Runtime.Tracking" value="All" />
      <add name="System.Workflow.Activities" value="All" />
      <add name="System.Workflow.Activities.Rules" value="All" />
    </switches>
  </system.diagnostics>

Source:
How to enable logging information for several Windows Workflow Foundation namespaces

Tuesday, September 30, 2014

#SharePoint | Broken List Views / ECB

Problem:
- Clicking a list view ECB (Edit Control Block) often causes
This item is no longer available. it may have been deleted by another user. click ok to refresh the page.

- List View Web Part often causes
Unable to display this webpart. Correlation ID: xxx
(UI)

or

Error while executing web part System.StackOverflowException Operation caused a stack overflow.   
at Microsoft.Xslt.NativeMethod.CheckForSufficientStack()

(log)


Solution:
It appears that list views need to load within 1 second, otherwise SharePoint will block them from loading due to a timeout.


SPFarm.XsltTransformTimeOut
"Specifies the seconds that a customized XSLT transformation is allowed to run. "

This property is editable with PowerShell:
$farm = Get-SPFarm
$farm.XsltTransformTimeOut = 5
$farm.Update()

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.administration.spfarm.xslttransformtimeout%28v=office.15%29.aspx

http://sharepoint.stackexchange.com/questions/20523/custom-list-form-loading-error-error-while-executing-web-part-system-stackover

Tuesday, July 22, 2014

#SharePoint | Read-only stories from the field

Problem:
On of the most common problems I have encountered among end-users, yet with incredible variable cause, is without doubt the dreadful "Read-Only" message we get while opening documents.


Identification:

There are multiple possible operations users try to accomplish that may cause this.
Most will result on one or more of the following bahaviour:
- Word will open with the message near the title of the document [Read-Only]






- The save disk icon does not contain the arrows (as below), but a flat disk alone


-You may get "The file [filename] has been modified by [domain\user] on [date]" or "The URL [filename] is invalid. It may refer to a nonexistent file or folder, or refer to a vlid file or folder that is not in the current web".




- You may get "Message from webpage: The document could not be opened for editing"
"A Microsoft SharePoint Foundation compatible application could not be found to edit the document."




Solution(s):

#1 - Excel
Excel co-authoring is NOT available in SharePoint 2010.
Don't expect it to. Second user's will automatically get a read-only prompt.
If you manage to remove features such as worksheet protection, data connections and other features, you may be able to use Web Apps instead.

#2 - Unsupported browser
The only fully supported browsers are the 32 bit versions of Internet Explorer 7-11.
Features such as drag-and-drop, multiple file upload, open with SharePoint Designer and a lot others will simply not be available on other browsers.

#3 - Browser pops up open dialog (creating local version)
Internet Explorer (specially 9) will sometimes display a popup saying that it cannot open the document directly, but it will open a local copy instead, which after editing will obviously prompt to save it in the computer, or somewhere else.
I have solved this multiple times by upgrading to Internet Explorer 10.

#4 - Broken Content Type / Column
I recently had a huge problem with files opening as read-only.
Unfortunately, all the most obvious resolutions weren't working, and we eventually narrowed it down to a post-deployment issue.
Errors such as "modified by" or "the URL is invalid" were popping up like popcorn.
The problematic documents were all in the same library, so we started removing the columns one by one on a test environment until we finally figure out that the problem was a specific MMS column.

 #5 - Office 2013
It appears that right after we install any component of Office 2013 (Word, Lync, etc.), documents start opening in read-only mode, or not opening at all.
My resolution for this so far has been repairing the Office 2010 setup.
Repairing Office is also a resolution for the "for some users documents keep opening in the browser" problem.
Update: there is a registry tweak to workaround this.

#6 - Microsoft Upload Center
Another very common scenario is the upload centre cache.
Whenever a user opens an office document, this office add-in will automatically create a local backup. Should anything happen (failed connection to server), the document will be no longer up-to-date and the document will be "dettached" from the server.
We can set an option to make sure cache is cleared after we close Word, Excel, etc.




#7 - Locks
Locked documents are usually resolved by closing the document and re-trying.
For further troubleshooting, close all office instances and clear the upload center cache.
Also, consider trying to wait for the 10 minute lock.

#8 - Permissions
Finally, make sure the user getting access problems does indeed have the necessary security level (e.g. Contribute).

#9 - Checked Out Documents
If a document is checked out, usually there is a intuitite message that clearly states that the document is checked out to someone. Anyway, something to check as well.

#10 - Old office formats
It appears that documents with .doc, .xls and other formats of Office 2007 and below will not co-author. Make sure you save them with the latest format and re-upload, in order to take full advantage of the features provided in Office integration. As already stated, Excel 2010 documents still won't co-author due to software limitations (SP2010).

#11 - Windows 7 50MB file size limit

There is a key in Windows 7 that will block files bigger than 50.000.000 bytes from being copied/edited.

The fix is to increase this value in the key:

HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Services -> WebClient -> Parameters -> FileSizeLimitInBytes

Complete System Reset Procedure
A few troubleshoot steps for local system problems:
  • Close all office related instances
  • Clear IE cache (uncheck "preserve favorites", check everything else)
  • Upgrade IE9 to IE10
  • Delete cached items in Upload Center
  • Delete all files in c:\windows\temp and c:\users\[username]\appdata\local\temp
  • Repair Office
  • Restart
Further troubleshooting
Clear Server Cache

Your own resolution
If you have a resolution to a read-only problem not listed, be sure to share it among the rest of us.

Resources:
Document unlocker


* Update *

Custom objects
Some external objects, when added to a document, immediately turn the save icon into a "sorry, no co-authoring" icon.
So you may want to check your document for these special elements.