SharePoint et Office 365 : résumé des évolutions en 2014

Avant de faire un point sur les attentes et les évolutions sur SharePoint et Office 365 qui devraient arriver en 2015, voici un billet de rétrospective sur les grandes annonces ou évolutions de l'année 2014 :

  1. Suppression dans Office 365 des sites publics : pressentie quelques mois avant son annonce dans la blogosphère spécialisé, les sites publics SharePoint ne seront plus proposés aux nouveaux clients et les sites existants ont encore jusqu’en Décembre 2016 pour être migrés.
  2. Retrait d’InfoPath de la gamme Office : en Janvier 2014, Microsoft créée la surprise en annonçant la fin d’InfoPath (supporté jusqu’en 2024). Cette information a énormément de répercution pour les clients et notamment pour la technologie de formulaires liées à l’écosystème Microsoft. Malgré la deadline annoncée de Q4 2014, aucune information n’a encore été donnée mais nous pouvons parier que la solution sera dans le cloud … sinon InfoPath serait encore là ! Stay tuned !
  3. Intégration de DropBox avec Office 365 : attirer ses utilisateurs vers le tout OneDrive ne se fera pas immédiatement. Ce partenariat et cette intégration fait donc sens et sera disponible dans les Office apps (puis les apps Android et iPhone, mais pour le moment pas dans les versions clients lourds même si on pourrait l’espérer), l’édition des documents Office dans DropBox et le partage de fichiers Dropbox.
  4. Arrivée de Delve/Office Graph et Groups dans Office 365 : L’arrivée de Delve et de Groups représente un grand pas dans l’usage et l’utilisation d’un portail collaboratif en entreprise. Là où certains vont trouver des redondances avec des fonctionnalités existantes, d’autres trouveront des opportunités et une nouvelle façon de travailler, et je fais partie de ces derniers.
  5. Espace OneDrive illimité : Les consommateurs et utilisateurs d'Office 365 possèdent un espace illimité pour OneDrive et OneDrive for business, et cela sans coût additionnel.
  6. Le portail Vidéo avec Office 365 : A l'instar des photos et avec l'évolution des outils vidéo, rendant plus simple leur création, la vidéo devient un média de prédilection et un vecteur de communication important pour les portails. Le nouveau service Vidéo intégré à Office 365 est là pour supporter ce nouvel usage et apporter un service "Youtube" directement dans Office 365. Compatible avec les différentes plateformes mobiles bien évidemment.

    Comment vos vidéos sont préparées et servies par le service de vidéos :

  7. Lync devient Skype for Business : un peu de rebranding ne fera pas mal, à un Lync en perte de vitesse et un Skype qui connait toujours un succès important. C'est décidé Microsoft appellera sa gamme Lync : Skype for business. Les premières interactions entre les clients Lync et Skype viennent d'être dévoilées.
  8. La roadmap officiel des déploiements de services et mise à jour d'Office 365 est disponible : afin de donner de la visilbilité et de transparence à ses clients sur l'évolution d'Office 365, Microsoft mets à disposition un site (http://roadmap.office.com/en-us) sur lequel vous y trouverez : ce qui a été déployé et ce qui va l'être prochainement, ce qui est en cours de développement et ce qui a été annulé. De quoi anticiper les évolutions, que ce soit en termes de fonctionnalités ou de services.

A très bientôt avec un prochain billet sur les attentes en 2015 sur SharePoint et Office 365.

[SharePoint 2010] Récupérer la date d’un répertoire pour mettre à jour une propriété d’un document

Un petit script prenant le nom d’un répertoire similaire à :

XYZ_110904_ABC

et permettant d’extraire la date (ici “110904”) et de la spécifier comme propriété (ici la propriété “Date de la revue”) sur les documents contenus dans le répertoire parent.

if(-not(Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}))
{
    Write-Host "Chargement de la librairie SharePoint pour PowerShell"
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}

