Latest Event Updates

PeoplePicker qui ne trouve personne dans l’annuaire

Posted on

Bonjour,

Suite à une migration entre SharePoint 2013 > 2016 > 2019, et passant de Kerberos à Claims, j’ai observé un comportement étrange sur les PeoplePickers (sélecteur de personnes dans SharePoint, associé à une métadonnée de type Personne ou Groupe). En effet, ces derniers ne résolvaient plus les noms !

Dans l’usage classique, lorsque l’on commence à taper le nom d’un collaborateur dans une métadonnée de type Personne, une requête est lancée en direction de l’annuaire (ou des annuaires) afin de récupérer les identités des personnes dont le nom ou le prénom contient les lettres recherchées. Au retour de la requête, les propositions concordantes sont affichées à l’utilisateur qui pourra choisi celle qui l’intéresse.

Lors de cette migration, les PeoplePickers ne résolvaient plus rien, ne proposaient plus rien. Cependant la validation des noms en entrant l’adresse e-mail (UPN) suivi de Ctrl + K validait bien le champ. Etrange !

J’ai tout d’abord pensé à un problème sur la requête ou autour, plus précisément à un port bloqué par le firewall. Non dans mon cas ce n’était pas ca.

Dans les Logs ULS, j’avais peu d’éléments mais quelques erreurs remontaient toutefois, du type :

  • Exception from site settings manager. Using default value. Key: ‘EveryoneClaimEnabled’, Default: ‘True’
  • Error in resolving user. User: ‘Michel’, ResolverInformation: ‘SPActiveDirectoryPrincipalResolver, DomainName: ‘tatooine.local’, DomainIsForest: ‘True’, DomainLoginName: ”, CustomSearchQuery: ”, CustomSearchFilter: ”, Timeout: ’00:00:30′, IncludeDistributionList: ‘True”, Exception: ‘System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational. at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_AdsObject() at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne) at Microsoft.SharePoint.WebControls.PeopleEditor.SearchFromGC(SPActiveDirectoryDomain domain, String strFilter, String[] rgstrProp, Int32 nTimeout, Int32 nSizeLimit, SPUserCollection spUsers, ArrayList& rgResults) at Microsoft.SharePoint.Utilities.SPUserUtility.SearchAgainstAD(String input, Boolean useUpnInResolve, SPActiveDirectoryDomain domainController, SPPrincipalType scopes, SPUserCollection usersContainer, Int32 maxCount, String customQuery, String customFilter, TimeSpan searchTimeout, Boolean& reachMaxCount) at Microsoft.SharePoint.Utilities.SPActiveDirectoryPrincipalResolver.SearchPrincipals(String input, SPPrincipalType scopes, SPPrincipalSource sources, SPUserCollection usersContainer, Int32 maxCount, Boolean& reachMaxCount) at Microsoft.SharePoint.Utilities.SPUtility.SearchPrincipalFromResolvers(List1 resolvers, String input, SPPrincipalType scopes, SPPrincipalSource sources, SPUserCollection usersContainer, Int32 maxCount, Boolean& reachMaxCount, Dictionary2 usersDict)’, ExceptionStackTrace: ‘ at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_AdsObject() at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne) at Microsoft.SharePoint.WebControls.PeopleEditor.SearchFromGC(SPActiveDirectoryDomain dom… 0094b8a0-2951-e0fc-8428-cb70dfc9d300

Je vous passe les recherches infructueuses, les tests, le parcours de centaines de lignes de logs etc. Alors la solution à mon problème… C’est quoi ?

En fait, il m’a fallu modifier un paramètre dans la WebApplication, accessible en PowerShell pour aller implémenter un objet forçant la recherche sur l’annuaire (sa forêt en l’occurence), et qui finalement est relativement simple :

$wa = Get-SPWebApplication | ? { $_.displayname -eq "Intranet" }
$SearchAD = $wa.PeoplePickerSettings.SearchActiveDirectoryDomains
$domain = New-Object Microsoft.SharePoint.Administration.sppeoplepickersearchactivedirectorydomain
$domain.DomainName = "tatooine.local"
$domain.IsForest = $true
$SearchAD.Add($domain)
$wa.Update()

Et c’est tout, enfin pensez à faire un petit IISReset /noforce sur tous les frontaux Web.

NB : Pensez à vérifier :

  • le nom du domain, on parle du haut de la forêt et le paramètre IsForest vous permettra de rechercher partout ($true = partout ; $false = sur le niveau supérieur seulement)
  • Le nom de votre WebApp, j’ai mis Intranet ici, à vous d’adapter dans votre contexte

A bientôt !

Sources :

CountDictionary() : Fonction JavaScript non supportée dans SP2016 et SP2019

Posted on Updated on

Bonjour,

Suite à la migration d’un de mes clients de SharePoint 2013 vers SharePoint 2019 (en passant par SP2016 évidemment), je me suis aperçu qu’une fonction bien pratique n’était plus disponible ! Il s’agit de la fonction CountDictionary() qui permettait d’énumérer et compter les éléments dans un dictionnaire.

Vous l’aurez probablement utilisée dans des CustomAction placées dans le ruban de SharePoint par exemple, afin de vérifier qu’un élément au moins était sélectionné dans un affichage (vue liste / bibliothèque de document par exemple).

Heureusement il est possible de corriger le problème en modifiant son fichier source JavaScript et en ajoutant la fonction directement :

function CountDictionary(b) {
	var a = 0, c;
	for (c in b)
	a++;
	return a
}

Il est probable que d’autres fonctions aient été “oubliées” sur la longue route de SharePoint et ses migrations… mais pour l’instant je ne suis tombé sur aucun de ces cas 🙂

A bientôt ! (en tout cas je l’espère… depuis le temps que je n’avais pas publié !)

[SharePoint Online] – Modifier la Timezone sur une collection de sites

Posted on Updated on

Bonjour à tous,

Aujourd’hui un script utile pour modifier la Timezone (fuseau horaire) sur l’ensemble des sites d’une collection sur SharePoint Online (Office 365). J’ai eu ce besoin suite à une migration d’un tenant O365 vers un autre tenant O365 hébergé sur une autre plaque (Europe vers Etats-Unis).

J’ai décidé ici d’utiliser le CSOM de SharePoint Online mais c’est tout à fait réalisable avec du Powershell ou en utilisant le Pattern & Practice (https://dev.office.com/patterns-and-practices).

Voici le script que j’ai utilisé (qui est sans doute perfectible et optimisable !).

Tout d’abord, il vous faudra installer les binaires Microsoft.SharePoint.Client.dll et Microsoft.SharePoint.Client.Runtime.dll via le setup : https://www.microsoft.com/en-US/download/details.aspx?id=35588 (à télécharger & installer donc). Ces dlls seront installées par défaut dans C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\.

Une fois ceci fait, vous pourrez les référencer dans votre script de cette manière :


add-type -Path 'C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll'
add-type -Path 'C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll'

Ensuite, j’initialise la connexion vers la collection de site que je souhaite mettre à jour (remplacer par vos valeurs ce qui est entre [ ]) :

$SiteCollectionUrl = "https://[MONTENANT].sharepoint.com/sites/[MACOLLECTIONDESITES]"
$username = "[LOGIN]@[DOMAIN].com"
$password = "[PASSWORD]"

Puis ensuite, on initialise le contexte :

function GetClientContext($SiteCollectionUrl, $username, $password) {
    $securePassword = ConvertTo-SecureString $password -AsPlainText -Force
    $context = New-Object Microsoft.SharePoint.Client.ClientContext($SiteCollectionUrl)
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)
    $context.Credentials = $credentials
    return $context
}

 

Et enfin la fonction qui permet de mettre la Timezone à jour. Pour ma part, je la positionne sur la Timezone “(UTC) Dublin, Edinburgh, Lisbon, London”. Une petite recherche sur le net pour trouver votre zone… (http://blog.jussipalo.com/2013/10/list-of-sharepoint-timezoneid-values.html).

Cette fonction est récursive et permet d’itérer sur l’ensemble des sites de la collection :

function ProcessSites($subsiteurl){
    $clientContext = GetClientContext $subsiteurl $username $password
    $rootWeb = $clientContext.Web
    $childWebs = $rootWeb.Webs
    $clientContext.Load($rootWeb)
    $clientContext.Load($childWebs)
    $clientContext.ExecuteQuery()
 
    write-host $rootWeb.url -ForegroundColor Yellow
    $TimeZones = $rootWeb.RegionalSettings.TimeZones
    $clientContext.Load($TimeZones)
    $clientContext.ExecuteQuery()

    $RegionalSettings = $rootWeb.RegionalSettings
    $clientContext.Load($RegionalSettings)
    $clientContext.ExecuteQuery()
    $TimeZone = $TimeZones| Where {$_.Description -eq "(UTC) Dublin, Edinburgh, Lisbon, London"}

    $TimeZone | Select ID,Description
    Write-Host "TimeZone " $TimeZone.Description -ForegroundColor Yellow
    $RegionalSettings.TimeZone = $TimeZone
    $RegionalSettings.Update()

    $rootWeb.Update()
    $clientContext.ExecuteQuery()
    foreach ($childWeb in $childWebs)
    {
        write-host $childWeb.url -ForegroundColor Yellow
        $clientContext.Load($childWeb)
        $clientContext.ExecuteQuery()

        $TimeZones = $childWeb.RegionalSettings.TimeZones
        $clientContext.Load($TimeZones)
        $clientContext.ExecuteQuery()

        $RegionalSettings = $childWeb.RegionalSettings
        $clientContext.Load($RegionalSettings)
        $clientContext.ExecuteQuery()
        $TimeZone = $TimeZones | Where {$_.Description -eq "(UTC) Dublin, Edinburgh, Lisbon, London"}

        $TimeZone | Select ID,Description
        Write-Host "TimeZone " $TimeZone.Description -ForegroundColor Yellow
        $RegionalSettings.TimeZone = $TimeZone 
        $RegionalSettings.Update()

        $childWeb.Update()
        $clientContext.ExecuteQuery()

        Write-Host "Done :" $childWeb.Title "-" $TimeZone.ID

        ProcessSites $childWeb.url
    }
}


ProcessSites $SiteCollectionUrl

Il ne reste qu’à lancer dans Powershell ou Powershell ISE.

[SPOnline] – Verrouiller un site en lecture seule

Posted on

Bonjour à tous,

Aujourd’hui une astuce toujours utile et en particulier pour lors des migrations de sites ou les fermetures pour maintenance.

Sur SharePoint OnPremise, il est facile de jouer avec le “Lockstate” qui l’on passe en readonly via quelques lignes de PowerShell… Mais sur SharePoint Online, ce statut n’existe pas ! Vous avez juste la possibilité de le passer à “NoAccess” (aucun accès pour personne, sauf les administrateurs de la collection de sites) ou “Unlock” qui déverrouille donc…

L’astuce consiste à utiliser une politique de site (Site Policy) qu’il faut créer à la racine de la collection de sites. Pour cela, il faut se rendre dans les paramètres du site (racine de la collection de sites) :

01

Puis accéder au menu “Site Policies” :

02

Et enfin créer une nouvelle Policy :

03

On lui donne un nom, description et surtout :

  • Ne pas fermer le site automatique et ne pas le supprimer !
  • Cocher la case : le site sera en readonly quand il sera fermé

On enregistre ensuite :

04

On revient dans les paramètre du site :

05 06

Et cette fois-ci on va dans le menu “Site Closure and Deletion” :

07

On choisit dans la liste déroulante notre nouvelle policy et on valide la page :

08

On revient de nouveau dans le même menu :

09

Et cette fois-ci on clique sur le bouton “Fermer le site maintenant” (Close this site now) :

10

Immédiatement, un bandeau rouge apparaît en haut de la page nous informant que le site est bien en ReadOnly :

11

 

En espérant que cela vous soit utile !

 

[SP2013-SP2016] – Utiliser un JSLink pour afficher un slider

Posted on Updated on

Bonjour à tous,

Cela fait un moment que je n’ai rien publié, mais j’ai été pas mal occupé 🙂

Aujourd’hui, comment créer un jslink qui affichera les images d’une bibliothèque d’image sous forme de Slideshow en JavaScript en utilisant les jslink.

1/ Créer une bibliothèque d’images et ajouter des images

Première étape donc, créer une bibliothèque d’image dans un site SharePoint. Facilement réalisable, à la souris via l’interface de création des applications. Pour cela, rendez-vous sur votre site SharePoint concerné, puis utilisez l’engrenage (Paramètres / Settings), puis créer une Application (Add an app) :

01

 

Puis sélectionner le type d’application “Bibliothèque d’images” (Picture Library) :

02

 

Ici je l’appellerai “Images” pour cet exemple :

03

 

L’application “Images” de type bibliothèque d’images est créée :

04

 

Ensuite, je vais charger un ensemble d’images que je souhaite afficher dans mon slideshow. Pour cela, j’utilise le site Pexels (https://www.pexels.com/) mais vous pourrez en trouver sur beaucoup de sites (Attention au droit à l’image) :

05

 

Puis je les télécharger dans SharePoint (via glisser-déposer, mais pour pouvez évidemment utiliser le bouton télécharger, Windows Explorer etc.) :

06

 

Mes images sont donc maintenant dans SharePoint.

 

2/ Les ressources nécessaires

Afin que le diaporama soit animé, et de ne pas redévelopper la roue, j’ai choisi d’utiliser un JavaScript bien connu afin de créer mon diaporama qui s’appelle slidejs (http://www.slidesjs.com/). Ce script est assez facile d’utilisation, il est responsive, “touchable” (tablettes, smartphones) et utilise CSS3 (attention aux navigateurs non-compatibles… ça existe encore).

Il peut également démarrer tout seul (auto-play), utilise des transitions etc. Tout ceci peut être personnalisé suivant les besoins. Ici, je voudrai qu’il change de photo seulement quand l’utilisateur clique sur le bouton suivant (ou précédent).

Je vais donc avoir besoin de charger JQuery, et jquery.slides.min.js.

Pour ma part, JQuery est chargé dans la masterpage de mon site (et le fichier est dans le hive car je l’utilise sur tous les sites : /template/layouts/demo/jquery-1.11.2.min.js) :

07

Et dans ma masterpage (je vous laisse voir les différents moyens de charger JQuery) :

<SharePoint:ScriptLink ID="ScriptLink6" language="javascript"  Name="/_layouts/15/demo/jquery-1.11.2.min.js" runat="server" Localizable="false"/>;

08

 

Pour la fichier jquery.slides.min.js, je vais le charger dans la bibliothèque de style de la collection de sites car il n’est utilisé que pour ce site, et pas sur les autres (rien ne vous empêche de le déployer dans le hive). Pour cela :

Accéder au contenu du site racine (qui est le site en question dans mon exemple), utilisez l’engrenage puis “Contenu du site” (Site Content) :

09

Puis accédez à l’application “Style Library” :

10

Dans cette application, je créé un nouveau répertoire pour isoler mes ressources, ce répertoire s’appellera “demo” :

11

12

13

Et enfin je télécharger le fichier “jquery.slides.min.js” dans ce nouveau répertoire :

14

 

Sans oublier de l’archiver puis de le publier :15

16

17

Et enfin, il nous faut télécharger dans ce même répertoire le fichier JSLink permettant de lancer le Slideshow. Nous allons voir maintenant ce qu’il contient…

3/ Le JSLink

Ici nous allons donc utiliser le fichier “SharePointSlideshow.js” (vous pourrez bien sûr le renommer).

Premièrement, nous allons déclarer un namespace spécifique :

Type.registerNamespace('DEMO');
DEMO.SPSlideshow = DEMO.SPSlideshow || {};
DEMO.SPSlideshow.Templates = DEMO.SPSlideshow.Templates || {}
DEMO.SPSlideshow.Functions = DEMO.SPSlideshow.Functions || {}

Puis déclarer un ID global pour le div qui encapsulera les éléments du slideshow :

var slideshowId = '';

Et enfin, déclarer les fonctions nécessaires :

Fonction affichant 1 élement :

DEMO.SPSlideshow.Functions.Display = function (ctxSlideshow) {

    var viewMoreLabel = "+ Read more";    
    var webpartTitle = "";

    /* DECLARE COLUMNS INTERNAL NAMES  */
    var ColumnIDInternalName = "ID";
    var ColumnTitleInternalName = "Title";
    var ColumnFileRefInternalName = "FileRef";   
    
    /* GET ITEM VALUES FROM CONTEXT  */
    var item = ctxSlideshow.CurrentItem;
    var itemId = item[ColumnIDInternalName];
    var itemTitle = item[ColumnTitleInternalName];
    var itemFileUrl = item[ColumnFileRefInternalName];
       
    //create img form jsslide library
    var strSlideshow = '<img src="' + itemFileUrl + '">';
    
    return strSlideshow;
}

Fonction générant le Header (div encapsulant la structure générale, voir documentation de slidejs) :

DEMO.SPSlideshow.Functions.GenerateHeader = function (ctxSlideshow) {

    var webpartId = ctxSlideshow.wpq;
    var webpartTitleCell = '#WebPartTitle' + webpartId;
    $("#WebPart" + webpartId).css("position","relative");
    var header = '<div class="container">';
    slideshowId = 'slides' + ctxSlideshow.ctxId;
    header += '<div id="' + slideshowId + '">';
    //insert buttons for next and previous
    header += '<a href="#" id="slideshowleftarrow" class="slidesjs-previous slidesjs-navigation"></a>';
    header += '<a href="#" id="slideshowrightarrow" class="slidesjs-next slidesjs-navigation"></a>';
    return header;
}

Fonction générant le Footer (div fermant la structure générale, voir documentation de slidejs):

DEMO.SPSlideshow.Functions.GenerateFooter = function (ctxSlideshow) {  
    var footer = '</div>';
    footer += '</div>';
    return footer;
}

Fonction permettant d’appliquer les éléments en JQuery sur la structure, et mettant en forme le slideshow :

DEMO.SPSlideshow.Functions.PostRender = function (ctxSlideshow) {   
    //start slide
    $(function () {
        var slidedivid = '#' + slideshowId;
        $(slidedivid).slidesjs({
            start: 2,
            pagination: {
                active: false
            }       
        });
    });    
}

Et enfin, le bout de script permettant de faire le “register” du JSLink sur le WebPart standard d’affichage des images (Application Picture Library) :

DEMO.SPSlideshow.Templates.RegisterSlideshowDisplay = function () {
// Fallback to loading jQuery from a CDN path if the local is unavailable
(window.jQuery || document.write('&lt;script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.2.min.js"&gt;&lt;\/script&gt;'));

var slideshowcontext = {};
slideshowcontext.Templates = {};
slideshowcontext.Templates.Header = DEMO.SPSlideshow.Functions.GenerateHeader;
slideshowcontext.Templates.Item = DEMO.SPSlideshow.Functions.Display;
slideshowcontext.Templates.Footer = DEMO.SPSlideshow.Functions.GenerateFooter;
slideshowcontext.Templates.OnPostRender = DEMO.SPSlideshow.Functions.PostRender;

slideshowcontext.ListTemplateType = 109;
slideshowcontext.BaseViewID = 6;

SPClientTemplates.TemplateManager.RegisterTemplateOverrides(slideshowcontext);
}

//Register CSR-MDS module then call template registration
DEMO.SPSlideshow.Functions.RegisterInMDS = function () {
//RegisterLikes-override for MDS disabled site (because we need to call the entry point function in this case whereas it is not needed for anonymous functions)
ExecuteOrDelayUntilScriptLoaded(DEMO.SPSlideshow.Templates.RegisterSlideshowDisplay, 'clienttemplates.js');
// RegisterLikes-override for MDS enabled site
RegisterModuleInit(_spPageContextInfo.siteServerRelativeUrl + "/Style Library/demo/SharePointSlideshow.js", DEMO.SPSlideshow.Templates.RegisterSlideshowDisplay);
}

//Load CSR-MDS module if feature is activated
if (typeof _spPageContextInfo != "undefined" &amp;&amp; _spPageContextInfo != null) {
DEMO.SPSlideshow.Functions.RegisterInMDS();
}
else {
ExecuteOrDelayUntilScriptLoaded(DEMO.SPSlideshow.Templates.RegisterSlideshowDisplay, 'clienttemplates.js');
}

Lorsque ce fichier est globalement (et syntaxiquement ok), il faut le télécharger avec le fichier précédent dans Style Library/Demo (on l’archive et publie également) :

18

 

4/ Utilisation

Pour utiliser ce JSLink, il faut tout d’abord ajouter le composant WebPart de l’application Picture Library sur une page. La page d’accueil par exemple. On édite la page en cliquant sur le bouton Modifier (Edit) dans le coin haut-droit :

19

Dans la galerie de WebParts, on choisit le WebPart associé à la nouvelle application Bibliothèque d’images (qui s’appelait “Images” dans mon cas) :

20

 

Et on l’ajoute dans la page, puis on sauvegarde la page :21

Ensuite, on repasse en édition sur la page, et on modifie les propriétés du composant WebPart que l’on vient d’ajouter :

19

Dans le coin en haut à droite du WebPart, on accède au menu “Modifier le composant WebPart” (Edit Web Part) :

22

 

La “boite à outils” du WebPart s’ouvre sur la droite :

23

Dans le dernier champ “JS Link”, il faut indiquer le chemin (relatif à la collection de sites) vers le fichier “SharePointSlideshow.js”. Dans mon cas, j’indique :

~sitecollection/Style%20Library/demo/jquery.slides.min.js|~sitecollection/Style%20Library/demo/SharePointSlideshow.js

J’utilise le token “~sitecollection” afin d’indiquer que mon url est relative à la collection de site (vous pouvez également utiliser ~site), SharePoint se chargera de recomposer l’url absolue. Et ensuite, j’utilise “|” afin de dire à SharePoint qu’il doit charger 2 scripts : “jquery.slides.min.js” et “SharePointSlideshow.js” :

24

 

On clique sur “OK”, on enregistre et immédiatement, le slideshow est fonctionnel (moche mais fonctionnel). En effet les boutons “Previous” et “Next” fonctionnement :

25 26

 

5/ Faire du beau…

En effet, le rendu est un peu sommaire… des liens cliquables, en bas… pas super ergonomique et même moche. Allez on fait du “un peu plus beau”. Et donc de la CSS !

Premièrement, je vais utiliser 4 images pour remplacer les liens Previous / Next par des flèches qui changeront de couleur lorsque la souris les survolera :

rightarrow-active rightarrow-inactive leftarrow-active leftarrow-inactive

 

 

Je vais télécharger ces images dans l’application “Style Library, dans le même dossier que les fichiers *.js téléchargés précédemment :

27

 

Puis enfin je vais créer une nouvelle feuille de style qui contiendra quelques directives pour mettre en place tout ça qui s’appellera SharePointSlideshow.css. Je choisis également de la déployer dans l’application Style Library et de la référencer dans la masterpage :

28

Dans la masterpage :

<SharePoint:CssRegistration ID="DemoCSS" Name="<% $SPUrl:~sitecollection/Style Library/demo/SharePointSlideshow.css %>" After="corev15.css" runat="server">

29

 

Et enfin le contenu de la CSS :

/* WebPart slideshow */

#slideshowleftarrow{
background:url('/sites/tests/Style%20Library/demo/leftarrow-inactive.png');
background-repeat:no-repeat;
height: 46px;
width: 35px;
position:absolute;
top:50%;
left:0;
z-index:98;

}

#slideshowrightarrow{
background:url('/sites/tests/Style%20Library/demo/rightarrow-inactive.png');
background-repeat:no-repeat;
height: 46px;
width: 35px;
position:absolute;
top:50%;
right:0;
z-index:98;

}

#slideshowleftarrow:hover{
background:url('/sites/tests/Style%20Library/demo/leftarrow-active.png');
background-repeat:no-repeat;
height: 46px;
width: 35px;
position:absolute;
top:50%;
left:0;
z-index:99;

}
#slideshowrightarrow:hover{
background:url('/sites/tests/Style%20Library/demo/rightarrow-active.png');
background-repeat:no-repeat;
height: 46px;
width: 35px;
position:absolute;
top:50%;
right:0;
z-index:99;

}

