CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: sharepoint 2013

Trigger SP2010 Workflows using JSOM

Today I found out how to start workflows in JSOM (JavaScript Object Model in SharePoint). Nothing special, but since it is not documented, it took me a while to find a solution. Here is the code which I want to keep as simple as possible.

What you need to start a SP2010 Workflow for a list item or a document in JSOM, you need to load SP.WorkflowServices.js and you need to create the manager and get the service, then you can trigger a workflow using the workflow name, the list guid and the guid of the list item:

var ctx = SP.ClientContext.get_current();
var workflowServicesManager =
	SP.WorkflowServices.WorkflowServicesManager.newObject(ctx,
		ctx.get_web());
var service = workflowServicesManager.getWorkflowInteropService();
service.startWorkflow(workflowName, null,
	listGuid, plainItem.guid, initiationParams);

Here is the code to trigger a workflow for multiple items:

//fire the workflows
function fire2010WorkflowForListItems(ctx, listGuid, plainItems) {
	var workflowServicesManager =
		SP.WorkflowServices.WorkflowServicesManager.newObject(ctx,
			ctx.get_web());
	var service = workflowServicesManager.getWorkflowInteropService();
	for(var i = 0; i < plainItems.length; i++) {
		var plainItem = plainItems[i];
		console.log('scheduling workflow for id: ', plainItem.id);
		service.startWorkflow(options.workflowName, null,
			listGuid, plainItem.guid, options.initiationParams);
	}
	console.log('now executing...');
	ctx.executeQueryAsync(function() {
		console.info('yes, workflows completed for '
			+ items.length + ' items');
	}, function() {
		console.error('it didnt go well');
	});
}

 

The code above is inspired from this gist and sharepoint stackexchange. It is a simplified version that only works for list item workflows and SharePoint 2010 workflows.
Here is an example how you can get multiple items and batch start a workflow:

//just a couple of variables
var options = {
	workflowName: 'Behörigheter',
	listName: 'Documents',
	initiationParams: {}
};
//load list items
function startWorfklows() {
	//Start 2010 Workflow for a List Item
	var ctx = SP.ClientContext.get_current();
	var web = ctx.get_web();
	var lists = web.get_lists();
	var list = lists.getByTitle(options.listName);
	ctx.load(list);
	var items = list.getItems(new SP.CamlQuery());
	ctx.load(items);
	ctx.executeQueryAsync(function() {
		var listGuid = list.get_id() + '';
		var en = items.getEnumerator();
		var plainItems = [];
		while (en.moveNext()) {
			var it = en.get_current();
			//do not take checked out files, it won't work
			if (!it.get_item('CheckoutUser')) {
				plainItems.push({id: it.get_id(), guid: it.get_item('GUID') + '' });
			}
		}
		fire2010WorkflowForListItems(ctx, listGuid, plainItems);
	}, function() {
		alert('boom');
	});
}

//Load Worfklow Js dependency
var wfScript = 'SP.WorkflowServices.js'
SP.SOD.registerSod(wfScript,
	_spPageContextInfo.webAbsoluteUrl + '/_layouts/15/SP.WorkflowServices.js');
SP.SOD.executeFunc(wfScript, '', startWorfklows);

Why I needed it

I created a simple workflow that is triggered on Item Added and Item Updated. Unfortunately there are already thousands of items in the document library. To trigger them manually is nothing good. But a simple javascript solution did exactly what I wanted.

Minimal Download Strategy. Simple

There are many correct ways (1234, 5…) of making scripts work with the Minimal Download Strategy Feature (MDS) in SharePoint 2013 and 2016. But to be honest – every time I need it, I get confused. So now it is time to find a simple solution for that.

Who is better at it than the developers of the SharePoint themselves? Look at the MDS code in the built-in Display Templates:

mds-001

Let’s keep it as simple as Item_Default.js, let’s take it as it is and create our own scripts. Here is a skeletton of and MDS-ready script:

function runMyCode() {
	var time = new Date().toISOString();
	console.log('runMyCode', time );
}
runMyCode();
if (typeof(RegisterModuleInit) == 'function') {
	var scriptUrl = '/Style Library/runMyCode.js';
  RegisterModuleInit(scriptUrl, runMyCode);
}