$web = Get-SPWeb http://companyweb
$listRP = $web.Lists["Revue de presse"]

# On récupère uniquement les répertoire contenant 6 chiffres dans leur nom
$listRP.Folders | ? { $_.Name -match "(?<num>\d{6})" } | % {
    $_ -match "(?<num>\d{6})" | out-null ;
    Write-Host "Update => " $_.Name
    $year = 0;
    $month = 0;
    $day = 0;
    [System.Int32]::TryParse($matches[0].Substring(0,2), [ref] $year)
    [System.Int32]::TryParse($matches[0].Substring(2,2), [ref] $month)
    [System.Int32]::TryParse($matches[0].Substring(4,2), [ref] $day)
    $year = $year+2000 # 11 => 2011
    $revueDate = New-Object System.DateTime($year, $month, $day)
    $files = $_.Folder.Files
   foreach ($file in $files)
   {
        Write-host "Traitement du fichier ==> " $file.Name
        $file.Item["Date de la revue"] = $revueDate
        $file.Item.Update();
   }
}

Si cela peut vous sauver quelques minutes de votre longue journée !

Mettre à jour le type de contenu des documents d’une bibliothèque SharePoint 2010 avec PowerShell

Beaucoup de travail, beaucoup de nouvelles astuces à partager mais pas beaucoup de temps pour le faire, voici ce qui devrait changer dans les prochaines semaines.

Pour la reprise, voici quelques scripts PowerShell qui pourrait vous épargner quelques minutes d’écriture. Le premier très simple (je n’ai pas le niveau de notre SPAdmin préfére Fabrice69), pour changer le type de contenu de documents contenus dans un répertoire récemment migré :

if(-not(Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}))
{
    Write-Host "Chargement de la librairie SharePoint pour PowerShell"
    Add-PSSnapin Microsoft.SharePoint.PowerShell
}

$web = Get-SPWeb http://companyweb
# La liste contenant les documents à mettre à jour
$listRP = $web.Lists["Revue de presse"]

# On prend que certains répertoires (ici ceux contenant le nom de notre journal local)
$folders = $listRP.Folders | where { $_.Name -like "*LNC*" }
foreach ($folder in $folders)
{
   Write-Host "Mise à jour répertoire => " $folder.Name
   $files = $folder.Folder.Files
   foreach ($file in $files)
   {
        Write-host "Traitement du fichier ==>" $file.Name
        if ($file.Level -eq [Microsoft.SharePoint.SPFileLevel]::Checkout)
        {
            $file.CheckIn("Archiver par le système")
        }
        # Créez le type de contenu dans les types de contenu de site
        $file.Item["ID du type de contenu"] = $web.ContentTypes["Revue de Presse"].Id;
        # Champ de type choix

        $file.Item["Nom du média"] = "LNC";
        $file.Item.Update();
   }
}

Happy PS ! (Dédicace à mon coéquipier de terrain David)

Introduction à SharePoint 2010 Word Services

Voici un article qui avait tendance à prendre la poussière sur mon disque dur. Le voici donc :

Le traitement des documents bureautiques est devenu aujourd’hui un véritable enjeu stratégique pour les entreprises. Pour gérer le volume d’informations stockées dans ce type de documents et leurs échanges, les besoins d’automatisation des traitements des documents bureautiques (génération, modification en masse, consolidation des informations, conversion en PDF pour archivage, etc) deviennent de plus en plus complexes et critiques pour les entreprises.

Avant l’arrivée de Word Services au sein de la plateforme SharePoint 2010, Microsoft préconisait par le biais d’un article - http://support.microsoft.com/kb/257757 - l’utilisation de Word avec Office Automation sur un serveur de production. Bien que l’article précise que cette utilisation d’Office n’est pas une solution fiable et efficace, il détaille malgré tout comment procéder ! L’arrivée de Word Services au sein de SharePoint 2010 et du format Open XML, et de son SDK associé, devrait mettre ce type de pratique au placard. Microsoft propose enfin une solution côté serveur efficace, performante et sécurisée et allant bien au-delà de ce que propose l’utilisation d’Office client sur un serveur.