a[title="Previous"] {
display:none;
}

a[title="Next"] {
display:none;
}

/* End WebPart slideshow */

 

Et voici le résultat :

slideshowjs

 

 

[SP2013] – Récupérer le statut d’un Workflow d’Approbation en REST

Posted on

Bonjour,

Aujourd’hui, un article orienté développement. Il s’agit ici d’une fonction JavaScript permettant de récupérer le statut d’un Workflow d’approbation standard SharePoint Server 2013 afin de l’afficher dans une page par exemple.

A la base, dans mon exemple, je devais afficher ce statut d’approbation dans la page d’accueil d’un Document Set sur lequel portait ce flux d’approbation. L’idée était d’insérer, via un WebPart  éditeur de contenu, un bloc de HTML et de fonctions Javascript afin d’afficher ce statut.

Je ne vais détailler ici que la partie requêtage, il sera facile pour vous d’utiliser ceci dans une logique métier par exemple.

1/ Statuts du Flux de travail d’approbation

Première chose à connaitre, ce sont les différents statuts qui peuvent être affichés lors de l’utilisation de ce type de flux de travail. Ces statuts sont représentés par un entier :


0 == Not Started
1 == Failed on Start
2 == In Progress
3 == Error Occurred
4 == Canceled
5 == Completed
6 == Failed on Start(Retrying)
7 == Error Occurred (Retrying)
15 == Canceled
16 == Approved
17 == Rejected

 