Which boils down to this in pseudocode:

  1. Execute your code
  2. Determine if MDS is enabled
  3. If MDS is enabled
  4.       Register your code for execution

That’s it. No more overcomplicating.

Related findings

External scripts (outside SharePoint Site Collection, from CDN) within ScriptBlock of a custom action (like AddJSLink in PnP)  work withou any MDS-adjustments. The ScriptBlock adds a script tag to the head of the html document, and it the js reference is added to every AjaxDelta load. I would need more time to find out why. The good news is: it is an argument for using more CDN solutions in SharePoint.

Old stuff

A while ago I wrote two blog posts about MDS. Now I realise they were overcomplicated and the solution required customizations of the master page and 3rd-party scripts.

  1. Make your javascript code work with MDS part 1
  2. Make your javascript code work with MDS part 2

 

 

A tiny tool for User Custom Actions

hehyuaf

Everybody loves User Custom Actions in SharePoint. That’s the only recommended way of customizing SharePoint. You have heard about it. Unfortunately there is no convinient way of administering them. People have their console applications or powershell scripts to add, update and delete user custom actions. It works but it is hard to open up Visual Studio or PowerShell every time you will try out an idea on a test site.

To overcome this, I have created a tiny little tool, packaged as a bookmarklet for your browser. When you click on it, it will show your existing user custom actions and you can add new user custom actions.

It is an ongoing little project, available on github, contributions are welcome. What’s left is:

  • Implement Delete operation
  • Implement Update operation
  • Improve the UI.

Here is how it looks today:

usercustomaction-001

To use this tool, add a new bookmark in your browser and copy the content of bookmarklet.html as the url.

Resources on that topic:

Creating a bookmarklet for Exporting Web Parts

REST API for User Custom Actions (MSDN)

What it can be used for

It can be used on test sites to try out ideas. But do not use it in Production. On ther other hand, parts of this script can be used in other scenarios, like adding new functionality by site owners directly from the browser, where data is predefined.

How to add a JavaScript code

You can use this boilerplate code to add a UserCustomAction, just put it into the textarea and click “Add new”:


var fileref=document.createElement("script");
fileref.setAttribute.src= "YOUR-SCRIPT";
document.getElementsByTagName("head")[0].appendChild(fileref);

Best practices for User Custom Actions

  • Add a ScriptBlock instead of ScriptSrc. In that way you can reference javascript and css files outside you site collection – ultimately from a CDN site.

Export any web part from a SharePoint page

The blog post below describes the technical details about how Web Parts can be exported using a hidden tool in OOB SharePoint, though this requires manual assembling of a special url. If you are just interested in a solution for an easy Web Part Export function, just proceed directly to my new blog post where you can download my tool that you can add to your web browser.

 