Remarque : pour les autres formats Office (Excel, PowerPoint et Visio), il existe d’autres services inclus dans SharePoint Server 2010 ; néanmoins, ces sujets dépassent le cadre de cet article.

Parmi les avantages de cette nouvelle solution, on retrouve les avantages suivants :

· Performance : Word Services a été conçu pour s’exécuter côté serveur : sans interface utilisateur à charger, sans boîte de dialogue bloquant l’exécution du traitement, … pour faire juste ce que le traitement demande et en consommant juste les ressources nécessaires. La gestion des threads et des processeurs multi cœur par le service permet d’exploiter véritablement les capacités de votre serveur pour obtenir une rapidité de loin la plus rapide du marché.

· Fiabilité et scalabilité : Le serveur n’a plus besoin de charger/décharger en mémoire une instance de Word ou d’Excel : limitation des entrées/sorties disque, charge mémoire constante et modèle objet optimisé pour un traitement serveur (le modèle objet n’est pas celui d’Office Automation). Word Services sait traiter des files importantes de documents sans problème de concurrence et de façon totalement centralisée. Enfin, ce service est compatible et respecte à 100% l’application Word client (mise en page, pagination, etc).

· Extensibilité : Word Services possède des APIs propres qui conjointement utilisé avec le SDK Open XML permet de créer des solutions sans limite.

Présentation Word Services

Vous rêvez de pouvoir générer des documents Office en masse, de convertir des documents en PDF ou XPS, de rafraichir les champs d’un document ou de convertir des documents Office en XML, HTML ou au format Open XML et plus encore ? Voici quelques possibilités de Word Services.

Le service Word ne fournit que la partie service des traitements communs décrit précédemment. Pour les traitements de modification, de consommation ou de génération de document à partir d’une logique propre (génération d’un catalogue, ajout d’un filigrane, etc) vous devrez vous orienter vers une autre API : celles du SDK Open XML. Le SDK Open XML offre une API complète pour manipuler des documents Open XML (Word, Excel et PowerPoint 2007 ou 2010), et cela sans nécessiter une quelconque instance d’Office. Conjointement utilisé avec Word Services, vous disposez d’un éventail de solutions conséquentes pour répondre aux problématiques les plus complexes que vous pouvez rencontrer dans les entreprises aujourd’hui.

Dans cet article nous allons nous pencher sur les cas utilisateur les plus courants :

· Conversion d’un document Word en PDF/XPS

· Générer un document Word

· Paginer un document

· Rafraichir les champs d’un document

Configurer son projet Visual Studio 2010

L’utilisation de Word Services dans un projet Visual Studio, dans notre cas la version 2010, nécessite l’ajout de deux assemblys : Microsoft.Office.Word.Server etSystem.Web.DataVisualization.

Ces DLLs se situent à deux endroits différents sur le disque dur. La première DLLMicrosoft.Office.Word.Server se trouve dans le répertoire 14 de SharePoint à l’emplacement suivant : C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\ Microsoft.Office.Word.Server.dll

image_47FBCB1E

La seconde DLL se situe à l’emplacement, peu commun, suivant :C:\Windows\assembly\GAC_MSIL\System.Web.DataVisualization\3.5.0.0__31bf3856ad364e35\System.Web.DataVisualization.dll

image_thumb_14EBEF1D

Une fois ajoutées ces deux assemblys, les références de votre projet devrait être proche de la capture d’écran suivante :

image_thumb_62E428C5

Les espaces de noms de Word Services

Le service Word possède plusieurs espaces de nom dans son assemblyMicrosoft.Office.Word.Server :

· Conversions : contient tous les objets nécessaires à la conversion de documents par Word Services.