2/ Appeler la fonction…

Pour appeler la fonction, j’ai choisi d’utiliser la fonction JQuery ready(), qui appelle ExecuteOrDelayUntilScriptLoaded() afin de différer l’appel à ma fonction qui récupère le statut, après le chargement de sp.js :


$(document).ready(function () { ExecuteOrDelayUntilScriptLoaded(loadItem, "sp.js"); });

Puis on déclare la fonction loadItem. Cette fonction récupère l’identifiant de l’item courant dans la QueryString (vous pouvez modifier cette partie suivant le cas d’usage) puis construit l’url de la requête REST à partir de cet identifiant et de l’identifiant de la Liste :

function loadItem() {
itemId = getParameterByName('ID');
console.log(WFName + ' : Current item id = ' + itemId);
listId = _spPageContextInfo.pageListId;
console.log(WFName + ' : Current list id = ' + listId);
var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getById('" + listId + "')/items(" + itemId + ")?$expand=FieldValuesAsHtml";
var requestHeaders = { "accept" : "application/json;odata=verbose" };
return $.ajax({
url: url,
method: "GET",
contentType: "application/json;odata=verbose",
headers: requestHeaders,
success : loaditemsuccess,
error : onError
});
}

 

Suite à l’exécution de la fonction précédente, en cas de succès, on récupère le statut du Workflow et on affiche le statut comme souhaité (non détaillé dans cet article) :


