Henri's blogg


Recent Posts

Sync SharePoint Managed metadata field with database table using Powershell

No comments

Or: How to add terms to a termset from Powershell :)

In this case we are collecting project numbers from a SQL Server table, the Job table in a Navision instance to be exact.

When we have got the records all fine and happy we connect to SharePoint and asks it gently if it could please let us in to the Managed Metadata Service.
Once inside we rush to the term group Projects, demands it to show us it's term set Project numbers and then convinces it to accept all new numbers or else:

The term set Project number and Term group Projects already have lived a while in the Term Store. If your Term Store are missing out and wants a visit you could introduce them the usual way: Intro to Term store GUI

After getting on equal terms with Projects we settle down, release the site back to SharePoint with a polite Dispose() and retreat happily into the sun again.

As we both feel this was important we arrange a regular appointment using Scheduled Tasks  and promise to call.

Hope it helps,

Use Toastr messages from codebehind

No comments
I have been using the excellent toastr library for my clientside messages now for a while.

Today I needed to send a message from codebehind to the client and I wanted to keep using toastr.

As I prefer to solve things only once I wanted this to be reusable through my app.
Something like:

var msg= new Message(Level.Error,"This is the text", "This is the title"));

and then have this show up the nice toastr way:

(See demo over at GitHub for all the options.)

So to have a reusable way to send messages to my users with Toastr I came up with this model:

First I define a model for messages

Next I create a ViewModel class and inherit from it:

In the controller I can now easily add messages:

Add finally make them pop up in the view:

I can now add multiple messages with different levels, all from codebehind:

SharePoint Workflows: Access Denied when starting manually

1 comment

Permissions needed to start Workflow manually

I had a list workflow in SharePoint Online that wouldn't start for users with Edit and/or Contribute permissions on the list.

This was a workflow the user would start manually, but before it started the user would get to a page saying Access denied.

I then tried to give the users permissions on Workflow History and Workflow Tasks list, but still no luck. The page it was trying to open was layouts/15/workflow.aspx

The solution:
Give the users Contribute permissions to the site itself.

This may implicate that you will have to break permissions on other Lists you don't want these users to have that level of access to, but I have not found another way to bypass this issue.

Many times this issue will not surface because users are Members of your site and then by default they will inherit this permission. But if you are tightening up security, using AD groups etc for your permissions then you can suddenly find yourself in the same situation. Then just google here ;)

Speed up page load when fething dynamic data via ajax/getjson

No comments
I had a page that was loading data using getJSON,
and then looping through the resultset with each and populating a viewmodel using Knockout:

.done(function (data) {
$.each(data, function (i, avt) {

The problem was that already at 50-60 records the actual view was taking quite a few seconds to load after the heading etc was drawn on the page.

The solution was to populate the viewmodel in pieces so the view could start to fill in with data while adding records in chunks.

Solution using setInterval:

.done(function (data) {
var n= 0;
var itr=setInterval(function() {
var apt = data[n];
if (n== data.length) {

This solved the problem nicely and let the view start rendering immediately, and then continuing to fill in the blanks.

Knockout: Different contexts in click binding

No comments


<button class="btn btn-success btn-sm" data-bind="click: $root.matchAppointment.bind($parent)">Match appointment</button>

The outlined .bind($parent) above will set this to the parent context of your viewmodel in your javascript:

self.matchAppointment = function (context) {
      var parent= this;

The variable context in function(context) will be the current context where the data-bind occurs (as usual).

Handy for example if you have an Order with Order lines,
and you have some function you want to call from an Order line, but you need also some property from the parent viewmodel Order.

Post multiple values to WebAPi using jQuery

No comments


                    url: "/Api/AppointmentApi/MatchAppointment",
                    type: "POST",
                    dataType: "json",
                    data: JSON.stringify({ appointmentId: appointment.ID, contractId: contract.ID }),
                    contentType: "application/json; charset=utf-8",
                    context: this,
                    success: function (results) {
                    error: function (jqXHR, textStatus, errorThrown) {
                        self.Info(textStatus + ": " + errorThrown);

To post multiple values to a WebApi method you need to convert it first to a json string using JSON.stringify.

WebApi will correctly do the reverse transformation and rebuild the object:


        public dynamic MatchAppointment(dynamic data)
            int appointmentId = data.appointmentId;
            int contractId = data.contractId;

            var rslt=doSomething...
            return rslt;

SharePoint 2013 - Update Web Title and Description with Powershell in other cultures than English

No comments
To update Web.Title or Description is pretty easy if your SharePoint-installation is in English, i.e:

$web = Get-SPWeb "http://sp2013"
$web.Title = "My title"
$web.Description="My site description"

We are using Norwegian, and setting web.Title and web.Description gives no errors, but you will not see any changes either.
The problem is that this only changes the default english Title and Description.

There was little SharePoint-related information regarding this, but using this little gem from this answer on StackOverflow solves this nicely:

function Using-Culture (
   [System.Globalization.CultureInfo]   $culture = (throw "USAGE: Using-Culture -Culture culture -Script {…}"),
   [ScriptBlock] $script = (throw "USAGE: Using-Culture -Culture culture -Script {…}"))
     $OldCulture = [Threading.Thread]::CurrentThread.CurrentCulture
     $OldUICulture = [Threading.Thread]::CurrentThread.CurrentUICulture
         try {
                 [Threading.Thread]::CurrentThread.CurrentCulture = $culture
                 [Threading.Thread]::CurrentThread.CurrentUICulture = $culture
                 Invoke-Command $script
         finally {
                 [Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture
                 [Threading.Thread]::CurrentThread.CurrentUICulture = $OldUICulture

$desc="This website's description"
$web = Get-SPWeb "http://sp2013"
Using-Culture nb-no { $web.Description=$desc; $web.Update() }