· Powershell : contient les commandlet Powershell. Au moment de l’écriture de cette article avec la Beta 2, seule une commande est disponible.

· Service : permet de configurer le service Word Services.

Convertir un document Word en PDF, XPS, HTML, etc

Convertir un document est aujourd’hui aussi simple que quelques lignes de .NET grâce à Word Services, et surtout une multitude formats est supportée aussi bien en entrée qu’en sortie.

Les formats supportés en entrée sont les suivants :

  • Word 97-2003 (doc et dot) voire plus ancien
  • Office Open XML 2007-2010 (docx, docm, dotx, dotm)
  • Le RTF (Rich Text Format)
  • HTML et MHTML (page html et ressources regroupées dans un fichier unique)
  • Word 2003/2007/2010 XML

Les formats supportés en sortie de conversion sont les suivants :

  • Word 97-2003 (doc)
  • Office Open XML 2007-2010 (docx, docm)
  • Le RTF (Rich Text Format)
  • MHTML (page html et ressources regroupées dans un fichier unique)
  • Word 2007/2010 XML
  • PDF
  • XPS

L’espace de nom nécessaire pour utiliser les objets liés à la conversion de documents est Microsoft.Office.Word.Server.Conversions. Pour effectuer une ou plusieurs conversions, vous devez soumettre une tâche – un ‘job’ - au service. L’API de Word Services propose la classe ConversionJob. Son utilisation est assez simpliste une fois que vous avez référencé les DLLs nécessaire dans votre projet. Pour convertir un document Word Office open XML 2010, les quelques lignes de code qui suivent sont nécessaires :

ConversionJob job = new ConversionJob("Word Automation Services");

job.Name = "PDF archive generator";

job.UserToken = properties.Web.CurrentUser.UserToken;

job.Settings.UpdateFields = true;

job.Settings.OutputFormat = SaveFormat.PDF;

string itemUrl = properties.Web.Url + "/" + properties.ListItem.Url;

job.AddFile(itemUrl, itemUrl + ".pdf");

job.Start();

Le code ci-dessus effectue le travail de récupération de l’instance du service Word Services, du passage des droits de l’utilisateur (via le UserToken), de spécification du format de sortie et du fichier à convertir. Pour finir, vous devez appeler la méthodeStart() d’exécution de la tâche.

Comme alternative, vous pouvez également spécifier un répertoire ou une bibliothèque de documents dans son intégralité en utilisant les méthodes AddFolder() etAddLibrary().

Une fois la tâche de conversion lancée, après appel à la méthode Start(), vous pouvez demander au service l’avancement de la tâche de conversion. Pour cela, vous disposez de la classe ConversionStatus et de ses méthodes GetAllActiveJobs() et GetAllJobs().

Le code suivant permet de récupérer les statuts des tâches de conversion lancées par Word Services dans les dernières vingt-quatre heures :

public string CheckWordServicesJobsStatus()

{

StringBuilder sb = new StringBuilder();

ReadOnlyCollection<ConversionJobInfo> jobsInfo =

ConversionJobStatus.GetAllJobs("Word Automation Services", null);

if (jobsInfo.Count == 0)

return "Aucune tâche de conversion en cours";

foreach (ConversionJobInfo info in jobsInfo)

{

// On ne prend que les conversions des dernières 24 heures

if (info.SubmittedTime.AddDays(1.0).CompareTo(DateTime.Now) < 0)

continue;

ConversionJobStatus jobStatus = new ConversionJobStatus("Word Automation Services", info.JobId, null);

string s = jobStatus.Name + " - (" + jobStatus.Count + " documents) - " +

"Annulé (" + jobStatus.Canceled + ") Echoué (" + jobStatus.Failed + ") En cours (" + jobStatus.InProgress + ") Non démarré (" +

jobStatus.NotStarted + ") Réussi (" + jobStatus.Succeeded + ")<br/>";

sb.Append(s);

}

return sb.ToString();

}