var WFColunmName = 'Validati';

var WFName = 'WF Approbation';

function loaditemsuccess(data, request) {
var moderationStatusName = data.d.FieldValuesAsHtml[WFColumnName];
console.log(WFName + ' : Moderation Status = ' + moderationStatusName);

//Change DOM into div "WFStatus" to add link to start workflow + icon
if(moderationStatusName == 'Canceled') {
//Display link to start a new worklow
displayStartNewWorkflow('Workflow has been canceled. ','');
}
else if(moderationStatusName == 'Rejected') {
//Display link to start a new worklow
displayStartNewWorkflow('Workflow has been rejected. ','');
}
else if(moderationStatusName == 'Approved') {
//Document set is already approved, display a special icon with no link
displayWorkflowApproved();
}
else if(moderationStatusName == 'In Progress') {
displayWorkflowInProgress();
}
else if (moderationStatusName == '') {
//Display link to start a new worklow
displayStartNewWorkflow('','');
}
else {
onError('Unable to load workflow status.');
}
}

 

Pour récupérer le statut du Workflow, on s’appuie donc sur la colonne de statut créée par l’association du flux d’approbation à la liste/bibliothèque. C’est donc plutôt simple, il suffit d’une requête REST (que je commence à préférer au JSOM ! 🙂 )

 