[youtube https://www.youtube.com/watch?v=wL9y9E1aJy0]

Technical background

Almost all web parts can be exported from a SharePoint page. An exported web part  can be imported on another page or it can be used as a source in a module to provision pages. An exception is the XsltListViewWebPart, there you cannot enable exporting. I have used Glyn Clough’s method before which has worked although it is a complicated process. Now I have found another way for exporting any web part (even ListViewWebPart and XsltListViewWebPart) present on a page. A method that only involves a web browser.

How to export any web part

First, we need to find out the webpartid. To do so inspect the html markup with the web browser dev tools of your choice.

export-webpart-001

In SharePoint there is a hidden application page that exports web parts: /_vti_bin/exportwp.aspx. This page takes two query parameters:

  • pageurl. The absolute url of the page where the web part resides that you want to export
  • guidstring. The guid that is called webpartid in the markup on the page

So, suppose, you have this site: https://intranet.contoso.com and a web part (id: 0c3adfe9-8f5d-4432-918a-42410e4e324d) on a page https://intranet.contoso.com/Pages/default.aspx

This will be the resulting URL to export your webpart:

https://intranet.contoso.com/_vti_bin/exportwp.aspx?pageurl=https://intranet.contoso.com/Pages/default.aspx&guidstring=0c3adfe9-8f5d-4432-918a-42410e4e324d

Paste it into the web browser address bar and you’ll download an xml file with your web part definition. This method works in SharePoint 2010 and SharePoint 2013 and even in SharePoint Online (Office 365).

Sources

Natalia Tsymbalenko. Get the list view web part convertable

Maurice Prather. Exporting a ListViewWebPart

SharePoint StackExchange

I am glad to update my answer on SharePoint StackExchange site and provide a much easier way of exporting any web part from SharePoint.

Bookmarklet (update 2015-10-21)

Finally there is a bookmarklet for making Web Part Export a lot easier. See my new blog post for more details:

Export SharePoint List Data To Xml through PowerShell

Today my colleague Johannes Milling wrote an awesome post:

Export SharePoint List Data To XML Directly from the GUI

He uses the old and forgotten RPC-based web service owssvr.dll (that has existed since SharePoint 2003). This url pattern is used to get the xml-formatted list data for a specific ListView:

http://<site_url>/_vti_bin/owssvr.dll?Cmd=Display&List=<list guid>&View=<view guid>&Query=*&XMLDATA=TRUE

To automate this I have written a PowerShell function. All the details are in the comments:

function Export-OIPSPListDataAsXml {
<#
.Synopsis
   Exports list items as xml
.DESCRIPTION
   This function uses a built-in hidden service owssvr.dll in SharePoint
.PARAMETER Web
   SPWeb or a url for the SPWeb object where the list resides
.PARAMETER ListName
   List Name (List Title)
.PARAMETER ViewName
   Name of the List View to export the data
.EXAMPLE
   Export-OIPSPListView -Web http://myawesomesite -ListName "Teddy Bears" -ViewName "All Items"
.EXAMPLE
   Export-OIPSPListView -Web $webInstance -ListName "Top Links" -ViewName "All Items"
.Notes
    Name: Export-OIPSPListDataAsXml
    Author: Anatoly Mironov
    Last Edit: 2014-09-11
    Keywords: SPList, SPWeb, SPListView, Xml
.Link
	http://chuvash.eu
#>
    [CmdLetBinding()]
    param(
	[Parameter(Mandatory=$true)]
    [Microsoft.SharePoint.PowerShell.SPWebPipeBind]$Web,
    [Parameter(Mandatory=$true)]
    [string]$ListName,
    [Parameter(Mandatory=$true)]
    [string]$ViewName)

    $spWeb = $Web.Read()
    $list = $spWeb.Lists[$ListName]
    if (!$list) { throw "List $ListName on web $($spWeb.Url) could not be found" }
    $view = $list.Views[$ViewName]
    if (!$view) { throw "View $ViewName on web $ListName could not be found" }
    $url = "{0}/_vti_bin/owssvr.dll?Cmd=Display&List={1}&View={2}&Query=*&XMLDATA=TRUE" `
            -f $spWeb.Url, $list.ID, $view.ID
    $wc = New-Object Net.WebClient
    $wc.UseDefaultCredentials = $true
    $wc.DownloadString($url)
}

Improving the web performance of an intranet

overloaded-sharepoint-in-browser

All the “small” app parts, web parts, delegate controls, user controls, and other “packages” that “must” be delivered to the users on every page load of the Start Page of your Intranet.

Recently we made an investment to improve the performance of our intranet. We made many changes in different layers: SQL, Network, Browser upgrade and code. Here I want to tell about what code changes we did to improve the web browser performance. Please leave feedback if you find it useful. You can also share your suggestions. We measured the performance before our code changes and after them. We had amazing results. Unfortunately I can not share any numbers, but we improved the Time to First Byte, time to load event firing in the browser, memory consumption in the clients and, perhaps, the most important, we improved the perceived performance of the Intranet, the way how users experience the speed and UI responsiveness. To do this I got many ideas of my project colleagues and branch colleagues. Here is the list of changes we’ve implemented:

– Execute code on demand

Consider this scenario: on a page users can click on a button to download a vcard. Aggregating user information is a costly operation that requires getting data from the User Profile Service, getting the profile image from SharePoint. Don’t ever do this operation on page load. Move the code to the “onclick” action. In other words, work when it is needed. It is like cooking a lot of food, when you are not hungry. It is nothing new, unfortunately there were a couple of the “eager code” places.

– Cache results, investigate what parts can be cached and how fresh data needs to be

All data on your page doesn’t need to be fetched on every page load. In our project We listed all the “parts” of the start page and other often visited pages and went to the business and asked them to evaluate how fresh data should be. Some parts should be as fresh as possible (no cache), whereas it would be tolerated that the information could be dirty (cache up to one week or more).

– Reference javascript and css files from one location

Do you have jQuery in your SharePoint Intranet. How many copies do you have? What we did in our Intranet was that we partially implemented the CDN concept. Even though we don’t distribute our resource files geographically, we have 1-to-1 relation between a file and its absolute URL. In the whole intranet, we have only one jQuery url and only one our intranet.core.js url. We did by creating a dedicated CDN site collection. This alone makes a big difference. To evolve the idea we could provision resources outside SharePoint to remove the authorization overhead. We could also distribute it geographically by having files closer to the end users.

– Unify your framework and your dependencies

In our projects we had a couple of SharePoint-hosted apps developed by different teams. We had different approaches and different framework that solved almost the same problem: AngularJS and KnockoutJS. Eventhough apps are independent pieces of software, they were used within the same page (as app parts). It was too much http traffic. We agreed on Developer Guidelines and chose one framework.

– Do not hide controls on the page with CSS, remove them

On the start page in our intranet we didn’t show the left navigation, but it was still rendered in code behind. Instead hiding it with CSS, we just removed it by an empty ContenPlaceHolder in our Start Page Layout:


<asp:Content ContentPlaceholderId="PlaceHolderLeftNavBar" runat="server"/>

– Optimize jQuery Selectors

We reviewed all the jQuery code and improved the selectors. Optimizing the selectors will improve the overall performance in the browser, especially in older browsers. The worst example is using text selectors, like this one:

jQuery('#NoteBoardContainer*:contains("There are no notes posted yet. You can use notes to comment on a page"):last');

It will sink your IE8 browser.

– Minify javascript and CSS files

Minifying resource files like javascript and css is not hard. My recommendation is to use Web Essentials plugin in Visual Studio. Alternatively you can use the SharePoint Assets Minifier.

– Use the weakest selectors in CSS and in LESS

In our project we are using LESS. With LESS it is easier to write  readable CSS code. But be aware of the output. Do not make the selectors too strong: Use the weakest CSS Selectors. The weakest selectors will make it easier to maintain the CSS and it will minimize the amount of KB the server needs to send to your users’ browsers.

– Ensure javascript and CSS files are cached

JavaScript and CSS files should be cached. You should also avoid 304 responses where the Server answers “Not Modified”, because this has an impact on the performance. Configure the Blob Cache and put your resources into the Style Library.

– Remove all app parts from SharePoint-hosted Apps from the start page

There can be exceptions, but we encountered that client web parts (app parts) from SharePoint-hosted apps had a huge impact on the performance. The combination of a couple of app parts on often visited pages (like the start page on the intranet) led to long page load times. These are the reasons why you should not have SharePoint Hosted App Parts on your start page:

  1. App Parts are iframes. They are loaded simultaneously if you add client web parts (app parts) in a usual way. They hold up the whole page. Users cannot interact with the intranet page until all the content in all app parts has been loaded. This can be partially improved if you introduce a delay in the app part loading, by developing an own engine. See my blog post where I mention such a concept: AppLoader Concept for SharePoint apps.
  2. The content from a SharePoint AppWeb is not fully cached. If you examine the http traffic from the apps you’ll see a lot of 304 responses, meaning the browser requests when the server answers that there is no newer version. This has an impact on the performance. See more in Alik Levin’s blog: ASP.NET Performance: Get Rid of HTTP 401 and HTTP 304. In a SharePoint-hosted app you don’t have any control what so ever to adjust the the cache settings. This is not the case in the Provider-hosted apps.
  3. SharePoint-hosted apps can only use javascript. The code is executed on the client. Older browsers like IE9 or IE8 render the pages slower. The Start Page that is slower than the rest of the Intranet is not something that will engage your users.
  4. App Parts are iframes that do not know about their dimensions. App parts often need to update the height and the width  of the parent iframe. This causes irritating flickering. Perhaps OK on some pages, but I’d say totally unacceptable on the start page of your brand new intranet..

What did we do instead of App Parts on the Start Page? We converted them into Script Editor Web Parts, the app parts were only one-time parts, they only were used on the start page.

Do not get me wrong. What we did was not abandoning apps as a model, we just removed wrong apps, apps that cannot be reused, the SharePoint-hosted apps that had big performance issues. I am looking forward creating right apps, that are written with performance, reusability, scalability and good design in mind.

 

Showing Birthdays and Job Anniversaries in the Newsfeed

anniversary-001

In our project we have a requirement to show birthdays and job anniversaries in the Newsfeed. The solution is simple (when you know it) but there has not been any information about it online, until today. I want to share a few lines of PowerShell code to enable Anniversary notifications in the Newsfeed. This desired piece of code was written by my colleague Emma Degerman. Enjoy:

$job = Get-SPTimerJob | ? { $_.TypeName -like "*.UserProfileChangeJob" }
$job.GenerateAnniversaries = $true
$job.Schedule = [Microsoft.SharePoint.SPSchedule]::FromString("hourly between 55 and 55")
$job.Update()

The code retrieves the Timer Job that changes User Profiles, sets “GenerateAnniversaries” to true, then it updates the schedule to run it before the Activity Feed Timer Job and updates it. By the way, it is only applicable for SharePoint On Premises.

This is it, a quick tip for a great Intranet.

Debugging “What’s happening” in Communities

Recently an issue was reported about count mismatches in SharePoint 2013 Communities. The number of replies in category tiles sometimes is different compared to the community stats in the web part called “What’s happening”. The actual number of replies is 1 in the figure below. The user who has reported has tried to add, update and delete discussions and replies.

 

category-replies-count.png   comm-002

I have invested some time debugging this issue. It would be pity to not share my findings. Well the first thing to do was to determine the type name for the “What’s happening” web part. To do so just edit the  page and export the web part. In the exported .webpart file I saw that the type was Microsoft.SharePoint.Portal.WebControls.DashboardWebPart.

With that knowledge it is time to open ILSpy, an awesome and free(!) assembly browser and decompiler. Load the “Microsoft.SharePoint.Portal” assembly from GAC into ILSpy. Then use F3 to search for DashboardWebPart:

comm-003

The number of replies is retrieved from SPWeb.AllProperties:

comm-004

If the Property Bag does not contain it, it gets the number of replies from the list. The formula is as follows:

list.ItemCount - list.RootFolder.ItemCount

It means that it gets the number of both discussions and replies: ItemCount of Discusssions List. The number of Discussions is determined by the ItemCount in the RootFolder of the Discussions List. Discussions are List Items in the RootFolder (num2 in the figure below). Replies are saved in the subfolders, every discussion gets an own folder. The number of all replies are num3 in the figure below.

comm-005

After checking the web properties I could see that the number of replies there were wrong: 2.

The next step was to determine where and when the Web Properties are updated. The first guess every SharePoint Developer has in such cases is an EventReceiver. Here are all EventReceivers connected to the Discussions List:

$list.EventReceivers | select class, Type, Synchronization | Out-GridView

comm-006

Allright, CommunityEventReceiver then:

comm-007

Found where the actual update happens: CommunityUtils.UpdateWebIndexedPropertyBag

comm-008

The method is used in DiscussionListCommunityEventHandler.HandleEvent

comm-009

There is a flag, flag5 that is used to determine if the Web Properties should be updated:

comm-010

But the flag5 is not true on Delete operations in some code flows:

comm-011

 

That’s it. So deleting a reply will not have any effect on “What’s happening”. But adding a new discussion will also update the stats:

comm-012

To summarize the debug session, there is an issue in the OOB code that misses to update community stats when deleting a discussion or a reply. Adding a new discussion, or a reply will synchronize the stats.

Tip: Use the weakest CSS selectors

I am reading Mobile HTML5 written by Estelle Weyle. It is an awesome recap and new knowledge about html, css and javascript. I want to highlight one of tips I got: Use the weakest CSS selectors (can be found on page 204).

We all know, that inline CSS and !important are evil. They have a higher level of specifity and override the standard cascade of the CSS rules. If you use !important, then it will be hard to override CSS rules when you really need it. After these two classic “evils” the evil number three is overqualifying of CSS selectors. You should really never add more classes or ids or elements than needed. Consider this:

.warning {
  background-color: red;
}

It is often enough, you don’t need those:

html .warning
div .warning
div.warning, div &gt; .warning
body p#myP.blue strong.warning

SharePoint

In SharePoint sometimes we want override some OOB CSS rules. We have our own “namespace” to do that really simple. We have added a class to the html tag: “contoso-html”. Then it was really easy to update any OOB CSS rules, just copy the selector and add .contoso-html:

.contoso-html #s4-workspace { }

We also use less preprocessor and nest our selectors which has resulted that almost all of our selectors contain .contoso-html. Now back to the tip of that blog. This “namespace” made it harder to adjust CSS rules for special cases, like left navigation in the Search Center, we were forced to add more specific selectors, and selectors became bigger and bigger.

What I would recommend today is to skip the .contoso-html namespace in the CSS but keep it in the masterpage markup, use it wisely, meaning only if the original rule doesn’t work. Don’t nest too much in less files. Try always to find the weakest CSS selector. It is especially important in the SharePoint “markup djungle”.

Using CAML with SharePoint REST API

Do you prefer REST over CSOM as I do? I’ll skip the whys. Andrew Connell put it already in wrtiting so nicely. Well, if you do prefer REST, then you must have discovered some shortcomings of REST, or its incompleteness compared to CSOM. I think of:

  1. Inability to filter items based on multivalued taxonomy fields
  2. Inability to filter items based on user fields where user is added through a group, rather than directly, e.g. AssignedTo=[Me] combined with a SharePoint group.

In such situations I was forced to use CSOM. Until yesterday. Yesterday I learned that we can actually use CAML queries in REST requests.

 

This enables using REST in all situations. The REST API is still developed and many features are added. Maybe a particular operation that needs a CAML query today, can be supported in the core REST API and can be easily refactored then.

But until then, we can use CAML queries in REST requests. Here are the important things about it:

  • A REST request with a CAML query is always a POST request
  • A REST request with a CAML query has always to have X-RequestDigest http header (actually because it is a POST request)
  • A REST request with a CAML query should always have the attached CAML query in the request body (and not in a query string). We don’t want to mess with long urls, do we?
  • A REST request with a CAML query must have the http header “Content-Type: application/json;odata=verbose” unless you use xml in the request body.
Needed HTTP Headers in REST requests

HTTP headers you have to provide in REST requests with CAML queries

You can use jQuery or SP.RequestExecutor to make an ajax call. The REST endpoint is:

_api/web/Lists/GetByTitle('<your list title>')/GetItems

The request body (if you use json, and I bet, you do) is in this format:

{ "query" :
   {"__metadata": 
      { "type": "SP.CamlQuery" }
      , "ViewXml": "<YOUR CAML QUERY>" 
   }
}

Here is the boilerplate for a REST request with a CAML Query:

function getDataWithCaml(listName, caml) {
    var endpoint = "/_api/web/lists/GetByTitle('" 
        + listName + "')/GetItems";
    var requestData = { "query" :
           {"__metadata": 
              { "type": "SP.CamlQuery" }
              , "ViewXml": caml
           }
        };
    return jQuery.ajax({
        url: endpoint,
        method: "POST",
        data: requestData,
        headers: {
            "X-RequestDigest": $("#__REQUESTDIGEST").val(),
            "Accept": "application/json; odata=verbose",
            "Content-Type": "application/json; odata=verbose"
        }
    });
}

This function is just an example. It has no error handling, and it takes for granted that your list is in the root site for on your (sub-)domain (“/”). So take it as an example only.

Here is how the function can be invoked

var caml = "<View><Query><Where><Or><Eq><FieldRef Name='AssignedTo' /><Value Type='Integer'><UserID/></Value></Eq><Membership Type='CurrentUserGroups'><FieldRef Name='AssignedTo' /> </Membership></Or></Where></Query></View>";
getDataWithCaml("Tasks", caml);
Discovering SharePoint

And going crazy doing it

Bram de Jager talking Office 365, SharePoint and Azure

My view and thoughts on Productivity and more.

My programming life

and everything in between

SharePoint Development Lab by @avishnyakov

It is a good place to share some SharePoint stories and development practices.

SharePoint Dragons

Nikander & Margriet on SharePoint

RealActivity - Real-time and trustworthy

Blog site of founder, RealActivty - Paul J. Swider

Mai Omar Desouki - Avid SharePointer

Egyptian & Vodafoner - Senior SharePoint Consultant

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points!!

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode, ya mama

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know about SharePoint - CommunicoCuspis