L’affichage du résultat du code précédent dans une Webpart pourrait être le suivant :

image_thumb_1AA6471C

Vous pouvez annuler une tâche de conversion en faisant appel à la méthode Cancel()de la classe ConversionJob.

Pour aller plus loin

Voilà pour une première partie permettant de démarrer avec Word Services. Combiné au SDK Open XML, la puissance de Word Services devrait vous permettre de satisfaire bon nombre de vos besoins. On pourra seulement regretté le manque de synchronisation ou d’évènement de call back à la fin d’une conversion ou d’un traitement de groupe.

Insérer le numéro de version SharePoint dans un document

Une question posée aujourd’hui qui m’a laissé perplexe : comment fait-on pour intégrer le numéro de version SharePoint dans le document ? Dans un précédent post, je vous avais présenté l’insertion des propriétés serveur. Malheureusement, cette propriété n’est pas disponible dans les champs à insérer.

La démarche consiste à utiliser un type de contenu et la fonctionnalité de stratégie de gestion des informations de SharePoint Server (SP Foundation est donc exclut).

Voici une méthode permettant de contourner ce manque :

  1. Dans la bibliothèque de documents :
    1. Activer la gestion des versions
    2. Activer les types de contenu
  2. Créer un nouveau type de contenu OU modifier un type de contenu existant OU dans un type de contenu que vous avez rattaché à la bibliothèque :
    1. Aller dans ‘Paramètres de la gestion de la stratégie des informations’
    2. Activer les étiquettes
      1. Attention : ne cochez pas les deux cases juste en dessus
      2. Donner le format suivant (le format sera “Version : 0.1” par exemple) : Version : {Version}
      3. Si vous actualisez l’aperçu, vous aurez une chaine de la forme Version : {_UIVersionString} : c’est normal !
    3. Enregistrer la modification
  3. Créer ou ouvrir un document existant dans votre bibliothèque :
    1. Menu Insérer > QuickPart > Propriétés du document > Etiquette :

image_thumb_774025ED

Après enregistrement le numéro de version sera inséré :

image_thumb_44CC2CA1

Bonne lecture

Mettre à jour les administrateurs du magasin de termes avec PowerShell

S’il vous prend d’envie d’ajouter un administrateur au magasin de termes du service de métadonnées avec PowerShell, voici quelques lignes de PowerShell pour le faire (fonctionne avec SharePoint 2010 et 2013) :

    $adminSite = Get-SPSite “http://sharepoint.contoso.prod:2013

    $taxoSession = Get-SPTaxonomySession -site $adminSite

    $metadataService = Get-SPMetadataServiceApplication – Identity “Managed Metadata Service”

    $termStore = $taxoSession.TermStores[$metadataService.DisplayName]

    $termStore.AddTermStoreAdministrator(“Domain\Nom utilisateur”)

    $termStore.CommitAll()

Erreur d’analyse de contenu “L’élément SharePoint en cours d’analyse a renvoyé une erreur lors de la demande de données auprès du service Web”

Que faire lorsque l’indexation du contenu de certaines collections de sites vous renvoie : “L’élément SharePoint en cours d’analyse a renvoyé une erreur lors de la demande de données auprès du service Web. ( Error from SharePoint site: Les données sont null. Cette méthode ou propriété ne peut pas être appelée sur des valeurs Null. )” ? (à part perdre son temps à créer de nouveaux proxies de recherche, à tester toutes les configurations possibles ou encore à scruter les logs avec minutie ?)

Il s’agit d’une erreur a priori  “bien connue” de Microsoft qui la détaille dans cette KB. Mais comment une telle erreur peut-elle bien se produire ? Mauvaise configuration du service de recherche ? Une réindexation sauvage ? Un proxy de service défaillant ? Non ! Il s’agit ‘tout simplement’ d’un bug dans votre code ou de celui de votre fournisseur, en effet le service d’indexation n’aime pas avoir la description d’un groupe avec une valeur null.