3/ Quelques fonctions utiles

Voici quelques fonctions que j’ai utilisé dans mon code :


//Function to get a parameter value from QueryString
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if(results == null){
return "";
}
else{
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
}
 

//Function to manage errors
function onError(error) {
console.log('An error occured:' + error);
}

 

Et voilà !

[SP2016] – Installation de la RTM de SharePoint 2016

Posted on Updated on

Bonjour à tous,

Je l’ai déjà fait pour la Preview, la Release Candidate, c’est au tour de la RTM de SharePoint 2016.

1/ Environnement

Pour installer cette RTM, j’ai choisi d’utiliser mon contrôleur de domaine habituel (Windows Server 2008 + AD Rôle) et une nouvelle machine virtuelle sous Windows Server 2016 TP4 (4 cores, 10Go RAM, 60Go de disque).

J’avais prévu de désinstaller les précédentes installations de la Preview / RC et de réinstaller par dessus, mais trop d’erreurs à l’installation des prérequis… Il vaut mieux  repartir sur une base propre !

2/ Installation

En fait l’installation de cette RTM ne diffère pas vraiment de la précédente. Je n’ai pas vu de différence à part qu’il y n’y ait pas noté “Preview”. J’ai également eu moins de redémarrages à l’installation des prérequis, mais je pense que cela peut venir du fait que j’avais lancé les Windows Updates avant l’installation et que certains prérequis ont pu descendre avec.

 

01

 

On procède comme d’habitude à l’installation des prérequis sur le serveur (Install software prerequisites) :

02

 

On accepte les termes du contrat de licence :03

 

Et c’est parti !04

 

Après 1 seul reboot, les prérequis sont installés :05

 

On passe à l’installation de SharePoint 2016 (Install SharePoint Server) :06

 

On patiente un peu… :07

 

Enfin on entre la clé de licence Trial donnée par MS (publique, ce n’est pas la mienne hein !) :08

 

On accepte encore les termes du contrat de licence… :09

 

On choisi ensuite 2 emplacements :

  • Répertoire d’installation de SharePoint (tronc commun à tous les serveurs)
  • Répertoire d’écriture des indexes pour le moteur de recherche (Search Server) :

 

10

 

On patiente… : 11

 

C’est assez rapide (env 4 minutes) :12

 

Et comme d’habitude, on nous propose de lancer l’assistant de configuration de la ferme (PSConfig) :13

 

Et enfin on passe à la configuration de la ferme :14

 

15

 

On créé une nouvelle ferme SharePoint 2016 :16

On entre les paramètres de serveurs de base de données :

17

La Farm security Passphrase :

17.1

En enfin on choisit le rôle pour notre serveur. Étant en configuration mono-serveur, je sélectionne Single-Server Farm :