Mais comment fait-on pour avoir une description null d’un groupe : en l’ajoutant avec du code et en lui spécifiant une description null. Pour faire simple, voici un exemple de code menant à cette ‘erreur’ :

using (SPSite oSite = new SPSite(textBox1.Text))
{
                    using (SPWeb oWeb = oSite.OpenWeb())
                    {
                        SPGroupCollection oGroupColl = oWeb.SiteGroups;
                        SPUser oUser = oWeb.AllUsers["domain\\user"];
                        oGroupColl.Add("Testing Group", oUser, oUser, null);

                    }
          }

La KB propose un code pour corriger cela, mais on remerciera Damien NOBLET, pour avoir créé un outil efficace qui corrigera les groupes ‘défaillants’ en tout simplicité et qui disponible sur la plateforme Codeplex :  http://sp2010fixgroups.codeplex.com/ (un grand merci pour cet outil à Damien).

Rendre un calendrier SharePoint 2010 consultable pour iPhone/iPad ou autre smartphone/tablet

Pendant vos projets SharePoint, vos utilisateurs vont ont certainement fait part qu’ils souhaitaient synchroniser un calendrier spécifique et particulièrement important avec leur iPhone ou leur iPad (que ce soit en interne ou en extérieur). Néanmoins, L’iPhone ne sait pas le faire pas naturellement : rien de plus simple qu’une publication au format iCalendar pour palier au problème !

Pour faire face à cette situation, direction Visual Studio 2010 (avec Nuget installé) ou 2012 (mieux !) :

  1. Créez un nouveau projet SharePoint vide
  2. Ajoutez le package DDay.iCal à votre projet (que vous pouvez trouver ici :http://nuget.org/packages/DDay.iCal) qui va nous permettre de générer simplement la sortie iCal
  3. Créez un fichier handler .ashx et copier (en l’adaptant à votre environnement) suivant :

<%@ Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="Contoso.iCal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5d957034fc68cb87" %>
<%@ WebHandler Language="C#" Class="Consoto.iCalPublisher.Agenda" %>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Noumea.iCal;
using Microsoft.SharePoint;

namespace Contoso.iCalPublisher
{
    public class Agenda : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            iCalCalendar cal = new iCalCalendar();

            using (SPSite site = new SPSite("http://demo.contoso.nc/managers/"))
            {
                using (SPWeb web = site.RootWeb)
                {
                    // Récupération du calendrier à publier en iCal
                    SPList calManager = web.Lists.TryGetList("Agenda Managers");
                    if (calManager != null)
                    {
                        // Filtrage par rapport à un type de contenu et ne récupère que les 15 derniers jours d'évènements antérieurs à la date du jour
                        SPQuery query = new SPQuery();
                        query.Query = string.Concat(
                                "<Where><And><Eq><FieldRef Name='ContentType'/><Value Type='Text'>Evènement Manager</Value></Eq><Geq><FieldRef Name='EndDate' /><Value Type='DateTime'><Today OffsetDays='-15' /></Value></Geq></And></Where>");
                        SPListItemCollection listItems = calManager.GetItems(query);
                        // On exporte tous les évènements récupérés en iCal
                        foreach (SPListItem item in listItems)
                        {
                            iCalEvent evt = new iCalEvent();
                            evt.DateBegin = DateTime.Parse(item["EventDate"].ToString());
                            evt.DateEnd = DateTime.Parse(item["EndDate"].ToString());
                            evt.Description = item["Title"].ToString();
                            evt.Location = item["Location"] != null ? item["Location"].ToString() : "";
                            cal.Events.Add(evt);
                        }
                    }
                }
            }

            byte[] arrBytData = cal.Serialize();
            context.Response.Clear();
            context.Response.ContentType = "text/plain";
            // Pour éviter le cache
            context.Response.AppendHeader("Pragma", "no-cache");
            context.Response.AppendHeader("Expires", "Sat, 05 Jul 2010 05:00:00 GMT");
            context.Response.AppendHeader("Content-Disposition", "attachment; filename=CalendrierManager.ics");
            context.Response.AppendHeader("Content-Length", arrBytData.Length.ToString());
            context.Response.ContentType = "text/calendar";
            context.Response.BinaryWrite(arrBytData);
            context.Response.Flush();
            context.Response.End();
            context.Response.Close();
        }
    }
}