18

 

Et on choisit le port pour la Centrale d’Administration de SharePoint 2016 et le mode d’authentification : 19

 

Le résumé :20

 

Et c’est parti… on croise les doigts… :21

 

On patiente… :22

 

On re-patiente… :23

 

Et c’est terminé. Tout s’est bien passé :24

Et la central admin répond bien :26 27 28

Et voilà. C’était globalement rapide. Pas de grosse différence comparé aux installations précédentes. Il reste maintenant à tester les nouvelles fonctionnalités !

 

[SP2016] – Disponibilité de la RTM de SharePoint 2016

Posted on

Bonjour.

Stephan Goßner annonce aujourd’hui la disponibilité de SharePoint 2016 dans la version RTM (Release To Manufacturer) dans un billet sur son blog : https://blogs.technet.microsoft.com/stefan_gossner/2016/03/14/sharepoint-2016-has-been-released-to-manufacturing-rtm-ga-in-early-may/

Elle est donc téléchargeable en Trial avec ses services packs de langues. Il n’y a plus qu’à télécharger et installer !

Autre info, la disponibilité générale devrait être pour le 4 Mai !

[SharePoint 2013] – Erreur JQuery au chargement d’une page en Edit

Posted on

Bonjour,

Aujourd’hui un tips technique sur un problème constaté lors du développement d’une fonction JQuery lorsque l’on passe en Edition sur une page.

J’ai constaté cette erreur sur un site qui a été “brandé” totalement (avec un style personnalisé avancé). Au départ, mes scrollbar (verticale notamment) ne fonctionnaient plus. Et dût au conflit entre plusieurs CSS, l’astuce a été d’écrire une fonction JQuery permettant de modifier le style à la volée pour ajouter un max-height et modifier l’overflow-x sur ma page.

Le contexte ici a peu d’importance, toutefois, ce qui est intéressant, c’est que j’ai décidé d’utiliser le contrôle EditModePanel afin d’utiliser une version de cette fonction lorsque la page est en Affichage ou en mode Edition.

Pour cela, c’est assez simple (sur un site de publication), il faut ajouter une directive Register dans la masterpage du portail :


<%@ Register TagPrefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

 

Et dans la page pour le mode Affichage :


<PublishingWebControls:EditModePanel runat="server" PageDisplayMode="Display">

...

</PublishingWebControls:EditModePanel>

 

Et pour le mode Edition :


<PublishingWebControls:EditModePanel runat="server" PageDisplayMode="Edit">

...

</PublishingWebControls:EditModePanel>

Tout ceci fonctionne bien, les fonctions sont bien chargées suivant le contexte… Là ou cela se gate, c’est lorsque l’on souhaite appeler des fonctions utiles de Jquery. En effet, en mode Affichage, aucun probleme. En mode Edition, j’ai une erreur qui me dit “Object doesn’t support this property or method ready” ou “Object doesn’t support this property or method resize”.

Il se trouve, qu’apparemment, JQuery ne parviens pas à charger ces fonctions… je me suis simplement dit, en ajoutant un ExecuteOrDelayUntilScriptLoaded pour retarder le chargement de mes fonctions après sp.js, cela devrait marcher. Ou pas.

Je vous passe les multiples essais, échecs, etc. Dans le cas de l’Edition seulement, il faut appeler les fonctions de cette manière :


( function($) {
$(document).ready( function() { FixWorkspaceInEditMode()  } );

} ) ( jQuery );

 

Et donc en résumé :

 
<PublishingWebControls:EditModePanel runat="server" PageDisplayMode="Edit">  
     function FixWorkspaceInEditMode() { 
         ... 
     } 
     ( function($) { $(document).ready( function() { FixWorkspaceInEditMode()  } ); } ) ( jQuery ); 
     ( function($) { $(document).resize( function() { FixWorkspaceInEditMode()  } ); } ) ( jQuery ); 
 
</PublishingWebControls:EditModePanel> 

[SP2016] – Installation de la Release Candidate de SharePoint Server 2016

Posted on

Bonjour à tous,

Microsoft vient de mettre à disposition la Release Candidate de SharePoint Server 2016 !

Pour la télécharger, c’est par ici : https://www.microsoft.com/en-us/download/details.aspx?id=50737

Vous aurez également besoin de la procédure de mise à jour : https://technet.microsoft.com/library/mt674910%28v=office.16%29.aspx

1/ Prérequis

Pour installer la Release Candidate, vous devrez auparavant (si ce n’est pas déjà fait) installé la Bêta 2 de SharePoint Server 2016. En effet, la RC est une mise à jour de cette Bêta. Reportez-vous au post que j’ai fait sur l’installation de SP2016 (même si c’était pour la bêta 1, peu de choses changent) : https://kazoumoulox.wordpress.com/2015/08/25/sp2016-setup-preview/

Je repars donc ici de l’étape 5 de la procédure d’installation, considérant que la Bêta 2 est installée, en anglais sur une machine virtuelle (windows Server 2016 Technical Preview 4 en anglais + SQL Server 2014).

2/ Installation

Pour commencer, il faut télécharger et exécuter les prérequis pour cette Beta que vous trouverez ici : https://www.microsoft.com/en-us/download/details.aspx?id=50737

Une fois copié et dézippé sur votre machine SharePoint Server 2016 Beta 2, lancez l’exécutable prerequisiteinstaller.exe :

01

Pour ma part, cela a été très vite (quelques secondes). L’installation des prérequis est terminée :

02

 

Ensuite, il faut télécharger le Global Patch ici https://www.microsoft.com/en-us/download/details.aspx?id=50737, le copier et dézipper sur la machine virtuelle. On lance sts.msp :

03

 

L’installation commence. Cela a pris environ 10 minutes :

04

05

 

Un redémarrage de certains services est demandé (ou redémarrage de la machine) :06

 

Et l’installation continu :07

08

 

Et enfin un reboot de la machine virtuelle :09

10

Et enfin, il faut installer un pack pour la langue installée (ou toutes les langues installées), que vous trouverez ici : https://www.microsoft.com/en-us/download/details.aspx?id=50736

On copie et dézippe le fichier sur la machine virtuelle, et on lance wssmui.msp :

11

 

L’installation démarre et termine en quelques minutes : 13

14

On peut ensuite se rendre dans l’Administration centrale, les sites créés pour vérifier que tout a migré !

15Bonne journée !