That’s all folks ! Bien évidemment la sécurité fonctionne à merveille (authentification requise).

Créer une webpart de génération de sommaire automatique des titres d’une page de publication pour le publishing de SharePoint 2010

Voici un petit bout de code rapide pour réaliser un sommaire des titres (H1) dans une page de publication assez longue, avec un retour vers le sommaire sous le titre :

var WebPart_SommaireAncres_Variable_Sommaire_CodeRetourSommaire = "<div class='WebPart_Sommaire_RetourSommaire'><a class='WebPart_Sommaire_RetourSommaire_a' href='#Sommaire'>Retour Sommaire</a><img class='WebPart_Sommaire_RetourSommaire_img' src='/_layouts/DemoCorp/images/WebPart_Sommaire_Fleche-Haut.png' /></div>"

jQuery(document).ready(function () {

    var divMainResize = document.getElementById('MainResize');

    /* Ajout des ancres sur les H1 */
    var divh1Array = divMainResize.getElementsByTagName('h1');
    for (var i = 0; i < divh1Array.length; i++) {
        // Ajoute l'id qui permet au menu d'identifier le titre
        jQuery(divh1ArrayIdea).attr("id", "sommaireIndex" + i);
        // Ajoute le lien de retour vers le sommaire
        jQuery(divh1ArrayIdea).after(WebPart_SommaireAncres_Variable_Sommaire_CodeRetourSommaire);
    }

    /* Ajout du sommaire */
    var elSommaire = jQuery("<a name='Sommaire'></a>");
    jQuery(divMainResize).prepend(elSommaire);
    // Génération du sommaire
    var elContenuSommaire = jQuery("<div id='WebPart_Sommaire'></div>").appendTo(elSommaire);
    jQuery("<h1 class='WebPart_Sommaire_h1'>Sommaire</h1>").appendTo(jQuery(elContenuSommaire));
    var elSommaireListe = jQuery("<ul class='WebPart_Sommaire_Liste_Lien_ul'></u>");
    jQuery(elSommaireListe).appendTo(jQuery(elContenuSommaire));
    for (var i = 1; i < divh1Array.length; i++) { // Début à 1 car nous ajoutons un H1 avec le titre du sommaire
        var contenuLi = jQuery("<li class='WebPart_Sommaire_Liste_Lien_li'></li>");
        jQuery(contenuLi).appendTo(elSommaireListe);
        var contenuLinkLi = jQuery("<a class='WebPart_Sommaire_Liste_Lien_a' href='#sommaireIndex" + (i - 1).toString() + "'>" + divh1ArrayIdea.innerHTML + "</a>");
        jQuery(contenuLinkLi).appendTo(contenuLi);
    }
});

Avec un peu de CSS et des images cela devrait rendre quelque chose de pas mal du tout !

SharePoint 2010 : Gérer la planification des pages de publication

Un petit bout de code pour gérer planifier des pages de publication :

SPList list=web.Lists["Pages"];
SPListItem item = list.GetItemById(…); // Récupération de l’élément à planifier

if (ScheduledItem.IsScheduledItem(item))
{
   ScheduledItem scheduledItem = ScheduledItem.GetScheduledItem(listItem);
   DateTime startDate = DateTimeNow;
   DateTime endDate = new DateTime(2013, 12, 31, 23, 59, 00);
   scheduledItem.StartDate = startDate;
   scheduledItem.EndDate = endDate;
   scheduledItem.ListItem.Update();
   scheduledItem.Schedule();
}