Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Blog Technique de Romelard Fabrice

Les dernières Actualités de Romelard Fabrice (Alias fabrice69 ou F___) principalement autour des technologies Microsoft

Actualités

  • Toutes les actualités et informations sur les technologies Microsoft principalement autour de .NET et SQL Server

Archives

SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection

Dans la gestion de collection de sites SharePoint avec un grand nombre de sous-sites, il peut être utile de pouvoir nettoyer des colonnes ajoutées par mégarde.

Ainsi le script suivant permet de supprimer une colonne spécifiée de tous les type de contentu des librairies “Pages” de tous les sous-sites de la collection.

Libre à vous de l’adapter à votre convenance.

[string]$username = "Admin@yourtenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd

[string]$RootSiteToCheck = "https://yourtenant.sharepoint.com/sites/YourSiteCollection"
[string]$SPListToCheck = "Pages"
[string]$SPFieldInternalNameToCheck = "PublishedDate"

function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""
    # Load assemblies to PowerShell session
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}

function Check-And-Fix-Field-In-SPList ([Microsoft.SharePoint.Client.ClientContext]$Context, [Microsoft.SharePoint.Client.Web]$CurrentWeb)
{
    $MyCurrentListTocheck = $CurrentWeb.Lists.GetByTitle($SPListToCheck)
    $AllSPListCT = $MyCurrentListTocheck.ContentTypes
    $Context.Load($MyCurrentListTocheck)
    $Context.Load($AllSPListCT)
    $Context.ExecuteQuery()
    Write-Host "  ===>>> SubSite to check:", $CurrentWeb.Title, "- URL:", $CurrentWeb.Url -ForegroundColor Green
    Write-Host "  ===>>> List to check:", $MyCurrentListTocheck.Title -ForegroundColor Green
    foreach($MySpListCT in $AllSPListCT)
    {
        Write-Host "         -->> Content Type Name:", $MySpListCT.Name
        Write-Host "         -->> Content Type ID:", $MySpListCT.id
        $Myfields = $MySpListCT.Fields
        $Context.Load($Myfields)
        $Context.ExecuteQuery()
        $MyfieldToCheck = ($Myfields | where {$_.InternalName -eq $SPFieldInternalNameToCheck})
        if($MyfieldToCheck -ne $null)
        {
            Write-Host "             ---------------------------------------------- " -ForegroundColor Yellow
            Write-Host "             >>>> Field Name:", $MyfieldToCheck.Title -ForegroundColor Yellow
             Write-Host "             >>>> Field InternalName:", $MyfieldToCheck.InternalName, "- Field ID:", $MyfieldToCheck.id -ForegroundColor Yellow
            Write-Host "             >>>> Field Required:", $MyfieldToCheck.Required -ForegroundColor Yellow
            Write-Host "             ---------------------------------------------- " -ForegroundColor Yellow
            $MyfieldToCheck.DeleteObject();
            $MySpListCT.Update($false);
            $Context.Load($MySpListCT);
            $Context.ExecuteQuery()
            Write-Host "             >>>> Field Deleted !!!!" -ForegroundColor Red
        }
    }
}

function Get-SPOSubWebs
{
    Param(
        [Microsoft.SharePoint.Client.ClientContext]$Context,
        [Microsoft.SharePoint.Client.Web]$RootWeb
    )
    $Webs = $RootWeb.Webs
    $Context.Load($Webs)
    $Context.ExecuteQuery()
    ForEach ($sWeb in $Webs)
    {
        Write-host "   ====>> SubSite:", $sWeb.URL -ForegroundColor red
        Check-And-Fix-Field-In-SPList $Context $sWeb
        Get-SPOSubWebs -RootWeb $sWeb -Context $Context
    }
}

cls
Write-Host " ---------------------------------------------- "
Load-DLLandAssemblies
Write-Host " ---------------------------------------------- "
Write-host "==================================================================” -ForegroundColor Green
$mySitectx = New-Object Microsoft.SharePoint.Client.ClientContext($RootSiteToCheck)
$mySitectx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($adminCreds.UserName, $adminCreds.Password)
$mySitectx.RequestTimeout = 1000000 # milliseconds
$myCurrentWeb = $mySitectx.Web
$mySitectx.Load($myCurrentWeb)
$mySitectx.ExecuteQuery()
Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $mySitectx.ServerVersion " # <<<<<<" -ForegroundColor Green
Write-Host " ---------------------------------------------------------"
Write-Host " "
Write-host "=================================================================="
Write-host "   -->> RootSite:", $myCurrentWeb.URL -ForegroundColor green
Write-host "=================================================================="
Check-And-Fix-Field-In-SPList $mySitectx $myCurrentWeb
Get-SPOSubWebs $mySitectx $myCurrentWeb
Write-host "=================================================================="

Fabrice Romelard

Version anglaise:

Sources utilisées:

Office 365: Script PowerShell pour supprimer des comptes utilisateur de collections de sites SharePoint Online

Le moteur de gestion des utilisateur de SharePoint Online est bien basé sur le core system de SharePoint, en l’occurence les SPUsers.

Cette liste intermédiaire est visible d’ailleurs par l’URL:

Le soucis est la suppression d’un compte utilisateur de cette base intermédiaire, car aucune interface ne permet cette suppression hormis la commande PowerShell suivante:

Le script suivant vous aide donc à effectuer ce nettoyage dans les collections de sites que vous souhaitez (selon les filtrages appliqués à la commande Get-SPOSite):

[string]$username = "AdminAccount@yourTenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
[string]$SiteCollectionURL = "
https://yourTenant.sharepoint.com"

[string]$LoginAccounttoRemove = "i:0#.f|membership|User.Login@yourTenant.com"

function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}

   
cls
Write-host " ------------------------------------------------------------ "
Write-host "    Removing Specific Account from specific Site collection   "
Write-host " -----------------------------------------------------------  "

Load-DLLandAssemblies

$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd

Connect-SPOService -Url https://yourTenant-admin.sharepoint.com -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

#Retrieve all site collection infos
#$sitesInfo = Get-SPOSite -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select *
#$sitesInfo = Get-SPOSite  -Filter  {Url -like "
https://yourTenant.sharepoint.com/sites/YourSiteCollection"}  -Limit ALL | Sort-Object -Property url | Select *
$sitesInfo = Get-SPOSite -Template "BLANKINTERNET#0" -Limit ALL | Sort-Object -Property url | Select *

[int]$i = 1;

Write-host " ===>>>   ", $sitesinfo.count + " site collections found." -ForegroundColor green

foreach ($site in $sitesInfo)
{
    $CheckUser = $null
    Write-host " ------------------------------------------------------------ "
    Write-host "SiteColl Number:", $i, "- of:", $sitesInfo.Count -ForegroundColor green
    $i += 1;
    Write-Host "SPO Site collection:", $site.Url, "- Title:", $site.Title -ForegroundColor magenta
    Write-Host "   => External Sharing:", $site.SharingCapability
    Write-Host "   => Site Template Used:", $site.Template

    $CheckUser = Get-SPOUser -Site $site.Url -LoginName $LoginAccounttoRemove

    if($CheckUser.count -gt 0)
    {
        write-Host "  >>>> Removing User Account:", $LoginAccounttoRemove -ForegroundColor magenta
        $CheckUser | Format-Table
        Remove-SPOUser -Site $site.Url -LoginName $LoginAccounttoRemove
    }
    else
    {
        write-Host "  >>>> User Account", $LoginAccounttoRemove, "does not exist into the site collection:", $site.Url -ForegroundColor Yellow
    }
    Write-host " ------------------------------------------------------------ "

}

Vous pouvez bien sur modifier ce script selon votre besoin.

Fabrice Romelard

Version anglaise:

Sources:

Office 365: Script PowerShell pour extraire les Teams associés à un utilisateur spécifié

Une question basique dans le cadre de la gestion de tenant Office 365 Teams est de connaitre les information pour les Teams sur lequel un utilisateur a les droits.

Une solution est de passer à travers le module PowerShell pour Teams:

Bien que limité dans les options disponibles le script suivant vous permet d’extraire les informations pour un utilisateur donné. Pour cela il vous faudra un compte avec des privilèges élevés et une license Office 365 teams.


Import-Module MicrosoftTeams

#$cred = Get-Credential
#$username = $cred.UserName
#Connect-MicrosoftTeams
#Get-Command -Module MicrosoftTeams

[string]$username = "YourAdminAccount@yourdomain.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

Connect-MicrosoftTeams -Credential $cred


[string]$LoginToUser =  "LogintoCheck@yourdomain.com"

Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-Host " => Login to check for the Teams:", $LoginToUser  -ForegroundColor Green

$ListOfMyTeams = Get-Team  -user $LoginToUser

foreach($MyTeams in $ListOfMyTeams)
{
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-Host "    ===-> Teams Name:", $MyTeams.GroupId, "- Name:", $MyTeams.DisplayName, "- Description:", $MyTeams.Description  -ForegroundColor Yellow
   
    Write-Host "    ===-> Get-TeamFunSettings:" -ForegroundColor Yellow
    Get-TeamFunSettings -GroupId $MyTeams.GroupId

    Write-Host "    ===-> Get-TeamGuestSettings:" -ForegroundColor Yellow
    Get-TeamGuestSettings -GroupId $MyTeams.GroupId

    Write-Host "    ===-> Get-TeamMemberSettings:" -ForegroundColor Yellow
    Get-TeamMemberSettings -GroupId $MyTeams.GroupId

    Write-Host "    ===-> Get-TeamMessagingSettings:" -ForegroundColor Yellow
    Get-TeamMessagingSettings -GroupId $MyTeams.GroupId

    Write-Host "    ===-> Get-TeamUser:" -ForegroundColor Yellow
    Get-TeamUser -GroupId $MyTeams.GroupId  | Format-Table
   

    $MyListOfChannelList = Get-TeamChannel -GroupId $MyTeams.GroupId
    foreach($MyChannel in $MyListOfChannelList)
    {
     
        Write-host "      ------------------ " -ForegroundColor green
        Write-Host "      ===-> Channel Name:", $MyChannel.Id, "- Name:", $MyChannel.DisplayName, "- Description:", $MyChannel.Description  -ForegroundColor Magenta
       
        #$MyChannel | Get-Member
   
    }

    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
}

Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green


Si vous souhaitez des options plus avancées, il vous faudra regarder Office Graph pour cela.

Fabrice Romelard

Version Anglaise:

Sources utilisées pour le script:

Office 365: Extraire les pages publiées dans un site SharePoint Online de publishing en CSV

Lorsque votre site est basé sur un modèle de site publishing avec une arborescence complexe avec de nombreux sous-sites:

  • Chaque département possède son sous-site
  • Différenciation entre les régions, les pays, … (forme de treeview)
  • Différence entre business et fonction

On se retrouve rapidement avec un très grand nombre de sous-sites dans lesquels sont publiées des pages et news.

La seule solution pour afficher celles-ci est d’utiliser le moteur de recherche en travaillant avec les queries adaptées.

Cela devient rapidement problématique pour répondre à des questions basiques de statistiques telles que:

  • Quel est le département publiant le plus de pages ?
  • Quel est le nombre de pages publiées par mois ?
  • Qui est le content manager le plus actif ?

La seule solution alors est de passer par un export de l’ensemble des pages publiées en CSV et de travailler la présentation de ces statistiques avec Excel (ou PowerBI).

Le script suivant vous permet ce travail en adaptant simplement les requêtes et les colonnes à sortir:


[string]$SitePagesURL = "
[DateTime]$PortalPublishingDate = Get-Date
[string]$CSVFileName = "ExportAllNewsItems.csv"

[string]$queryText = "ContentTypeId:0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D00DAB155038B062847A409F1E450E9E5E3*  Path:https://yourtenant.sharepoint.com/intranet "
[string]$outputline = ""

[int]$TempUserID = 0

# ---------------------------------------------------------------------------------------------------------------
function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.Client.Search\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.Search.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

}

function Get-SearchResults([int] $startIndex, $myclientContext)
{
    try
    {
        $keywordQuery = New-Object Microsoft.SharePoint.Client.Search.Query.KeywordQuery($MyctxTemp)
        $keywordQuery.StartRow = $startIndex #gets or sets the first row of information from the search results
        $keywordQuery.QueryText = $queryText
        $keywordQuery.RowLimit = 500
        $keywordQuery.RowsPerPage = 500
        $keywordQuery.TrimDuplicates=$false 
        $keywordQuery.Timeout = 10000;
        $keywordQuery.SelectProperties.Add("LastModifiedTime")
        $keywordQuery.SelectProperties.Add("RefinableDate00")   # Date Article
        $keywordQuery.SelectProperties.Add("RefinableString00") # Business & Function
        $keywordQuery.SelectProperties.Add("RefinableString01") # News Type
        $keywordQuery.SelectProperties.Add("RefinableString03") # Publishing Area / Country
        $keywordQuery.SelectProperties.Add("CreatedBy")
        $keywordQuery.SortList.Add("RefinableDate00","Desc")

        $searchExecutor = New-Object Microsoft.SharePoint.Client.Search.Query.SearchExecutor($MyctxTemp)
       
        $ClientResult = $searchExecutor.ExecuteQuery($keywordQuery)
         $MyctxTemp.ExecuteQuery()
        #$MyctxTemp.ExecuteQueryWithIncrementalRetry(5, 30000); #5 retries, with a base delay of 30 secs.
       
        Write-Host "         - Item number into the function:", $ClientResult.Value[0].ResultRows.Count
                
        return $ClientResult.Value[0]

    }
    Catch [Exception] {
        Write-host " >>>> ERROR MESSAGE:", $_.Exception.Message -f Red
        Return $False
    }       

}

# ---------------------------------------------------------------------------------------------------------------
Function Get-All-Intranet-News-Published-ExportCSV($MyctxTemp, $MyspoRootwebTemp)
{
    [System.Data.DataTable]$resultDataTable = new-object System.Data.DataTable("SGSWORLDNEWS")
    [System.Data.DataColumn]$titleCol = new-object System.Data.DataColumn("Title")
    [System.Data.DataColumn]$pathCol = new-object System.Data.DataColumn("Path")
    [System.Data.DataColumn]$RefinableDate00Col = new-object System.Data.DataColumn("RefinableDate00")
    [System.Data.DataColumn]$RefinableString00Col = new-object System.Data.DataColumn("RefinableString00")
    [System.Data.DataColumn]$RefinableString01Col = new-object System.Data.DataColumn("RefinableString01")
    [System.Data.DataColumn]$RefinableString03Col = new-object System.Data.DataColumn("RefinableString03")
    [System.Data.DataColumn]$CreatedByCol = new-object System.Data.DataColumn("CreatedBy")

    $resultDataTable.Columns.Add($titleCol)
    $resultDataTable.Columns.Add($pathCol)
    $resultDataTable.Columns.Add($RefinableDate00Col)
    $resultDataTable.Columns.Add($RefinableString00Col)
    $resultDataTable.Columns.Add($RefinableString01Col)
    $resultDataTable.Columns.Add($RefinableString03Col)
    $resultDataTable.Columns.Add($CreatedByCol)
   
    [int]$currentRowIndex = 0
    $resultTable = Get-SearchResults $currentRowIndex $MyctxTemp
    Write-Host "  >> Total Rows Include Duplicated:",         $resultTable.TotalRowsIncludingDuplicates -ForegroundColor Red
   
    if(($resultTable -ne $null) -and ($resultTable.TotalRowsIncludingDuplicates -gt 0))
    {
        while ($resultTable.TotalRowsIncludingDuplicates -gt $resultDataTable.Rows.Count)
        {
            foreach($resultRow in $resultTable.ResultRows)
            {
                [System.Data.DataRow]$myrow = $resultDataTable.NewRow()
                $myrow["Title"] = $resultRow["Title"]
                $myrow["Path"] = $resultRow["Path"]
                $myrow["RefinableDate00"] = $resultRow["RefinableDate00"]
                $myrow["RefinableString00"] = $resultRow["RefinableString00"]
                $myrow["RefinableString01"] = $resultRow["RefinableString01"]
                 $myrow["RefinableString03"] = $resultRow["RefinableString03"]
                $myrow["CreatedBy"] = $resultRow["CreatedBy"]
                $resultDataTable.Rows.Add($myrow)
            }
           
            $currentRowIndex = $resultDataTable.Rows.Count
           
            $resultTable = $null
             $resultTable = Get-SearchResults $currentRowIndex $MyctxTemp
            if (($resultTable -ne $null) -and ($resultTable.TotalRowsIncludingDuplicates -gt 0))
            {
                if ($resultTable.RowCount -le 0)
                {
                     break
                }
            }
            else
             {
                break
            }
        }
    }
     [string] $totalResults = $resultDataTable.Rows.Count;
    Write-Host "     >>>>> Table Items placed into Datatable: ", $totalResults -ForegroundColor Yellow

    Clear-Content $CSVFileName
     $outputline = '"NewsTitle";"PublicationDate";"NewsURL";"BusinessFunction";"NewsType";"PublishingAreaCountry";"NewsCreator";'
    Add-Content -Encoding UTF8 -Force $CSVFileName $outputline  

    foreach($result in $resultDataTable.Rows)
    {
        if($result["RefinableDate00"] -ne "")
        {
            $TempString = $result["RefinableDate00"].split(';')[0]
            $PortalPublishingDate=[datetime]::ParseExact([string]$TempString, 'M/d/yyyy h:mm:ss tt', [CultureInfo]::InvariantCulture) #10/2/2018 10:00:00 PM
    
            Write-Host "  ---------------------------------------- "
            Write-Host " ------>>> NewsPath:", $result["Path"]
            Write-Host " ------>>> Title:", $result["Title"]
            Write-Host " ------>>> RefinableDate00:",  $result["RefinableDate00"] #$PortalPublishingDate
             Write-Host " ------>>> PublicationDate:",  $PortalPublishingDate
            Write-Host " ------>>> BusinessFunction:", $result["RefinableString00"]
            Write-Host " ------>>> NewsType:", $result["RefinableString01"]
            Write-Host " ------>>> PublishingAreaCountry:", $result["RefinableString03"]
            Write-Host " ------>>> NewsCreator:", $result["CreatedBy"]
            Write-Host "  ---------------------------------------- "

            #CSV file location, to store the result
            $outputline = '"'+ $result["Title"] +'";"'+ $PortalPublishingDate.ToString("dd.MM.yyyy") +'";"'+ $result["Path"] +'";"'+ $result["RefinableString00"] +'";"'+ $result["RefinableString01"] +'";"'+ $result["RefinableString03"] +'";"'+ $result["CreatedBy"] +'";'
            Add-Content -Encoding UTF8 -Force $CSVFileName $outputline
        }
    }
}

# ---------------------------------------------------------------------------------------------------------------
Load-DLLandAssemblies

#get and save your O365 credentials
[string]$username = "loginadmin@yourtenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

#connect to the web site using the stored credentials
Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
Write-host "   CONNECTED SITE:", $SitePagesURL  -ForegroundColor Yellow

$Myctx = New-Object Microsoft.SharePoint.Client.ClientContext($SitePagesURL +"/intranet")

$Myctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
$Myctx.RequestTimeout = 1000000 # milliseconds
$MyspoRootweb = $Myctx.Web
$Myctx.Load($MyspoRootweb)
$Myctx.ExecuteQuery()

Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $Myctx.ServerVersion " # <<<<<<" -ForegroundColor Green
Write-Host " ---------------------------------------------------------"
Write-Host " "

Write-host " -------------------------------------------------------- "
Write-host "   -->> RootSite:", $MyspoRootweb.URL -ForegroundColor green

Write-host " "

Get-All-Intranet-News-Published-ExportCSV $Myctx $MyspoRootweb


Ce script a été utilisé en production avec des milliers de news publiées et permet une présentation plus précise de l’activité des contributeurs au sein de la plateforme.

Fabrice Romelard

Version Anglaise:

Les sources utilisées pour la construction:

Office 365: Comment créer un jeu de Pages Modernes dans un Modern Site SharePoint Online en utilisant PowerShell depuis un fichier CSV

Dans de nombreux cas, les pages modernes sont très pratiques pour un site d’aide en ligne, alors que dans le passé la réponse classique à ce besoin était de passer par des Site Wiki et les WikiPages

Les avantages d’utiliser les Modern Pages

Dans Office 365 SharePoint Online. l’implémentation des pages modernes entraine de nombreuses fonctionnalités natives simplifiant la vie des gestionnaires de contenu et la navigation de l’utilisateur final, telles que:

  • Présentation moderne des pages
  • Les composant disponibles Modern WebPart
  • L’intégration des pages modernes dans le composant Modern News WebPart
  • Agrégation des pages modernes dans les Communication Hub Site
  • Agrégation des pages modernes dans les application natives SharePoint (Web et Mobile)
  • Adaptation de la présentation pour tous les appareils sans aucun développement aditionnel
  • ...

C’est aussi un besoin vital de se caller à la stratégie de Microsoft et l’usage des Wiki Site/Pages n’est plus du tout dans cet axe d’évolution.

Présentation du Business Case

Ce script s’inscrit dans un besoin particulier correspondant aux demandes suivantes:

  • Pour chaque tâche de travail d’une checklist business, créer une page de présentation de cette tâche
  • Grouper les tâches par groupe dans la navigation de gauche
  • Implementer dans chacune des pages un fond de page basique préchargé
  • Automatiser la création des pages et des menus

Le fichier CSV doit contenir les éléments suivant en colonne:

  • CHECKID: en text semblable "1.01", qui sera utilisé pour le nom du fichier de page"1.01.aspx"
  • CHECKNAME: en texte avec le nom de la tâche semblable "Collect data from the business line"
  • CHECKTOPIC: en texte semblable à "01. BASICS TASKS"

Une image générique par groupe de tâche doit être placée dans la librairie de fichiers “SiteAsset” du site courant sous le format "$(CHECKTOPIC).JPG".

Une fois le site exécuté, chaque responsable de tache doit éditer et compléter les détails de la tâche comme suit:


Task Title: Collect the Data from the Business

Topic:
  • 01. BASIC TASKS
Description:

Get all the data from the business line to be sure the mission is ready to start

Estimated Time:
  • Some minutes
Person in charge:
  • Task Manager
Starting time:
  • When the mission is started

PowerShell script:

Le script peut être utilisé tel que ou adapté à votre besoin:


$HelpAndQAUrl = "https://[YourTenant].sharepoint.com/sites/SiteCollection/helpsite"
$CSVFilePath = "C:\Business-CheckList.csv"

##Connecting to site - get and save your O365 credentials
[string]$username = "Admin@YourTenant.onmicrosoft.com"
[string]$PwdTXTPath = "D:\FINAL\SHAREPOINT\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

# ---------------------------------------------------------------------------------------------------------------

[string]$TextTemplateToPut = ""
[string]$pageFilename = ""
[string]$pageFileTitle = ""
[string]$PageTopic = ""
[string]$PageTitleFull = ""
[string]$pageFilename = ""
[string]$PageTitleToUpdate = ""
[int]$ParentNodeID = 0
[int]$PageNodeID = 0

# ---------------------------------------------------------------------------------------------------------------
#GET CSV File
$AllPagesToCreate = Import-Csv -Path $CSVFilePath

# --------------------------------------------------------------------------------------------
#Loop for each line
foreach ($PageToCreate in $AllPagesToCreate)
{
    # ---------------------------------------------------------------------------------------------------------------
    Write-host " ==> Page ID", $PageToCreate.CHECKID, "- Name:", $PageToCreate.CHECKNAME , "- Topic:", $PageToCreate.CHECKTOPIC -ForegroundColor Yellow
    # ---------------------------------------------------------------------------------------------------------------

    $pageFileTitle = $PageToCreate.CHECKID
    $PageTopic = $PageToCreate.CHECKTOPIC
    $PageTitleFull = $PageToCreate.CHECKNAME
    if($PageTitleFull.IndexOf("(") -gt 0)
    {
        $PageTitleShort = $PageTitleFull.Substring(0, $PageTitleFull.IndexOf("("))
    }
    else
    {
        $PageTitleShort = $PageTitleFull
    }
    $pageFilename =  -join($pageFileTitle, ".aspx")

    $TextTemplateToPut = "<h2>Task Title: $($PageTitleFull)</h2>"
    $TextTemplateToPut += "<h3>Topic:</h3><ul><li>$($PageTopic)</li></ul>"
    $TextTemplateToPut += "<h3>Description:</h3><p>&nbsp;</p><p>&nbsp;</p>"
    $TextTemplateToPut += "<h3>Estimated Time:</h3><ul><li>&nbsp;</li></ul>"
    $TextTemplateToPut += "<h3>Person in charge:</h3><ul><li>&nbsp;</li></ul>"
    $TextTemplateToPut += "<h3>Starting time:</h3><ul><li>&nbsp;</li></ul><p>&nbsp;</p>"

    $PageTitleToUpdate = -join($pageFileTitle, " - ", $PageTitleShort)
    $ParentNodeID = 0
    $PageNodeID = 0

    Write-host " "
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-host " ---- START THE PAGE CREATION:", $pageFileTitle, "-", $pageFilename -ForegroundColor green
    Write-host " ---- Page Title Full:", $PageTitleFull -ForegroundColor green
    Write-host " ---- Page Title Short:",  $PageTitleShort -ForegroundColor green
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green

    # ---------------------------------------------------------------------------------------------------------------
    #connect to the web site using the stored credentials
    Write-host " "
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
    Write-host "   CONNECTED SITE:", $HelpAndQAUrl  -ForegroundColor Yellow
    Connect-PnPOnline -Url $HelpAndQAUrl -Credential $cred
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    $checkpage = Get-PnPClientSidePage -Identity $pageFilename -ErrorAction SilentlyContinue

    if($checkpage -eq $null)
    {
        Write-Host "  >>>  Page does not exist or is not modern"
        $page = Add-PnPClientSidePage -Name $pageFilename -LayoutType "Article"
    }
    else
    {
         Write-Host "  >>> We have a modern page present"
        $page = $checkpage
    }
    #Add text webpart to page
    Add-PnPClientSideText -Page $page -Text $TextTemplateToPut
    Set-PnPClientSidePage -Identity $page -LayoutType "Article" -Title $PageTitleToUpdate

    $page = Get-PnPClientSidePage -Identity $pageFilename -ErrorAction SilentlyContinue

    Write-host "   ==>> PAGE HEADERS ImageServerRelativeUrl:", $page.PageHeader.ImageServerRelativeUrl  -ForegroundColor Green
    $ctx = Get-PnPContext
    Write-host "   ==>> WEB Relative URL:", $ctx.Web.ServerRelativeUrl  -ForegroundColor Yellow
    $mySiteRelativeURL = $ctx.Web.ServerRelativeUrl
    $myPageRelativeURL = -join($mySiteRelativeURL, "/", $page.PagesLibrary, "/", $pageFilename)
    Write-host "   ==>> PAGE Relative URL:", $myPageRelativeURL  -ForegroundColor Yellow

    $page.PageHeader.ImageServerRelativeUrl = $mySiteRelativeURL +"/SiteAssets/$($PageTopic).JPG"
    $page.Save()
    $page.Publish()

    Get-PnPConnection
    $AllQuicklaunchNodes = Get-PnPNavigationNode

    foreach($MyNode in $AllQuicklaunchNodes)
    {
        if($MyNode.Title -eq $PageTopic)
        {
             Write-host "   ->>>>  PARENT - MenuNode Title:", $MyNode.Title, "- ID:", $MyNode.ID  -ForegroundColor Yellow
             $ParentNodeID = $MyNode.ID
        }
        else
        {
             Write-host "   - MenuNode Title:", $MyNode.Title, "- ID:", $MyNode.ID  -ForegroundColor Green
        }
    }
    if($ParentNodeID -eq 0)
    {
        Write-host "               ===>>>>  TOPIC LINK NOT EXIST, Need to create it"  -ForegroundColor Red
        $AddMyNode = Add-PnPNavigationNode -Title $PageTopic -Url $mySiteRelativeURL -Location "QuickLaunch"
        $ParentNodeID = $AddMyNode.Id
    }
   
    $Topicnodes = Get-PnPNavigationNode -Id $ParentNodeID   
    foreach($MyPageNode in $Topicnodes.Children)
    {
        if($MyPageNode.Title -eq $PageTitleToUpdate)
        {
            Write-host "            ->>>>  PAGE NODE EXIST- MenuNode Title:", $MyPageNode.Title, "- ID:", $MyPageNode.ID  -ForegroundColor Red
            $PageNodeID = $MyPageNode.ID
        }
        else
        {
            Write-host "            ->>>>  PAGE NODE - MenuNode Title:", $MyPageNode.Title, "- ID:", $MyPageNode.ID  -ForegroundColor green
         }
    }
    if($PageNodeID -eq 0)
    {
        $AddMyNode = Add-PnPNavigationNode -Title $PageTitleToUpdate -Url $myPageRelativeURL -Location "QuickLaunch" -Parent $ParentNodeID
    }
}


Résultat:

La page d’accueil du site peut alors être configurée pour présenter les dernières pages publiées via la WebPart Modern News

Untitled-HelpPageCreated-02

Pour chaque tâche on trouvera le résultat présenté:

Untitled-HelpPageCreated-01

Exécution Post creation

Cet autre script peut être utilisé par la suite pour adapter les pages du site avec le personnes ayant édité ces pages (responsables de tâches) et présenter ces information correctes dans la webpart:

Conclusion

Ce script a été utilisé de nombreuses fois pour créer des centaines de pages de manière industrielle.

Romelard Fabrice

English version published:

Office 365: Comment Utiliser les Modern Pages dans un Site Intranet SharePoint basé sur le Publishing site

Microsoft est plus rapide que les organisations dans son changement de stratégie et le passage de toute la solution SharePoint à la sauce Moderne entraine quelques soucis.

En effet, de nombreuses organisations ont créées des Sites Intranet Corporate basés sur la technologie des Publishing Site qui n’est pas supportée par les automatismes actuellement implémentés par Microsoft.

Donc la question vient très rapidement:

  • Comment intégrer les News de mon site Intranet dans les applications basiques Office 365 SharePoint (Mobile ou Web) ?

Pour répondre à cette question, une solution peut être le passage par les Repost Pages

Qu’est-ce qu’un “Repost Page”

Ce type de page est basé sur la technologies des pages Modernes utilisant un Layout spécifique.

Cette logiques est d’ailleurs visible dans les Communication Hub Sites qui permettent d’aggéger les “News” de plusieurs sites dans un seul endroit et ceci sans aucune action du content manager (on retrouve la logique du “Retweet”).

Pour créer un Repost page manuallement, on peut aller dans un site modern et cliquer sur “Add > News Link”

Capture-RepostPage-01

Ce lien peut pointer vers n’importe quoi, même une page publique Bing News par exemple.

On doit fournir à cet instant l’adresse Web de la page à lier, puis un titre, une description et une image associée

Capture-RepostPage-02

Lorsque le formulaire est complété, la page repost apparait comme n’importe quelle News dans la WebPart des News du site (ou Hubsite)

Capture-RepostPage-03

Mais aussi dans la page racine du Tenant:

Capture-RepostPage-04

Vous pouvez donc simplement dédier une personne en charge de la création de ces “Repost Pages”, mais cela sera vraiment peu passionant pour cette personne.

La seconde option est d’adapter et d’utiliser le script PowerShell pour cela.

Script PowerShell créant les Repost Page pointant les news des Publishing Site

Basé sur un autre message publié ici:

J’ai donc créé le script siuvant permettant de:

  • Collecter les dernières news publiées sur le Site de Publishing en utilisant le Search et exportant la liste en CSV
  • Charger ce CSV pour vérifier si un Repost Page existe, sinon le créer
  • Changer les Metadata de chaque repost page avec les données du CSV

[string]$SitePagesURL ="
[string]$PageLibPublicName = "Site Pages"
[DateTime]$MyCSVPublishingDate = Get-Date
[DateTime]$PortalPublishingDate = Get-Date
[string]$MyCSVPublisher = ""
[string]$MyCSVTitle = ""
[string]$MyCSVNewsURL = ""
[string]$MyCSVNewsPictureURL = ""
[string]$MyCSVNewsDescription = ""
[string]$CSVFileName = "ExportGlobalNewsItems.csv"
[string]$NewsPageFileName = ""

[string]$queryText = "ContentTypeId:0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D00DAB155038B062847A409F1E450E9E5E3*  Path:https://yourTenant.sharepoint.com/yourintranet  "
[string]$srcrpattern = '(?i)src="(.*?)"'
[string]$outputline = ""

[int]$TempUserID = 0

# ---------------------------------------------------------------------------------------------------------------
function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SharePoint.Client.Search\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.Search.dll"
    #$defaultDLLPath = "D:\TOOLS\SHAREPOINT\SP_ONLINE\sharepointclientcomponents\microsoft.sharepointonline.csom.16.1.8119.1200\lib\net40-full\Microsoft.SharePoint.Client.Search.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

}

# ---------------------------------------------------------------------------------------------------------------
Function Get-All-Intranet-News-Published-ExportCSV($MyctxTemp, $MyspoRootwebTemp)
{
# add references to SharePoint client assemblies and authenticate to Office 365 site - required for CSOM   

    $keywordQuery = New-Object Microsoft.SharePoint.Client.Search.Query.KeywordQuery($MyctxTemp)
    $keywordQuery.QueryText = $queryText
    $keywordQuery.RowLimit = 50
    $keywordQuery.TrimDuplicates=$false 

    $keywordQuery.SelectProperties.Add("LastModifiedTime") 
    $keywordQuery.SelectProperties.Add("Modified") 
    $keywordQuery.SelectProperties.Add("ModifiedBy") 
    $keywordQuery.SelectProperties.Add("IntranetPublisher") 
    $keywordQuery.SelectProperties.Add("DescriptionResumeOWSTEXT") 
    $keywordQuery.SelectProperties.Add("PublishingImage") 

    $keywordQuery.SortList.Add("Modified","Desc")     

    $searchExecutor = New-Object Microsoft.SharePoint.Client.Search.Query.SearchExecutor($MyctxTemp)
   
    $results = $searchExecutor.ExecuteQuery($keywordQuery)
    $MyctxTemp.ExecuteQuery()
   
    Write-Host $results.Value[0].ResultRows.Count

    Clear-Content $CSVFileName
    $outputline = '"NewsTitle";"PublisherEmail";"PublicationDate";"NewsURL";"NewsPictureURL";"NewsDescription";'
    Add-Content -Encoding UTF8 -Force $CSVFileName $outputline  

    foreach($result in $results.Value[0].ResultRows)
    {
        $TempString = $result["Modified"].split(';')[0]

        $ImageURLsrc = ([regex]$srcrpattern ).Matches($result["PublishingImage"]) |  ForEach-Object { $_.Groups[1].Value }
        $ImageURLsrc = $SitePagesURL + $ImageURLsrc.split('?')[0] +"?RenditionID=9"
        
        $PortalPublishingDate=[datetime]::ParseExact([string]$TempString, 'M/d/yyyy h:mm:ss tt', [CultureInfo]::InvariantCulture)
        $PublisherDetails = $result["IntranetPublisher"].split('|')

        #Write-Host "     ------>>> TempString:", $TempString
        #Write-Host "     ------>>> PublisherDetails:", $PublisherDetails.Count, "- LastField:",  $PublisherDetails[4].Trim()
        #Write-Host " ------>>> PublishingImage:", $result["PublishingImage"]
        #Write-Host " ------>>> Modified:", $result["Modified"]
 
        Write-Host "  ---------------------------------------- "
        Write-Host " ------>>> NewsPath:", $result["Path"]
        Write-Host " ------>>> Title:", $result["Title"]
        Write-Host " ------>>> PublicationDate:", $PortalPublishingDate
        Write-Host " ------>>> IntranetPublisherEmail:",  $PublisherDetails[4].Trim()
        Write-Host " ------>>> ImageURLsrc:", $ImageURLsrc
        Write-Host " ------>>> DescriptionResumeOWSTEXT:", $result["DescriptionResumeOWSTEXT"]
        Write-Host "  ---------------------------------------- "

        #CSV file location, to store the result 
         $outputline = '"'+ $result["Title"] +'";"'+ $PublisherDetails[4].Trim() +'";"'+ $PortalPublishingDate.ToString("dd.MM.yyyy hh:mm:ss") +'";"'+ $result["Path"] +'";"'+ $ImageURLsrc +'";"'+  $result["DescriptionResumeOWSTEXT"] +'";'
        Add-Content -Encoding UTF8 -Force $CSVFileName $outputline  
    }

   
}

# ---------------------------------------------------------------------------------------------------------------
Function Get-All-News-PageList-ComparedToCSV($MyctxTemp, $MyspoRootwebTemp)
{
    $GlobalNewsPageCSV = Import-Csv -encoding UTF8 $CSVFileName -delimiter ";"

    $GlobalNewsPageCSV | Format-Table

    $Alllists = $MyspoRootwebTemp.Lists
    $MyPagelist = $Alllists.GetByTitle($PageLibPublicName)

    $MyPagelistItems = $MyPagelist.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(9999))
    $MyctxTemp.load($MyPagelistItems)
    $MyctxTemp.executeQuery()

    foreach($PageItem in $MyPagelistItems)
    {
        Write-Host ""
        Write-Host ""
        Write-Host "   --------------------------------------------------------- "


         foreach($MyFieldval in $PageItem.FieldValues)
        {
             Write-Host "     >>> FieldName:", $MyFieldval
        }
#>

        $ModifiedByuser = $PageItem["Editor"]
        $CreatedByuser = $PageItem["Author"]
        Write-Host "ID:", $PageItem["ID"], "- Title:", $PageItem["Title"], "- Original Publication Date:", $PageItem["Modified"]
        Write-Host "   ==>>> PromotedState:", $PageItem["PromotedState"], "- PageLayoutType:", $PageItem["PageLayoutType"] -ForegroundColor red
        Write-Host "       ===> Modified by:", $ModifiedByuser.LookupValue, "[", $ModifiedByuser.LookupId, "] - Created by:", $CreatedByuser.LookupValue, "[", $CreatedByuser.LookupId, "]"
        Write-Host "   >> _OriginalSourceUrl:", $PageItem["_OriginalSourceUrl"] -ForegroundColor magenta
        Write-Host "   >> Description:", $PageItem["Description"]
        Write-Host "   >> BannerImageUrl:", $PageItem["BannerImageUrl"].URL, "- URLDesc:", $PageItem["BannerImageUrl"].Description #[BannerImageUrl, Microsoft.SharePoint.Client.FieldUrlValue]
        Write-Host "   >> ContentTypeId:", $PageItem["ContentTypeId"] # [ContentTypeId, 0x0101009D1CB255DA76424F860D91F20E6C4118002A50BFCFB7614729B56886FADA02339B00FB61AB42CC88E741A501DF164E1EDB74]

        $searchTerm = $PageItem["_OriginalSourceUrl"]
        $MyCSVPublishingDate = Get-Date
    
        $GlobalNewsPageCSV |Where-Object {$_.NewsURL -match $searchTerm} |foreach-object{ $MyCSVTitle=$_.NewsTitle; $MyCSVNewsURL=$_.NewsURL; $MyCSVPublisher=$_.PublisherEmail; $MyCSVPublishingDate=[datetime]::ParseExact($_.PublicationDate,'dd.MM.yyyy hh:mm:ss',$null) }
       
        if ($PageItem["_OriginalSourceUrl"] -eq $MyCSVNewsURL)
        {
            Write-Host "    >>> CSV Title found:", $MyCSVTitle, "- CSV Publication Date:", $MyCSVPublishingDate, "- Publisher:", $MyCSVPublisher  -ForegroundColor Yellow
            Write-Host "    >> CSV NewsURL:", $MyCSVNewsURL -ForegroundColor magenta

            #Load Context for the target link page $PageItem["_OriginalSourceUrl"]
             $TempUri = new-object Uri($MyCSVNewsURL)
            [string]$TempserverRelativeURL = $TempUri.AbsolutePath
            [string]$MyTempSubWebURL = $MyCSVNewsURL.substring(0, $MyCSVNewsURL.IndexOf('Pages'))
            Write-Host "             === >> MyTempSubWebURL:", $MyTempSubWebURL -ForegroundColor Yellow
             Write-Host "             === >> TempserverRelativeURL:", $TempserverRelativeURL -ForegroundColor Yellow
           
             $MyDestinationPagectx = New-Object Microsoft.SharePoint.Client.ClientContext($MyTempSubWebURL)
            $MyDestinationPagectx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
             $MyDestinationPagectx.RequestTimeout = 1000000 # milliseconds

            $MyDestinationPageweb = $MyDestinationPagectx.Web
            $MyDestinationPageSiteColl = $MyDestinationPagectx.Site
            $MyDestinationPagelist = $MyDestinationPageweb.Lists.GetByTitle("Pages")
            $MyDestinationPageFile = $MyDestinationPageweb.GetFileByServerRelativeUrl($TempserverRelativeURL);
   
            $MyDestinationPageFileitem = $MyDestinationPageFile.ListItemAllFields;
           
            $MyDestinationPagectx.Load($MyDestinationPageweb)
            $MyDestinationPagectx.Load($MyDestinationPageSiteColl)
            $MyDestinationPagectx.Load($MyDestinationPagelist)
            $MyDestinationPagectx.Load($MyDestinationPageFileitem)

            $MyDestinationPagectx.ExecuteQuery()

            Write-Host "         === >> DestinationPage Site URL:", $MyDestinationPageSiteColl.Url, "- ID:", $MyDestinationPageSiteColl.ID -ForegroundColor white
            Write-Host "         === >> DestinationPage Web URL:", $MyDestinationPageweb.Url, "- ID:", $MyDestinationPageweb.ID -ForegroundColor white
            Write-Host "         === >> DestinationPage PageList Title:", $MyDestinationPagelist.Title, "- ID:", $MyDestinationPagelist.ID -ForegroundColor white
            Write-Host "         === >> DestinationPage PageFile Title:", $MyDestinationPageFileitem["Title"].ToString(), "- ID:", $MyDestinationPageFileitem["UniqueId"].ToString()

            $MyEditoruserAccount = $MyspoRootwebTemp.EnsureUser("i:0#.f|membership|$($MyCSVPublisher)");
            $MyctxTemp.load($MyEditoruserAccount)
            $MyctxTemp.executeQuery()
             Write-Host "                ===> Modified Account Login:", $MyEditoruserAccount.LoginName -ForegroundColor Magenta
            $PageItem["Created_x0020_By"] = $MyEditoruserAccount.LoginName
            $PageItem["Modified_x0020_By"] = $MyEditoruserAccount.LoginName
            $PageItem["PromotedState"] = "2"
             $PageItem["PageLayoutType"] = "RepostPage"
            $PageItem["ClientSideApplicationId"] = "b6917cb1-93a0-4b97-a84d-7cf49975d4ec"

            $PageItem["_OriginalSourceSiteId"] = $MyDestinationPageSiteColl.ID
            $PageItem["_OriginalSourceWebId"] = $MyDestinationPageweb.ID
            $PageItem["_OriginalSourceListId"] = $MyDestinationPagelist.ID
            $PageItem["_OriginalSourceItemId"] = $MyDestinationPageFileitem["UniqueId"].ToString()

            $PageItem["Modified"] = $MyCSVPublishingDate;
            $PageItem["Created"] = $MyCSVPublishingDate;
            $PageItem["FirstPublishedDate"] = $MyCSVPublishingDate;
            $PageItem["Editor"] = $MyEditoruserAccount.Id;
            $PageItem["Author"] = $MyEditoruserAccount.Id
             $PageItem.Update()
            $MyctxTemp.ExecuteQuery()

        }
        else
        {
            Write-Host "    >>> CSV Title not found:", $MyCSVTitle, "- Date:", $MyCSVPublishingDate, "- Publisher:", $MyCSVPublisher  -ForegroundColor Red
             Write-Host "    >> CSV NewsURL:", $MyCSVNewsURL -ForegroundColor Red
        }

        Write-Host "   --------------------------------------------------------- "
    } 
}


Function Get-All-CSVNews-ComparedToPageList($MyctxTemp, $MyspoRootwebTemp)
{
    $GlobalNewsPageCSV = Import-Csv -encoding UTF8 $CSVFileName -delimiter ";"
    $GlobalNewsPageCSV | Format-Table

    foreach($CSVItem in $GlobalNewsPageCSV)
    {
        Write-Host "   --------------------------------------------------------- "
         Write-Host "    >> CSV NewsTitle:", $CSVItem.NewsTitle
         Write-Host "    >> CSV NewsURL:", $CSVItem.NewsURL
         Write-Host "    >> CSV PublisherEmail:", $CSVItem.PublisherEmail
        Write-Host "    >> CSV PublicationDate:", $CSVItem.PublicationDate
        Write-Host "    >> CSV NewsPictureURL:", $CSVItem.NewsPictureURL
        Write-Host "    >> CSV NewsDescription:", $CSVItem.NewsDescription
        $MyCSVTitle = $CSVItem.NewsTitle
        $MyCSVNewsURL = $CSVItem.NewsURL
        $MyCSVPublisher = $CSVItem.PublisherEmail
        $MyCSVPublishingDate = [datetime]::ParseExact($CSVItem.PublicationDate,'dd.MM.yyyy hh:mm:ss',$null)
        $MyCSVNewsPictureURL = $CSVItem.NewsPictureURL
        $MyCSVNewsDescription = $CSVItem.NewsDescription

        #Load Context for the target link page $PageItem["_OriginalSourceUrl"]
        $TempUri = new-object Uri($MyCSVNewsURL)
        [string]$TempserverRelativeURL = $TempUri.AbsolutePath
        [string]$MyTempSubWebURL = $MyCSVNewsURL.substring(0, $MyCSVNewsURL.IndexOf('Pages'))
        Write-Host "             === >> MyTempSubWebURL:", $MyTempSubWebURL -ForegroundColor Yellow
        Write-Host "             === >> TempserverRelativeURL:", $TempserverRelativeURL -ForegroundColor Yellow
       
        $MyDestinationPagectx = New-Object Microsoft.SharePoint.Client.ClientContext($MyTempSubWebURL)
        $MyDestinationPagectx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
        $MyDestinationPagectx.RequestTimeout = 1000000 # milliseconds

        $MyDestinationPageweb = $MyDestinationPagectx.Web
        $MyDestinationPageSiteColl = $MyDestinationPagectx.Site
        $MyDestinationPagelist = $MyDestinationPageweb.Lists.GetByTitle("Pages")
        $MyDestinationPageFile = $MyDestinationPageweb.GetFileByServerRelativeUrl($TempserverRelativeURL);

        $MyDestinationPageFileitem = $MyDestinationPageFile.ListItemAllFields;
       
        $MyDestinationPagectx.Load($MyDestinationPageweb)
        $MyDestinationPagectx.Load($MyDestinationPageSiteColl)
        $MyDestinationPagectx.Load($MyDestinationPagelist)
         $MyDestinationPagectx.Load($MyDestinationPageFileitem)
         $MyDestinationPagectx.ExecuteQuery()

        Write-Host "         === >> DestinationPage Site URL:", $MyDestinationPageSiteColl.Url, "- ID:", $MyDestinationPageSiteColl.ID -ForegroundColor white
        Write-Host "         === >> DestinationPage Web URL:", $MyDestinationPageweb.Url, "- ID:", $MyDestinationPageweb.ID -ForegroundColor white
        Write-Host "         === >> DestinationPage PageList Title:", $MyDestinationPagelist.Title, "- ID:", $MyDestinationPagelist.ID -ForegroundColor white
         Write-Host "         === >> DestinationPage PageFile Title:", $MyDestinationPageFileitem["Title"].ToString(), "- ID:", $MyDestinationPageFileitem["UniqueId"].ToString()
       
        $MyEditoruserAccount = $MyspoRootwebTemp.EnsureUser("i:0#.f|membership|$($MyCSVPublisher)");
        $MyctxTemp.load($MyEditoruserAccount)
        $MyctxTemp.executeQuery()
           
        $MyPagelist = $MyspoRootwebTemp.Lists.GetByTitle($PageLibPublicName)
        $MyQuery = New-Object Microsoft.SharePoint.Client.CamlQuery;
        $MyQuery.ViewXml = "$MyCSVNewsURL"
        $MyPagelistItems = $MyPagelist.GetItems($MyQuery);
        $MyctxTemp.Load($MyPagelistItems)
        $MyctxTemp.ExecuteQuery()
 
        if($MyPagelistItems.Count -lt 1)
        {
            [string]$NewsPageFileName = "/yourintranet/SitePages/"+ $MyCSVPublishingDate.ToString("yyyyMMdd") +'-'+ $CSVItem.NewsURL.Substring($CSVItem.NewsURL.LastIndexOf("/") + 1)
            Write-Host "                >> $($MyPagelistItems.Count) PageList Item Found, Need to be created [ $NewsPageFileName ]" -ForegroundColor Red # TO CREATE !!!

            $NewPageitem = $MyPagelist.RootFolder.Files.AddTemplateFile($NewsPageFileName, [Microsoft.SharePoint.Client.TemplateFileType]::ClientSidePage).ListItemAllFields
            # Make this page a "modern" page
            $NewPageitem["ContentTypeId"] = "0x0101009D1CB255DA76424F860D91F20E6C4118002A50BFCFB7614729B56886FADA02339B00874A802FBA36B64BAB7A47514EAAB232";
             $NewPageitem["PageLayoutType"] = "RepostPage"
            $NewPageitem["PromotedState"] = "2"
            $NewPageitem["Title"] = $CSVItem.NewsTitle
            $NewPageitem["ClientSideApplicationId"] = "b6917cb1-93a0-4b97-a84d-7cf49975d4ec"

            $NewPageitem["_OriginalSourceSiteId"] = $MyDestinationPageSiteColl.ID
            $NewPageitem["_OriginalSourceWebId"] = $MyDestinationPageweb.ID
            $NewPageitem["_OriginalSourceListId"] = $MyDestinationPagelist.ID
            $NewPageitem["_OriginalSourceItemId"] = $MyDestinationPageFileitem["UniqueId"].ToString()

            $NewPageitem["_OriginalSourceUrl"] =  $MyCSVNewsURL
            $NewPageitem["Editor"] = $MyEditoruserAccount.Id
            $NewPageitem["Author"] = $MyEditoruserAccount.Id
            $NewPageitem["Description"] = $MyCSVNewsDescription
            $NewPageitem["BannerImageUrl"] = $MyCSVNewsPictureURL;
            $NewPageitem["Modified"] = $MyCSVPublishingDate;
            $NewPageitem["Created"] = $MyCSVPublishingDate;
            $NewPageitem["Created_x0020_By"] = $MyEditoruserAccount.LoginName
            $NewPageitem["Modified_x0020_By"] = $MyEditoruserAccount.LoginName
            $NewPageitem["FirstPublishedDate"] = $MyCSVPublishingDate;
            $NewPageitem.Update();
            $MyctxTemp.Load($NewPageitem);
            $MyctxTemp.ExecuteQuery();
        }
        elseif($MyPagelistItems.Count -eq 1)
        {
            Write-Host "                >> $($MyPagelistItems.Count) Page Item Found, Case OK !!!" -ForegroundColor Yellow # TO CHECK AND UPDATE VIA SCRIPT !!!
             #Loop through each item (only one if that is OK)
             $MyPagelistItems | ForEach-Object {
                #Get the Title field value
                Write-Host "                >> PageList NewsTitle:", $_["Title"] -ForegroundColor Yellow
                 Write-Host "                >> PageList NewsUrl:", $_["_OriginalSourceUrl"] -ForegroundColor Yellow

                if($MyCSVNewsPictureURL -ne $_["BannerImageUrl"].URL)
                 {
                    $_["BannerImageUrl"].URL = $MyCSVNewsPictureURL
                    $_["BannerImageUrl"].Description = $MyCSVNewsPictureURL
                }
                $_["PromotedState"] = "2"
                $_["Modified"] = $MyCSVPublishingDate;
                $_["Created"] = $MyCSVPublishingDate;
                $_["FirstPublishedDate"] = $MyCSVPublishingDate;
                $_["_OriginalSourceSiteId"] = $MyDestinationPageSiteColl.ID
                $_["_OriginalSourceWebId"] = $MyDestinationPageweb.ID
                $_["_OriginalSourceListId"] = $MyDestinationPagelist.ID
                $_["_OriginalSourceItemId"] = $MyDestinationPageFileitem["UniqueId"].ToString()
                 $_["Editor"] = $MyEditoruserAccount.Id;
                 $_["Author"] = $MyEditoruserAccount.Id
                $_["Created_x0020_By"] = $MyEditoruserAccount.LoginName
                 $_["Modified_x0020_By"] = $MyEditoruserAccount.LoginName
                 $_.Update()
                $MyctxTemp.ExecuteQuery()
            }
        }
        else
        {
            Write-Host "                >> $($MyPagelistItems.Count) PageList Item Found, Need to be fixed !!!" -ForegroundColor Red # TO CHECK AND CONTROL MANUALLY !!!
            $MyPagelistItems | ForEach-Object {
                #Get the Title field value
                 Write-Host "                >> PageList NewsTitle:", $_["Title"] -ForegroundColor Yellow
                Write-Host "                >> PageList NewsUrl:", $_["_OriginalSourceUrl"] -ForegroundColor Yellow
            }
        }
    }
}

# ---------------------------------------------------------------------------------------------------------------
Load-DLLandAssemblies

#get and save your O365 credentials
[string]$username = "AdminAccount@Yourtenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

#connect to the web site using the stored credentials
Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
Write-host "   CONNECTED SITE:", $SitePagesURL  -ForegroundColor Yellow

$Myctx = New-Object Microsoft.SharePoint.Client.ClientContext($SitePagesURL +"/yourintranet")

$Myctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
$Myctx.RequestTimeout = 1000000 # milliseconds
$MyspoRootweb = $Myctx.Web
$Myctx.Load($MyspoRootweb)
$Myctx.ExecuteQuery()

Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $Myctx.ServerVersion " # <<<<<<" -ForegroundColor Green
Write-Host " ---------------------------------------------------------"
Write-Host " "

Write-host " -------------------------------------------------------- "
Write-host "   -->> RootSite:", $MyspoRootweb.URL -ForegroundColor green

Write-host " "

Get-All-Intranet-News-Published-ExportCSV $Myctx $MyspoRootweb

Get-All-CSVNews-ComparedToPageList $Myctx $MyspoRootweb

Get-All-News-PageList-ComparedToCSV $Myctx $MyspoRootweb


Vous pouvez facilement reprendre ce script et l’adapter à vos propres besoins, mais celui-ci a été validé en chargeant les 500 dernières News globales publiées sur notre Intranet Corporate sans aucun soucis.

Romelard Fabrice

Version en Anglais:

Office 365: Comment changer le nom “Auteur” dans les pages modernes d'un Modern Site SharePoint Online

Office 365 SharePoint Online propose désormais l’usage des sites Modernes accompagnés des pages Modernes.

Ces pages peuvent alors être utilisées comme des News et donc présentées aux utilisateurs de manière sympathique.

WebPartHomeNewsModernPage

Le fait est que ce mode de fonctionnement est moins souple que les pages de “Publishing” et certaines fonctionnalités ne sont pas intégrées, dont la désignation du “Publieur”.

WebPartHomeNewsModernPage03

En effet, par défaut le nom qui sera montré sera toujours le créateur de la news:

WebPartHomeNewsModernPage02

Le script PowerShell suivant vous permet de changer la valeur Auteur par le nom de la dernière personne ayant édité la News.

De même que la date de publication deviendra celle de modification.


[string]$SitePagesURL =”https://[yourtenant].sharepoint.com/sites/SiteCollection”
[string]$PageLibPublicName = "Site Pages"
[DateTime]$modifiedDate = Get-Date

[string]$DefaultEmailAddress = "Fabrice.Romelard@sgs.com"
[string]$MyTempEmailAddress = ""

# ---------------------------------------------------------------------------------------------------------------
function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session
    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}

# ---------------------------------------------------------------------------------------------------------------
Function Get-All-PageList-UpdateMetadata($MyctxTemp, $MyspoRootwebTemp)
{
    $Alllists = $MyspoRootwebTemp.Lists
     $MyPagelist = $Alllists.GetByTitle($PageLibPublicName)

    $MyQuery = New-Object Microsoft.SharePoint.Client.CamlQuery;
    $MyQuery.ViewXml = "9999"
    $MyPagelistItems = $MyPagelist.GetItems($MyQuery);

    $MyctxTemp.load($MyPagelistItems)
    $MyctxTemp.executeQuery()
   
    foreach($PageItem in $MyPagelistItems)
     {
        Write-Host ""
        Write-Host ""
        Write-Host "   --------------------------------------------------------- "
< #   
        foreach($MyFieldval in $PageItem.FieldValues)
        {
            Write-Host "     >>> FieldName:", $MyFieldval
        }
#>
        $modifiedDate = $PageItem["Modified"]
        $ModifiedByuser = [Microsoft.SharePoint.Client.FieldUserValue]$PageItem["Editor"]
        $CreatedByuser = [Microsoft.SharePoint.Client.FieldUserValue]$PageItem["Author"]
        Write-Host "ID:", $PageItem["ID"], "- Title:", $PageItem["Title"], "- Original Publication Date:", $modifiedDate.ToString("dd-MM-yyyy")
        Write-Host "           ==>>> PromotedState:", $PageItem["PromotedState"], "- PageLayoutType:", $PageItem["PageLayoutType"] -ForegroundColor red
       
        Write-Host "   >> Description:", $PageItem["Description"]
        Write-Host "   >> BannerImageUrl:", $PageItem["BannerImageUrl"].URL, "- URLDesc:", $PageItem["BannerImageUrl"].Description
        Write-Host "   >> ContentTypeId:", $PageItem["ContentTypeId"]

        if ($ModifiedByuser.LookupId -ne  $CreatedByuser.LookupId)
        {
             Write-Host "       ===> Modified by:", $ModifiedByuser.LookupValue, " - ", $ModifiedByuser.Email ,"[", $ModifiedByuser.LookupId, "]" -ForegroundColor green
            Write-Host "       ===> Created by:", $CreatedByuser.LookupValue, " - ", $CreatedByuser.Email ,"[", $CreatedByuser.LookupId, "]" -ForegroundColor green

            if($ModifiedByuser.Email -ne "")
             {
                $MyTempEmailAddress = $ModifiedByuser.Email
            }
            else
            {
                $MyTempEmailAddress = $DefaultEmailAddress #Admin Account to reset with the default one
            }
            $MyEditoruserAccount = $MyspoRootwebTemp.EnsureUser("i:0#.f|membership|$($MyTempEmailAddress)");
            $MyctxTemp.load($MyEditoruserAccount)
            $MyctxTemp.executeQuery()
            Write-Host "                ===> Modified Account Login:", $MyEditoruserAccount.LoginName -ForegroundColor Magenta

            $PageItem["Modified"] = $modifiedDate;
            $PageItem["Created"] = $modifiedDate;
            $PageItem["FirstPublishedDate"] = $modifiedDate;
            $PageItem["Created_x0020_By"] = $MyEditoruserAccount.LoginName
            $PageItem["Modified_x0020_By"] = $MyEditoruserAccount.LoginName
            $PageItem["Editor"] = $MyEditoruserAccount.Id;
            $PageItem["Author"] = $MyEditoruserAccount.Id
            $PageItem.Update()
            $MyctxTemp.ExecuteQuery()
        }
        else
        {
             Write-Host "       ===> Modified by:", $ModifiedByuser.LookupValue, " - ", $ModifiedByuser.Email ,"[", $ModifiedByuser.LookupId, "]" -ForegroundColor red
            Write-Host "       ===> Created by:", $CreatedByuser.LookupValue, " - ", $CreatedByuser.Email ,"[", $CreatedByuser.LookupId, "]" -ForegroundColor red

            if($ModifiedByuser.Email -eq "") #Admin Account to reset with the default one
            {
                $MyTempEmailAddress = $DefaultEmailAddress
                $MyEditoruserAccount = $MyspoRootwebTemp.EnsureUser("i:0#.f|membership|$($MyTempEmailAddress)");
                $MyctxTemp.load($MyEditoruserAccount)
                $MyctxTemp.executeQuery()
                 Write-Host "                ===> Modified Account Login:", $MyEditoruserAccount.LoginName -ForegroundColor Magenta

                $PageItem["Modified"] = $modifiedDate;
                 $PageItem["Created"] = $modifiedDate;
                $PageItem["FirstPublishedDate"] = $modifiedDate;
                $PageItem["Created_x0020_By"] = $MyEditoruserAccount.LoginName
                 $PageItem["Modified_x0020_By"] = $MyEditoruserAccount.LoginName
                $PageItem["Editor"] = $MyEditoruserAccount.Id;
                $PageItem["Author"] = $MyEditoruserAccount.Id
                $PageItem.Update()
                $MyctxTemp.ExecuteQuery()           
            }
        }
        Write-Host "   --------------------------------------------------------- "
    } 
}


# ---------------------------------------------------------------------------------------------------------------
Load-DLLandAssemblies

#get and save your O365 credentials
[string]$username = "AdminAccount@Tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

#connect to the web site using the stored credentials
Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
Write-host "   CONNECTED SITE:", $SitePagesURL  -ForegroundColor Yellow

$Myctx = New-Object Microsoft.SharePoint.Client.ClientContext($SitePagesURL)

$Myctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
$Myctx.RequestTimeout = 1000000 # milliseconds
$MyspoRootweb = $Myctx.Web
$Myctx.Load($MyspoRootweb)
$Myctx.ExecuteQuery()

Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $Myctx.ServerVersion " # <<<<<<" -ForegroundColor Green
Write-Host " ---------------------------------------------------------"
Write-Host " "

Write-host " -------------------------------------------------------- "
Write-host "   -->> RootSite:", $MyspoRootweb.URL -ForegroundColor green

Write-host " "

Get-All-PageList-UpdateMetadata $Myctx $MyspoRootweb



Vous pouvez l’adapter à vos besoins.

Fabrice Romelard

Message en Anglais:

Office 365: Modifier les jeux de couleur dans les Thèmes des pages classiques de SharePoint Online

Dans un précédent post, nous avons vu comment configurer et implémenter un Theme utilisable dans les Modern Site Page via un script PowerShell:

La question du systeme de gestion de theme en mode classique reste pourtant d'actualité à travers le lien "Classic change the look options" disponible dans la sélection des thèmes modernes. Cette option vous ammene directement dans la page des gestion de theme de SharePoint 2013.

Du point de vue administrateur, la gestion des thèmes est différentes entre la version moderne et classique
  - Modern site:
     - Au niveau du Tenant:
          -> Activation de la selection des thèmes
          -> Désactivation des sélections de couleur de base
          -> Ajouter le nouveau jeu de couleurs Corporate
     - Au niveau de la collection de sites:
          -> Rien de possible
     - Au niveau SPWeb (pour chaque site ou sous-site)
          -> Sélection de la couleur utilisée
  - Classic site:
     - Au niveau du Tenant: Rien de possible
     - Au niveau de la collection de sites: Rien de possible sauf la remontée des fichiers techniques du thème
     - Au niveau SPWeb (pour chaque site ou sous-site)
            -> Ajouter le nouveau Theme Corporate
           -> Suppression des autres thèmes de base

Il est utile de déléguer la gestion des couleurs (et le thème) des sites au propriétaires de ceux-ci, mais il faut alors leur proposer la mise en place du jeu de couleur corporate s'ils le souhaitent.

Ce script permet donc de mettre en place les thèmes classiques pour tous les sites et sous-sites d'un ensemble de collections de site suivant le filtrage choisi.
C'est possible au niveau des sites SharePoint basiques, des groupes office 365 ou tout autre filtrage voulu.

Vous devez préparer les fichiers de resource (spconf, spcolor, backgroundfile and logo file).
 
Vous pouvez utiliser ce script PowerShell script comme vous le souhaitez en l'adaptant à votre besoin, mais il a fonctionné dans un tenant avec plus de 2000 collections de site et de très nombreux sous-sites associés.


[string]$username = "admin@tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"

$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd

[string]$ThemeFileFolder = "D:\THEME_FILES\CORP_SPO_THEME\"
[string]$ThemeName = "CORP Theme"
[string]$AssetListNameURL = "SiteAssets"
[string]$CORPFoldername = "CORPTheme"
[string]$IntranetMasterPage = "seattle.master"
[string]$ExtranetMasterPage = "oslo.master"

[string]$ThemeFileSPFont = "Fontscheme-CORP.spfont"
[string]$ThemeFileSPColor = "Palette-CORP.spcolor"
[string]$ThemeFileLogo = "logo_CORP.png"
[string]$ThemeFileIntranetBG = "INTRANET_CORP.jpg"
[string]$ThemeFileExtranetBG = "EXTRANET_CORP.jpg"

function Load-DLLandAssemblies
{
     [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}

function IfThemeExists($Myctx, $list, $themeName)
{
    [int]$ReturnValue = 0
    $caml="<View><Query><Where><Eq><FieldRef Name='Name' /><Value Type='Text'>$themeName</Value></Eq></Where></Query></View>";
    $cquery = New-Object Microsoft.SharePoint.Client.CamlQuery
    $cquery.ViewXml=$caml
    $listItems = $list.GetItems($cquery)
    $Myctx.Load($listItems)
    $Myctx.ExecuteQuery()
    if($listItems.Count > 0)
    {
         $ReturnValue = 0;
    }
    else
    {
        foreach ($targetListItem in $listItems)
        {
            $ReturnValue = $targetListItem["ID"]
        }
    }
    return $ReturnValue
}

function Upload-Specific-File($CompleteFilePath, $spoWebContext, $MyfolderURL )
{   
    $Localfile = get-item $CompleteFilePath
   
    [string]$MyNewFileURL = -join($MyfolderURL, "/", $Localfile.Name)
    write-host "CORP File URL Uploaded:", $Localfile.FullName, " - Url:", $MyNewFileURL
    [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($spoWebContext, $MyNewFileURL, $Localfile.OpenRead(), $true)
}

#Custom Function to Add a new Theme in the old classic format
Function AddNewCorpThemeInSPweb($myctx, $myCurrentWeb, [string]$RootOrSubstite, [string]$RootSiteRelativeURL, [string]$ExtranetSharing)
{
    Try
    {
        [string]$tempSourcePath = ""
        [string]$tempDestinationPathSiteAsset = ""
        [string]$tempDestinationPathTheme = ""
        [string]$masterPageUrl = ""
        $myUploadedFile
       
         [string]$tempPathBG = ""
        [string]$tempPathFont = ""
        [string]$tempPathPalette = ""

        $tempDestinationPathSiteAsset = -join($myCurrentWeb.ServerRelativeUrl, "/", $AssetListNameURL, "/", $CORPFoldername)
        $tempDestinationPathTheme = -join($myCurrentWeb.ServerRelativeUrl, "/_catalogs/theme/15")

        Write-Host " ---------------------------------------------- "
        Write-Host " >>>> UPLOAD THE THEME FILES INTO THE ROOT SITE: ", $myCurrentWeb.ServerRelativeUrl  -foregroundcolor yellow
        #Deploy Custom Logo
        $tempSourcePath = -join($ThemeFileFolder, $ThemeFileLogo)
        Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathSiteAsset
         Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathSiteAsset

        #Deploy BackGround
        $tempSourcePath = -join($ThemeFileFolder, $ThemeFileIntranetBG)
        Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathSiteAsset
        Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathSiteAsset
       
        $tempSourcePath = -join($ThemeFileFolder, $ThemeFileExtranetBG)
        Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathSiteAsset
        Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathSiteAsset
        if($ExtranetSharing -eq "Disabled")
        {
            $tempPathBG =  -join($tempDestinationPathSiteAsset, "/", $ThemeFileIntranetBG)
        }
        else
        {
            $tempPathBG =  -join($tempDestinationPathSiteAsset, "/", $ThemeFileExtranetBG)
        }
       
         #Deploy Custom Color
        $tempSourcePath = -join($ThemeFileFolder, $ThemeFileSPColor)
        Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathSiteAsset
        Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathSiteAsset
        $tempPathPalette =  -join($tempDestinationPathTheme, "/", $ThemeFileSPColor)
        if($RootOrSubstite -eq "RootSite")
        {
            Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathTheme
             Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathTheme
            $tempPathPalette =  -join($tempDestinationPathTheme, "/", $ThemeFileSPColor)
         }
        else
        {
            $tempPathPalette =  -join($RootSiteRelativeURL, "/_catalogs/theme/15/", $ThemeFileSPColor)
        }
       
        #Deploy Custom Font
        $tempSourcePath = -join($ThemeFileFolder, $ThemeFileSPFont)
         Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathSiteAsset
        Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathSiteAsset
        if($RootOrSubstite -eq "RootSite")
        {
            Upload-Specific-File  $tempSourcePath $myctx $tempDestinationPathTheme
            Write-Host "     >>>> file uploaded from:", $tempSourcePath, "- to:", $tempDestinationPathTheme
            $tempPathFont =  -join($tempDestinationPathTheme, "/", $ThemeFileSPFont)
        }
        else
        {
            $tempPathFont =  -join($RootSiteRelativeURL, "/_catalogs/theme/15/", $ThemeFileSPFont)
        }

        if($ExtranetSharing -eq "Disabled")
         {
            $masterPageUrl = -join($myCurrentWeb.ServerRelativeUrl, "/_catalogs/masterpage/", $IntranetMasterPage)
        }
        else
        {
            $masterPageUrl = -join($myCurrentWeb.ServerRelativeUrl, "/_catalogs/masterpage/", $ExtranetMasterPage)
        }
       
        Write-Host " ---------------------------------------------- "  -foregroundcolor green
         Write-Host "     ===>> tempPathPalette:", $tempPathPalette   -foregroundcolor green
        Write-Host "     ===>> tempPathFont:", $tempPathFont  -foregroundcolor green
        Write-Host "     ===>> tempPathBG:", $tempPathBG  -foregroundcolor green
        Write-Host "     ===>> masterPageUrl:", $masterPageUrl  -foregroundcolor green
        Write-Host " ---------------------------------------------- "  -foregroundcolor green

        $themesOverviewList = $myCurrentWeb.GetCatalog(124);
        $myctx.Load($themesOverviewList);
        $myctx.ExecuteQuery();

        $IDThemeCorp = IfThemeExists -Myctx $myctx -list $themesOverviewList -themeName $ThemeName
        if ($IDThemeCorp -eq 0)
         {
            # Create new theme entry.
            $itemInfo  = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
            $item = $themesOverviewList.AddItem($itemInfo)
            $item["Name"] = $ThemeName;
            $item["Title"] = $ThemeName;
            $item["ThemeUrl"] = $tempPathPalette;
            $item["FontSchemeUrl"] = $tempPathFont;
             $item["ImageUrl"] = $tempPathBG;
            $item["MasterPageUrl"] = $MasterPageUrl ;
            $item["DisplayOrder"] = 1;
            $item.Update()
            $myctx.ExecuteQuery();
        }
        else
        {
            [Microsoft.SharePoint.Client.ListItem]$listItem = $themesOverviewList.GetItemById($IDThemeCorp)
            $listItem["Name"] = $ThemeName;
             $listItem["Title"] = $ThemeName;
            $listItem["ThemeUrl"] = $tempPathPalette;
            $listItem["FontSchemeUrl"] = $tempPathFont;
            $listItem["ImageUrl"] = $tempPathBG;
            $listItem["MasterPageUrl"] = $MasterPageUrl ;
            $listItem["DisplayOrder"] = 1;
            $listItem.Update()
            $myctx.ExecuteQuery()       
        }
    }
    Catch [Exception]
    {
        Write-host " >>>> ERROR MESSAGE:", $_.Exception.Message -f Red
    }
}

function Get-SPOSubWebs
{
    Param(
        [Microsoft.SharePoint.Client.ClientContext]$Context,
        [Microsoft.SharePoint.Client.Web]$RootWeb,
        [string]$RootSiteRelURL,
        [string]$ExtranetMode
    )
   
    $Webs = $RootWeb.Webs
    $Context.Load($Webs)
    $Context.ExecuteQuery()
    ForEach ($sWeb in $Webs)
    {
        Write-host "   ====>> SubSite:", $sWeb.URL -ForegroundColor red
        AddNewCorpThemeInSPweb $Context $sWeb "subsite" $RootSiteRelURL $ExtranetMode

        Get-SPOSubWebs -RootWeb $sWeb -Context $Context -RootSiteRelURL $RootSiteRelURL $ExtranetMode
    }
}

cls
Write-Host " ---------------------------------------------- "
Load-DLLandAssemblies
Write-Host " ---------------------------------------------- "

Connect-SPOService -Url https://tenant-admin.sharepoint.com -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

#Retrieve all site collection infos
#Get-SPOSite -Template GROUP#0 #(Group Sites)
#Get-SPOSite -Template POINTPUBLISHINGTOPIC#0  #(Video Portal Sites)
#$sitesInfo = Get-SPOSite -Identity
https://tenant.sharepoint.com/sites/testsitecoll  | Sort-Object -Property url | Select *
#$sitesInfo = Get-SPOSite -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select *

$sitesInfo = Get-SPOSite -Template "STS#0" -Filter  {Url -like "https://tenant.sharepoint.com/sites/a*"}  -Limit ALL | Sort-Object -Property url | Select *

[int]$i = 1;
[string]$ExternalSharingSetting = ""

Write-Host "--------------------------------------------------------------------------------------------"
#Retrieve and print all sites
foreach ($site in $sitesInfo)
{
    $ExportAllUserLogin = ""
    Write-Host "SiteColl Number:", $i, "- of:", $sitesInfo.Count;
    $i += 1;
   
    Write-Host "--------------------------------------------------------------------------------------------"
    Write-Host "SPO Site collection:", $site.Url, "- Title:", $site.Title
    Write-Host "   => External Sharing:", $site.SharingCapability
    Write-Host "   => Site Template Used:", $site.Template
    Write-Host "   => Storage Quota:", $site.StorageQuota, "- Storage used:", $site.StorageUsageCurrent
    Write-Host "   => Percent Usage:", $($site.StorageUsageCurrent / $site.StorageQuota * 100), "%"
    Write-Host "   => Resource Quota:", $site.ResourceQuota, "- Resource used:", $site.ResourceUsageCurrent
    Write-Host "--------------------------------------------------------------------------------------------"

    #Set-SPOsite -Identity $site.Url -DenyAddAndCustomizePages 0 #Non mandatory but could be useful for the group sites

    $mySitectx = New-Object Microsoft.SharePoint.Client.ClientContext($site.Url)
    $mySitectx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($adminCreds.UserName, $adminCreds.Password)
    $mySitectx.RequestTimeout = 1000000 # milliseconds
    $myCurrentWeb = $mySitectx.Web
    $mySitectx.Load($myCurrentWeb)
    $mySitectx.ExecuteQuery()

    $ExternalSharingSetting = $site.SharingCapability

    AddNewCorpThemeInSPweb $mySitectx $myCurrentWeb "RootSite" $myCurrentWeb.ServerRelativeUrl $ExternalSharingSetting
    Get-SPOSubWebs $mySitectx $myCurrentWeb $myCurrentWeb.ServerRelativeUrl $ExternalSharingSetting
}

Write-Host " ---------------------------------------------- "

Les sites de référence sont les suivant:

Cette solution peut aussi être intégré dans vos script de provisioning permettant la création de Group ou Teams Office 365
 
Fabrice Romelard

Office 365: Modifier les jeux de couleur dans les Thèmes des pages modernes de SharePoint Online

La gestion des Thèmes de SharePoint Online est désormais différente avec l’arrivée des pages modernes et son implementation dans les Office 365 Groups et tous les modules connexes (Teams, Stream, Planner, …).

De ce fait, la manière de faire ne passe maintenant que via les jeux de couleur au niveau du Tenant Office 365 et voici comment faire en PowerShell


    [string]$themePaletteCustomName = "Your Customized Theme"
    $themepaletteCustom = @{
        "themePrimary" = "#102542"; #Navy
        "themeLighterAlt" = "#d6e3f5";
        "themeLighter" = "#fef1ef"; #Coral, themeLighter
        "themeLight" = "#fde2df"; #Coral, themeLight
        "themeTertiary" = "#6495da";
        "themeSecondary" = "#3e7bd1";
        "themeDarkAlt" = "#F87060"; #Coral
         "themeDark" = "#F87060"; #Coral
        "themeDarker" = "#193a68";
        "neutralLighterAlt" = "#f8f8f8";
        "neutralLighter" = "#f4f4f4";
        "neutralLight" = "#eaeaea";
         "neutralQuaternaryAlt" = "#dadada";
        "neutralQuaternary" = "#d0d0d0";
        "neutralTertiaryAlt" = "#c8c8c8";
         "neutralTertiary" = "#e2e2e2";
        "neutralSecondary" = "#53C7BD"; #Turquoise
        "neutralPrimaryAlt" = "#656565";
        "neutralPrimary" = "#6f6f6f";
        "neutralDark" = "#4f4f4f";
        "black" = "#3e3e3e";
        "white" = "#ffffff";
        "primaryBackground" = "#ffffff";
        "primaryText" = "#6f6f6f";
        "bodyBackground" = "#ffffff";
         "bodyText" = "#6f6f6f";
        "disabledBackground" = "#f4f4f4";
        "disabledText" = "#c8c8c8";
        "accent" = "#F87060"; #Coral
    }

    [string]$username = "Admin@tenant.onmicrosoft.com"
    [string]$PwdTXTPath = "D:\SECUREDPWD\ExportedPWD-$($username).txt"
    $secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
    $adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd

    Connect-SPOService -Url https://Tenant-admin.sharepoint.com -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

    # TO CHANGE THE USAGE OF THE DEFAULT COLORSET CHOICE
        Write-Host "   =>Status for the Default Theme Availability in modern site"
        Get-SPOHideDefaultThemes

    Write-Host "   => Hide the default Theme in the modern site"
    Set-SPOHideDefaultThemes $false #Or $True if you want to hide all
    Write-Host "   =>Status for the Default Theme Availability in modern site"
    Get-SPOHideDefaultThemes

# TO GET ALL THE PERSONAL COLORSET ADD AT THE TENANT LEVEL

    $AllThemes = Get-SPOTheme
    Write-Host "     >> Customited Theme Installed:", $AllThemes.count
    Write-Host "--------------------------------------------------------------------------------------------"
    Add-SPOTheme -Name $themePaletteCustomName -Palette $themepaletteCustom -IsInverted $false -Overwrite

#TO REMOVE THE CUSTOMIZED THEME YOU DON'T WANT ANYMORE

    #Remove-SPOTheme -Name $themePaletteCustomName

    $AllThemes = Get-SPOTheme

A ce moment, le nouveau jeu de couleur est visible en cliquant sur la roue (Settings) et sélectionnant “Change the look”:

ChangeTheLookModernPage-01

Pour trouver plus d’informations, vous pouvez aller sur les documentations officielles de Microsoft ou naviguer sur les pages suivantes:

Fabrice Romelard

Office 365: Script PowerShell pour fixer le Quota Warning de toutes les collections d’un tenant

En tant qu’administrateur Office 365, il est utile de pouvoir piloter l’évolution des volumétries occupées par les environnements SharePoint.

En effet, la somme de tous les volumes utilisés dans les collections SharePoint se retrouve dans le Quota défini pour le tenant, de ce fait, il convient de s’assurer qu’un mauvais usage ne vous crée pas de soucis pour l’ensemble des autres sites.

Ce script permet donc d’utiliser le système des alertes de quota qui sont envoyées au Site Collection Admins en cas de limite atteinte. Ceci afin d’éviter de recevoir des plaintes provenant des utilisateurs des sites en question.

Vous pouvez facilement modifier ce script pour l’adapter à votre cas d’usage.

[string]$username = "adminaccount@tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
[string]$ExportAllUserLogin = ""

[double]$QuotaAlertPercentValue = 0.9 # 90%
[integer]$QuotaStorageAlertToApply = 0

function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}
   
cls
Write-Host " ------------------------------------------------------------ "
write-Host "                                                              "
write-Host " Reset the quota alert with $($QuotaAlertPercentValue)        "
write-Host "                                                              "
Write-Host " -----------------------------------------------------------  "

Load-DLLandAssemblies

$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd

Connect-SPOService -Url https://tenant-admin.sharepoint.com -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

#Retrieve all site collection infos
$sitesInfo = Get-SPOSite -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select *
# Other filtering samples
#$sitesInfo = Get-SPOSite  -Filter {Url -like '*tenant.sharepoint.com/sites/ca*' } -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select *
#$sitesInfo = Get-SPOSite -Filter {Url -like '*sgs.sharepoint.com/sites/ca-*' } -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select -first 1 *

[int]$i = 1;
[int]$ItemsChanged = 0;

Write-Host " >>>> Number of sites found:", $sitesinfo.count

foreach ($site in $sitesInfo)
{
    Write-Host " >>>>  Site Num to check:", $i  -foregroundcolor green
    $QuotaStorageAlertToApply = [convert]::ToInt32($site.StorageQuota, 10)
    Write-Host "     ===>> Storage Quota before the percentage:", $QuotaStorageAlertToApply, "- StorageQuotaAlertPercent:", $QuotaAlertPercentValue -foregroundcolor yellow
    $QuotaStorageAlertToApply =  $($QuotaStorageAlertToApply * $QuotaAlertPercentValue)
     Write-Host "     ===>> Storage Quota before round command:", $QuotaStorageAlertToApply -foregroundcolor yellow

    $QuotaStorageAlertToApply = [math]::Round($QuotaStorageAlertToApply)

    Write-Host "   >>> Site details:", $site.Url , "- Current Size:", $site.StorageUsageCurrent, "- Storage Quota:", $site.StorageQuota -foregroundcolor green
    Write-Host "     ===>> Storage Quota Warning Applied:", $site.StorageQuotaWarningLevel -foregroundcolor yellow
    Write-Host "     ===>> Storage Quota Warning Theoric:", $QuotaStorageAlertToApply -foregroundcolor yellow
    if($QuotaStorageAlertToApply -ne $site.StorageQuotaWarningLevel)
     {
        $ItemsChanged++;
        Write-Host " >>>>  Number of sites changed:", $ItemsChanged  -foregroundcolor green
         if ($site.Status -ne "Active")
        {
            do
             {
                $site = Get-SPOSite -Identity $site.Url
                Write-Host "        ===>> Wait 60 sec for the change application"  -foregroundcolor red
                start-sleep -s 60
            }
            until ($site.Status -eq "Active")
        }
        Set-SPOSite -Identity $site.Url -StorageQuotaWarningLevel $QuotaStorageAlertToApply
        Write-Host "     =======>> Storage Quota Warning Applied:", $QuotaStorageAlertToApply -foregroundcolor yellow
    }
    else
    {
        Write-Host "     =======>> NO NEED TO CHANGE Storage Quota Warning " -foregroundcolor red
    }
    $i++;
}

Write-Host " ------------------------------------------------------------------------------------------"
Write-Host " >>>> Number of sites modified:", $ItemsChanged, "- of Total sites checked:", $i -foregroundcolor Red

Fabrice Romelard

Office 365: Comment créer un sous-plan dans Office 365 Planner

planner_logo

Office 365 offre un ensemble d’outils différents associés entre-eux au travers des Office 365 Groups.

Planner est un de ces outils accessible via le site Web ou l’application mobile, qui permet de gérer des projets quelconques sans avoir besoin de la solution Project Online. Vous pouvez créer des tâches, des groupes de tâches, les assigner à quelqu’un donner des dates ou avancées, …

Cet outil est intégré à Office 365 Groups et donc requiere la licence E1 simplement, sans ajout supplémentaire.

Le soucis est que la création d’un groupe permet d’avoir un seul plan de manière native alors que de nombreux cas exigent une création de plan par “Projet” en parallèle du travail quotidien.

Si on prend le cas d0’une équipe de support utilisateurs, elle sera intéressée d’avoir différents plans associés avec des projets plus ou moins long, répétitifs ou différents:

  • Installer la dernière solution video dans la salle de réunion XXX
  • Tester la dernière image officielle corporate sur les machines disponibles au catalogue
  • Préparer l’arrivé du collaborateur YYY
  • ...

Cette question de duplication des plans a été remontée dans le système UserVoice de Planner:

Et le status indique bien partiellement activé, ce qui explique ce post.

En effet pour créer un Sous-Plans, il faut lancer l’application Teams et choisir l’option “Add a Tab”:

SnipImage-CreateSubPlan-01

Dans la sélection, vous devez choisir Planner

SnipImage-CreateSubPlan-02

Il faut maintenant donner un nom à ce nouveau plan, comme le nom du projet:

SnipImage-CreateSubPlan-03


On trouve alors dans Teams la nouvelle Tab pointant ce nouveau sous-plan

SnipImage-CreateSubPlan-04

En allant dans le l’application Web de Planner, on retrouve alors notre nouveau sous-plan et le sous le nom de ce plan on voit le sous-niveau (SPS-Genève > General)

SnipImage-CreateSubPlan-05


La navigation est alors normale dans le plan en question et il n’y a pas de différence notable

SnipImage-CreateSubPlan-06

Attention:

Cette solution est parfaite pour les petites équipes, mais vous devez accepter la gestion des permissions qui est associée. En effet, les permissions dans planner sont celles du Group Office 365 sous-jacent et il n’y a pas d’isolation possible pour un sous-plan.

Ca viendra certainement dans le futur, mais pour le moment, ce n’est pas implémenté

Fabrice Romelard [MVP]

Office 365: Script PowerShell de création de sous-sites basés sur CSOM ou PnP

Au sein d’Office 365, l’option pour SharePoint "Save as Site template" n’est plus du tout disponible.

En effet, cette stratégie était pourtant largement utilisée par les utilisateurs avancés leur permettant de créer un modèle de site vierge qui pouvait ensuite être répliqué tel un moule à gateaux.

Dans SharePoint Online, cette option est désormais supprimée et il est évident maintenant que Microsoft invite ses utilisateurs à ne plus créer de sous-sites mais bien rester le plus “flat” possible, la hiérarchie est largement déconseillée (il faut voir la logique des HubSites pour s’en convaincre).

La raison principale justifiant ce choix est que SharePoint Online est une branche d’un arbre complexe proposé avec les Office 365 Groups (Planner, Teams, Stream, …).

Le fait est que dans de nombreux cas d’usage, les modèles sont pourtant nécessaires pour industrialiser certaines activités demandant des duplications répétées (projets, analyses, audits, …).

Donc la seule solution applicable dans ce besoin d’industrialisation est de créer son script PowerShell.

Dans cet article, vous trouverez 2 versions distinctes pour mon besoin, qui devra simplement être adapté au votre:

  • Le premier script est basé uniquement sur CSOM
  • Le second script est basé sur PnP

Script PowerShell utilisant CSOM

Pour développer ce script, j’ai utilisé de nombreuses ressources disponibles:

Il ne vous reste plus qu’à l’adapter:


# VALUE TO ADAPT !!!!!
# --------------------------------------------------------------------------------------------
$SiteIntegrationUrl ="https://tenant.sharepoint.com/sites/SiteCollection/Subsite1"
$SubSiteURL = "testsubsite"
$SubSiteName ="_TESTSUBSITE"
$EmailAddressAccessRequest = "emailaddresstosupport@domain.com"
$RootSiteOwnerGroup = "Root Site Collection Owners"
# --------------------------------------------------------------------------------------------


function Load-DLLandAssemblies
{
    [string]$defaultDLLPath = ""

    # Load assemblies to PowerShell session

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.SharePoint.Client.Runtime.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)

    $defaultDLLPath = "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell\Microsoft.Online.SharePoint.Client.Tenant.dll"
    [System.Reflection.Assembly]::LoadFile($defaultDLLPath)
}


#Custom Function to Check if Site Collection Exists in Given URL
Function Check-SiteExists($MySiteURL, $MyCredentials)
{
    #Setup context
    $Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($MySiteURL)
    $Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($MyCredentials.UserName,$MyCredentials.Password)
    $Web = $Ctx.Web
    $Ctx.Load($web)
    
    Try {
            $Ctx.ExecuteQuery()
            Return $True
         }
    Catch [Exception] {
      Write-host " >>>> ERROR MESSAGE:", $_.Exception.Message -f Red
      Return $False
     }       
}


Function Create-SPWebList([string]$MyShortTitle, [string]$MyDescription, [int]$MyListTemplateType, [Microsoft.SharePoint.Client.ClientContext]$Mycontext)
{
    Write-Host " ---------------------------------------------------------"

    $lci = New-Object Microsoft.SharePoint.Client.ListCreationInformation
    $lci.Title = $MyShortTitle
    $lci.Description = $MyDescription
    $lci.TemplateType = $MyListTemplateType   #see: https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splisttemplatetype.aspx
    $list = $Mycontext.web.lists.add($lci)
    $Mycontext.load($list)
    #send the request containing all operations to the server
    try{
        $Mycontext.executeQuery()
         write-host "    >>> info: List Created $($MyShortTitle)" -foregroundcolor green
    }
    catch{
        write-host "  >>> List Creation Error info: $($_.Exception.Message)" -foregroundcolor red
    }

    Write-Host " ---------------------------------------------------------"
}


# ---------------------------------------------------------------------------------------------------------------


Load-DLLandAssemblies

#get and save your O365 credentials
[string]$username = "AdminSiteCollection@tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

$DocLibTitleLong = "Given Documents"

$DocLibTitle = -join($SubSiteURL, "GivenDocuments")
$DocLibTitleLong = -join($SubSiteName, " Given Documents")
$SubSiteTitle = -join($SubSiteName, " - Subsite Usage")

$SubSiteOwnerOwners = -join($SubSiteName, " Subsite Usage Web Owners")
$SubSiteOwnerMembers = -join($SubSiteName, " Subsite Usage Web Members")
$SubSiteOwnerVisitors = -join($SubSiteName, " Subsite Usage Web Visitors")

$SubSiteFullUrl = -join($SiteIntegrationUrl, "/", $SubSiteURL)

# ---------------------------------------------------------------------------------------------------------------
#connect to the web site using the stored credentials
Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
Write-host "   CONNECTED SITE:", $SiteIntegrationUrl  -ForegroundColor Yellow

$Myctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteIntegrationUrl)

$Myctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
$Myctx.RequestTimeout = 1000000 # milliseconds
$MyspoRootweb = $Myctx.Web
$Myctx.Load($MyspoRootweb)
$Myctx.ExecuteQuery()

Write-Host " "
Write-Host " ---------------------------------------------------------"
Write-Host "  >>>> # Server Version:" $Myctx.ServerVersion " # <<<<<<" -ForegroundColor Green
Write-Host " ---------------------------------------------------------"
Write-Host " "

Write-host " -------------------------------------------------------- "
Write-host "   -->> RootSite:", $MyspoRootweb.URL -ForegroundColor green

Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- START THE SUBSITE CREATION  --- " -ForegroundColor green
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green


$SiteExists = Check-SiteExists $SubSiteFullUrl $cred

if($SiteExists -ne $true)
{

    Write-host "   NEW SITE URL TO CREATE:", $SubSiteFullUrl  -ForegroundColor Yellow
    $Subsite = New-Object Microsoft.SharePoint.Client.WebCreationInformation
    $Subsite.WebTemplate = "STS#0"
    $Subsite.Title = $SubSiteTitle
    $Subsite.Url = $SubSiteURL
    $Subsite.Language = "1033"
    $Subsite.Description = $SubSiteTitle

    $SubWeb = $Myctx.Web.Webs.Add($Subsite)
     $Myctx.Load($SubWeb)
    Try{
        $Myctx.ExecuteQuery()
         Write-host " "
        Write-host "     >> Success info creating site for $SubSiteURL" -ForegroundColor green
    }
    Catch{
        Write-host "     >> Error info creating subsite for $SubSiteURL - $_.Exception.Message" -ForegroundColor red
    }

    $context = New-Object Microsoft.SharePoint.Client.ClientContext($SubSiteFullUrl)
    $context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName,$cred.Password)
    $web = $context.web
    $context.load($web)
   
    Write-host " "
    Write-host "   Implement the Top menu navigation" -ForegroundColor green
    $web.Navigation.UseShared = $true
    $context.ExecuteQuery();
   
    Write-host " "
    Write-host "   Implement the Access Request settings: ", $EmailAddressAccessRequest -ForegroundColor green
    $Web.RequestAccessEmail = $EmailAddressAccessRequest
    $web.breakroleinheritance($false, $false)
    $web.update()
    $context.ExecuteQuery();

    $AllSiteCollectionGroups = $web.SiteGroups
    $context.Load($AllSiteCollectionGroups)
    $context.executeQuery()
    
    $existingRootSiteOwnerGroup = $AllSiteCollectionGroups.getByName($RootSiteOwnerGroup)
    Write-host " "
    Write-host "   Default Root site group", $existingRootSiteOwnerGroup -ForegroundColor green

    Write-host " "
    $PermissionLevel = $context.Web.RoleDefinitions.GetByName("Full Control")

    #Bind Permission Level to Group
    $RoleDefBind = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($context)
    $RoleDefBind.Add($PermissionLevel)
    $Assignments = $context.Web.RoleAssignments
    $RoleAssignOneNote = $Assignments.Add($existingRootSiteOwnerGroup,$RoleDefBind)
    $context.Load($existingRootSiteOwnerGroup)
    #send the request containing all operations to the server
    try{
        $context.executeQuery()
         Write-host " "
        write-host "     >> Success info: Added Root site group with Full Control" -foregroundcolor green
    }
    catch{
        Write-host " "
        write-host "     >> Error info: $($_.Exception.Message)" -foregroundcolor red
    }

   
    #Create new groups
    $MysiteGroups = $SubSiteGroupOwners, $SubSiteGroupMembers, $SubSiteGroupVisitors
    foreach ($siteGroup in $MysiteGroups){
        if ($siteGroup -like "*Web Visitors")
        {
            Write-host " "
            Write-host "   Creation of the Visitors group", $SubSiteGroupVisitors -ForegroundColor green
            $gci = New-Object Microsoft.SharePoint.Client.GroupCreationInformation
            $gci.Title = $siteGroup
            $gci.Description = $siteGroup
             $siteGroup = $context.Web.SiteGroups.Add($gci)

            $PermissionLevel = $context.Web.RoleDefinitions.GetByName("Read")

            #Bind Permission Level to Group
            $RoleDefBind = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($context)
            $RoleDefBind.Add($PermissionLevel)
            $Assignments = $context.Web.RoleAssignments
            $RoleAssignOneNote = $Assignments.Add($siteGroup,$RoleDefBind)
            $context.Load($siteGroup)
            $context.Web.Update()
            #send the request containing all operations to the server
            try{
                $context.executeQuery()
                write-host "     >> Success info: Added visitors group" -foregroundcolor green
            }
             catch{
                write-host "     >> Error info: $($_.Exception.Message)" -foregroundcolor red
            }
         }
        
        if ($siteGroup -like "*Web Members")
         {
            Write-host " "
            Write-host "   Creation of the Members group", $SubSiteGroupMembers -ForegroundColor green
            $gci = New-Object Microsoft.SharePoint.Client.GroupCreationInformation
            $gci.Title = $siteGroup
            $gci.Description = $siteGroup
            $siteGroup = $context.Web.SiteGroups.Add($gci)

            $PermissionLevel = $context.Web.RoleDefinitions.GetByName("Edit")
             
            #Bind Permission Level to Group
            $RoleDefBind = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($context)
            $RoleDefBind.Add($PermissionLevel)
            $Assignments = $context.Web.RoleAssignments
            $RoleAssignOneNote = $Assignments.Add($siteGroup,$RoleDefBind)
            $context.Load($siteGroup)
            $context.Web.Update()
            #send the request containing all operations to the server
            try{
                $context.executeQuery()
                write-host "     >> Success info: Added members group" -foregroundcolor green
            }
            catch{
                write-host "     >> Error info: $($_.Exception.Message)" -foregroundcolor red
            }
         }
        
        if ($siteGroup -like "*Web Owners")
         {
            Write-host " "
            Write-host "   Creation of the Owners group", $SubSiteGroupOwners -ForegroundColor green
            $gci = New-Object Microsoft.SharePoint.Client.GroupCreationInformation
            $gci.Title = $siteGroup
            $gci.Description = $siteGroup
            $siteGroup = $context.Web.SiteGroups.Add($gci)

            $PermissionLevel = $context.Web.RoleDefinitions.GetByName("Full Control")
             
            #Bind Permission Level to Group
            $RoleDefBind = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($context)
            $RoleDefBind.Add($PermissionLevel)
            $Assignments = $context.Web.RoleAssignments
            $RoleAssignOneNote = $Assignments.Add($siteGroup,$RoleDefBind)
            $context.Load($siteGroup)
             $context.Web.Update()
            #send the request containing all operations to the server
            try{
                 $context.executeQuery()
                write-host "     >> Success info: Added owners group" -foregroundcolor green
             }
            catch{
                write-host "     >> Error info: $($_.Exception.Message)" -foregroundcolor red
             }
        }
    }

    Write-host " "
    Write-host "   Get the Site groups" -ForegroundColor green

    $context.Load($AllSiteCollectionGroups)
    $context.executeQuery()


    Write-host " "
    Write-host "   Update the Groups owners to:",  $existingRootSiteOwnerGroup.Id -ForegroundColor green
    $MyOwnersGroup = $AllSiteCollectionGroups.GetByName($SubSiteGroupOwners)
    $MyMembersGroup = $AllSiteCollectionGroups.GetByName($SubSiteGroupMembers)
    $MyVisitorsGroup = $AllSiteCollectionGroups.GetByName($SubSiteGroupVisitors)
   
    $MyOwnersGroup.Owner = $existingRootSiteOwnerGroup
    $MyOwnersGroup.Update()
    $MyMembersGroup.Owner = $existingRootSiteOwnerGroup
    $MyMembersGroup.Update()
    $MyVisitorsGroup.Owner = $existingRootSiteOwnerGroup
     $MyVisitorsGroup.Update()
    $context.executeQuery()

    Write-host " "
    Write-host "   >>>>> in Case of error, you have to go on the default group page: $($SubSiteFullUrl)/_layouts/15/permsetup.aspx    " -ForegroundColor magenta  # : /_layouts/15/permsetup.aspx   
   
    Write-host " "
    Write-host "   Define the Default SPWeb groups" -ForegroundColor green

    $context.Load($web)
    $context.executeQuery()

    Write-host "  Check the values !!!"
    Write-host "      >>> AssociatedVisitorGroup:", $web.AssociatedVisitorGroup.Id -ForegroundColor Magenta
    Write-host "      >>> AssociatedMemberGroup:", $web.AssociatedMemberGroup.Id -ForegroundColor Magenta
    Write-host "      >>> AssociatedMemberGroup:", $web.AssociatedOwnerGroup.Id -ForegroundColor Magenta

    Write-host " "
    Write-host "   Define the Visitors group:", $MyVisitorsGroup.Id -ForegroundColor green
    $web.AssociatedVisitorGroup = $MyVisitorsGroup
    $web.AssociatedVisitorGroup.Update()

    Write-host " "
    Write-host "   Define the Members group:", $MyMembersGroup.Id -ForegroundColor green
    $web.AssociatedMemberGroup = $MyMembersGroup
    $web.AssociatedMemberGroup.Update()

    Write-host " "
    Write-host "   Define the Owners group:", $MyOwnersGroup.Id -ForegroundColor green
    $web.AssociatedOwnerGroup = $MyOwnersGroup
    $web.AssociatedOwnerGroup.Update()

    $web.Update()
    $context.executeQuery()


    #Create the Doc Lib
    Write-host " "
    Write-host "   Create Doc Lib:", $DocLibTitle -ForegroundColor green
    Create-SPWebList  $DocLibTitle $DocLibTitleLong 101 $context

    $MyList = $context.Web.Lists.GetByTitle($DocLibTitle)
    $context.Load($MyList)
    $context.executeQuery()   
    $MyList.Title = $DocLibTitleLong
    $MyList.OnQuickLaunch = $True
     $MyList.Update()
    $context.executeQuery()   
   
    #Rename Shared Document library
    Write-host " "
    Write-host "   Modification of the Shared Document lib" -ForegroundColor green
    $MyList = $context.Web.Lists.GetByTitle("Documents")
    $context.Load($MyList)
    $context.executeQuery()   
    $MyList.Title = "Other Documents"
    $MyList.OnQuickLaunch = $True
     $MyList.Update()
    $context.executeQuery()   
   
    #Create Contact List
    Write-host " "
    Write-host "   Creation of Contacts list" -ForegroundColor green
    Create-SPWebList  "SubsiteContacts" "Subsite Contacts" 105 $context

    $MyList = $context.Web.Lists.GetByTitle("SubsiteContacts")
    $context.Load($MyList)
    $context.executeQuery()   
    $MyList.Title = "Subsite Contacts"
    $MyList.EnableAttachments = $false
    $MyList.EnableFolderCreation = $false
    $MyList.OnQuickLaunch = $True
    $MyList.Update()
    $context.executeQuery()   
   
    #Create Links List
    Write-host " "
    Write-host "   Creation of Links list" -ForegroundColor green

    Create-SPWebList  "SubsiteLinks" "Subsite Links" 103 $context
    $MyList = $context.Web.Lists.GetByTitle("SubsiteLinks")
    $context.Load($MyList)
    $context.executeQuery()   
    $MyList.Title = "Subsite Links"
    $MyList.EnableAttachments = $false
    $MyList.EnableFolderCreation = $false
    $MyList.OnQuickLaunch = $false
     $MyList.Update()
    $context.executeQuery()   
   
    #Create Calendar List
    Write-host " "
    Write-host "   Creation of Calendar list" -ForegroundColor green

    Create-SPWebList  "SubsiteCalendar" "Subsite Calendar" 106 $context
    $MyList = $context.Web.Lists.GetByTitle("SubsiteCalendar")
    $context.Load($MyList)
    $context.executeQuery()   
    $MyList.Title = "Subsite Calendar"
    $MyList.EnableAttachments = $false
    $MyList.EnableFolderCreation = $false
    $MyList.OnQuickLaunch = $True
    $MyList.Update()
    $context.executeQuery()   

    Write-host " "
    Write-host "   Start the Navigation Cleanup" -ForegroundColor green
   
    $QuickLaunchNodes = $web.Navigation.QuickLaunch
    $context.Load($QuickLaunchNodes)
    #send the request containing all operations to the server
    $context.executeQuery()
    for($i=$QuickLaunchNodes.Count-1;$i -ge 0; $i--)
    {
        write-host "     >>> MenuItem $($QuickLaunchNodes[$i].Title) - ID: $($QuickLaunchNodes[$i].Id)"  -foregroundcolor green
        #write-host "          >>> MenuItem Children $($QuickLaunchNodes[$i].Children) "  -foregroundcolor green

        switch ($QuickLaunchNodes[$i].Title)
        {
            "Home" {
                    $QuickLaunchNodes[$i].DeleteObject()
                    $context.executeQuery()
                    write-host "           >>> MenuItem $($QuickLaunchNodes[$i].Title) Link Found !!!!" -foregroundcolor red
            }
             "Recent" {
                    $QuickLaunchNodes[$i].DeleteObject()
                    $context.executeQuery()
                     write-host "           >>> MenuItem $($QuickLaunchNodes[$i].Title) Link Found !!!!" -foregroundcolor red
            }
             "Pages" {
                    $QuickLaunchNodes[$i].DeleteObject()
                    $context.executeQuery()
                     write-host "           >>> MenuItem $($QuickLaunchNodes[$i].Title) Link Found !!!!" -foregroundcolor red
             }
            "Site contents" {
                    $QuickLaunchNodes[$i].DeleteObject()
                    $context.executeQuery()
                    write-host "           >>> MenuItem $($QuickLaunchNodes[$i].Title) Link Found !!!!" -foregroundcolor red
            }
        }
    }

    Write-host "   Add the new Home Link into the Navigation Menu", $SubSiteFullUrl -ForegroundColor green

    $NavigationNode = New-Object Microsoft.SharePoint.Client.NavigationNodeCreationInformation
    $NavigationNode.Title = "Subsite Home"
    $NavigationNode.Url = $SubSiteFullUrl
    #$NavigationNode.AsLastNode = $true         
    $context.Load($QuickLaunchNodes.Add($NavigationNode))
    $context.executeQuery()   

    Write-host "   Add the Link into the Subsite Navigation Menu", $SiteIntegrationUrl -ForegroundColor green
    $QuickLaunchNodes = $Myctx.web.Navigation.QuickLaunch
    $Myctx.Load($QuickLaunchNodes)
    $Myctx.executeQuery()   

    $NavigationNode = New-Object Microsoft.SharePoint.Client.NavigationNodeCreationInformation
    $NavigationNode.Title = $SubSiteName
     $NavigationNode.Url = $SubSiteFullUrl
    $NavigationNode.AsLastNode = $true         
    $Myctx.Load($QuickLaunchNodes.Add($NavigationNode))
    $Myctx.executeQuery()   
   
}
else
{
     Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-host " ====>> THE SUBSITE IS YET CREATED:", $SubSiteFullUrl -ForegroundColor red

}


Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green


Script PowerShell basé sur PnP

Les sources utilisées pour celui-ci sont:

A adapter selon vos besoins

if (-not (Get-Module -ListAvailable -Name SharePointPnPPowerShellOnline))
{
    Install-Module SharePointPnPPowerShellOnline
}
Import-Module SharePointPnPPowerShellOnline


# VALUE TO ADAPT !!!!!
# --------------------------------------------------------------------------------------------
$SiteIntegrationUrl ="https://tenant.sharepoint.com/sites/SiteCollection/Subsite1"
$SubSiteURL = "testsubsite"
$SubSiteName ="_TESTSUBSITE"
$EmailAddressAccessRequest = "emailaddresstosupport@domain.com"
$RootSiteOwnerGroup = "Root Site Collection Owners"
# --------------------------------------------------------------------------------------------

#Custom Function to Check if Site Collection Exists in Given URL
Function Check-SiteExists($MySiteURL, $MyCredentials)
{
    Try {
            Connect-PnPOnline -Url $MySiteURL -Credentials $MyCredentials
            Return $True
        }
    Catch [Exception] {
      Write-host " >>>> ERROR MESSAGE:", $_.Exception.Message -f Red
      Return $False
     }       
}

# ---------------------------------------------------------------------------------------------------------------


#get and save your O365 credentials
[string]$username = "AdminSiteCollection@tenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

$DocLibTitleLong = "Given Documents"

$DocLibTitle = -join($SubSiteURL, "GivenDocuments")
$DocLibTitleLong = -join($SubSiteName, " Given Documents")
$SubSiteTitle = -join($SubSiteName, " - Subsite Usage")

$SubSiteOwnerOwners = -join($SubSiteName, " Subsite Usage Web Owners")
$SubSiteOwnerMembers = -join($SubSiteName, " Subsite Usage Web Members")
$SubSiteOwnerVisitors = -join($SubSiteName, " Subsite Usage Web Visitors")

$siteUrl = -join($SiteIntegrationUrl, "/", $SubSiteURL)

# ---------------------------------------------------------------------------------------------------------------
#connect to the web site using the stored credentials
Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
Write-host "   CONNECTED SITE:", $SiteIntegrationUrl  -ForegroundColor Yellow
Connect-PnPOnline -Url $SiteIntegrationUrl -Credential $cred

Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- START THE SUBSITE CREATION  :", $siteUrl -ForegroundColor green
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green


$SiteExists = Check-SiteExists $siteUrl $cred
if($SiteExists -ne $true)
{
    Write-host "   NEW SITE URL TO CREATE:", $siteUrl  -ForegroundColor Yellow
    #Create the subWeb for the Integration site
    New-PnPWeb -Template "STS#0" -Title $SubSiteTitle -Description $SubSiteTitle -Url $SubSiteURL -Locale "1033" -InheritNavigation -BreakInheritance
    Add-PnPNavigationNode -Title $SubSiteTitle -Url $siteUrl -Location "QuickLaunch"

    #connect to the new web site using the stored credentials
     Write-host " "
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-host " ---- CONNECT THE SITE --- " -ForegroundColor green
    Write-host "   CONNECTED SITE:", $siteUrl  -ForegroundColor green
    Connect-PnPOnline -Url $siteUrl -Credentials $cred
    $MyCurrentWeb = Get-PnPWeb

    #configure the Access request system
    Set-PnPRequestAccessEmails -Emails $EmailAddressAccessRequest
   
    #Create the Doc Lib
    Write-host " "
    Write-host "   Create Doc Lib:", $DocLibTitle -ForegroundColor green
    New-PnPList -Title $DocLibTitle -Template DocumentLibrary -OnQuickLaunch
    Set-PnPList -Identity $DocLibTitle -Title $DocLibTitleLong -EnableVersioning $true -MajorVersions 100 -EnableMinorVersions $false

    #Rename Shared Document library
    Write-host " "
    Write-host "   Modification of the Shared Document lib" -ForegroundColor green
    Set-PnPList -Identity "Documents" -Title "Other Documents" -EnableVersioning $true -MajorVersions 100 -EnableMinorVersions $false

    #Create Contact List
    Write-host " "
    Write-host "   Creation of Contacts list" -ForegroundColor green
    New-PnPList -Title "SubsiteContacts" -Template Contacts -OnQuickLaunch
    Set-PnPList -Identity "SubsiteContacts" -Title "Subsite Contacts"

    #Create Links List
    Write-host " "
    Write-host "   Creation of Links list" -ForegroundColor green
    New-PnPList -Title "SubsiteLinks" -Template Links
    Set-PnPList -Identity "SubsiteLinks" -Title "Subsite Links"

    #Create Calendar List
    Write-host " "
    Write-host "   Creation of Calendar list" -ForegroundColor green
    New-PnPList -Title "SubsiteCalendar" -Template "Events" -OnQuickLaunch
    Set-PnPList -Identity "SubsiteCalendar" -Title "Subsite Calendar"

    #Change the Navifation menu
    Write-host " "
    Write-host "   Modification of the Navigation Menu" -ForegroundColor green
    Remove-PnPNavigationNode -Title "Pages" -Location QuickLaunch -Force
    Remove-PnPNavigationNode -Title "Recent" -Location QuickLaunch -Force
    Remove-PnPNavigationNode -Title "Site contents" -Location QuickLaunch -Force
    Remove-PnPNavigationNode -Title "Home" -Location QuickLaunch -Force
    Add-PnPNavigationNode -Title "Subsite Home" -Url $siteUrl -Location "QuickLaunch" -First

    #Configure the permission set by default
    Write-host " "
    Write-host "   Get the OwnerGroup from the root site", $RootSiteOwnerGroup -ForegroundColor green
    $owner = Get-PnPGroup -Identity $RootSiteOwnerGroup  #(Get-PnPContext).Credentials.UserName
     Write-host "    >>> Group ID:", $owner.ID -ForegroundColor green
    Set-PnPWebPermission -Identity $MyCurrentWeb.Id -Group $RootSiteOwnerGroup -AddRole "Full Control" 
   
    #Create default groups for the new web
    #here, by default owner will be the person provisioning the groups
    Write-host " "
    Write-host "   Creation of the Owners group", $SubSiteOwnerOwners -ForegroundColor green
    $ownerGroup = New-PnPGroup -Title $SubSiteOwnerOwners -Owner $RootSiteOwnerGroup
    Set-PnPGroup -Identity $SubSiteOwnerOwners -SetAssociatedGroup Owners -AddRole "Full Control" 

    Write-host " "
    Write-host "   Creation of the Members group", $SubSiteOwnerOwners -ForegroundColor green
    $memberGroup = New-PnPGroup -Title $SubSiteOwnerMembers -Owner $RootSiteOwnerGroup
    Set-PnPGroup -Identity $SubSiteOwnerMembers -SetAssociatedGroup Members -AddRole "Edit"

    Write-host " "
    Write-host "   Creation of the Visitors group", $SubSiteOwnerOwners -ForegroundColor green
    $visitorGroup = New-PnPGroup -Title $SubSiteOwnerVisitors -Owner $RootSiteOwnerGroup
    Set-PnPGroup -Identity $SubSiteOwnerVisitors -SetAssociatedGroup Visitors -AddRole "Read"

}
else
{
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
    Write-host " ====>> THE SUBSITE IS YET CREATED:", $siteUrl -ForegroundColor red

}

Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
Write-host " ---- DISCONNECT THE SITE --- " -ForegroundColor green
# Quit the script and disconnect from the site
Disconnect-PnPOnline

Write-host " "
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green


Comme vous pouvez le constater, le script PnP est bien plus court, puisque cette solution sert d’interface à CSOM. En revanche il vous demandera plus de travail de maintenance.

Fabrice Romelard [MVP]

Office 365: Comment exporter tous les comptes Azure Active Directory ayant une license via PowerShell

Basé sur les pages suivantes:

Voici un script PowerShell permettant de sortir un fichier CSV ayant tous les comptes utilisateurs de votre tenant avec les propriétés suivantes (vous pouvez l’adapter selon votre besoin):

  • UserPrincipalName: Tenant login
  • DisplayName: User Display Name
  • AADCountryName: Countryname defined in Azure AD
  • UserLocationCountryName: Country name of the AAD property UsageLocation
  • UsageLocationCountryCode: ISO Format of the AAD property UsageLocation

[string]$username = "YourAdminAccount@YourTenant.onmicrosoft.com"
[string]$PwdTXTPath = "D:\SECUREDPWD\ExportedPWD-$($username).txt"


$isoCountries = @{
    "AF" = "Afghanistan";
    "AX" = "Aland Islands";
    "AL" = "Albania";
    "DZ" = "Algeria";
    "AS" = "American Samoa";
    "AD" = "Andorra";
    "AO" = "Angola";
    "AI" = "Anguilla";
    "AQ" = "Antarctica";
    "AG" = "Antigua And Barbuda";
    "AR" = "Argentina";
    "AM" = "Armenia";
    "AW" = "Aruba";
    "AU" = "Australia";
    "AT" = "Austria";
     "AZ" = "Azerbaijan";
    "BS" = "Bahamas";
    "BH" = "Bahrain";
    "BD" = "Bangladesh";
    "BB" = "Barbados";
    "BY" = "Belarus";
    "BE" = "Belgium";
    "BZ" = "Belize";
    "BJ" = "Benin";
    "BM" = "Bermuda";
    "BT" = "Bhutan";
    "BO" = "Bolivia";
    "BA" = "Bosnia And Herzegovina";
    "BW" = "Botswana";
    "BV" = "Bouvet Island";
    "BR" = "Brazil";
    "IO" = "British Indian Ocean Territory";
    "BN" = "Brunei Darussalam";
    "BG" = "Bulgaria";
    "BF" = "Burkina Faso";
    "BI" = "Burundi";
    "KH" = "Cambodia";
    "CM" = "Cameroon";
    "CA" = "Canada";
    "CV" = "Cape Verde";
    "KY" = "Cayman Islands";
    "CF" = "Central African Republic";
    "TD" = "Chad";
     "CL" = "Chile";
    "CN" = "China";
    "CX" = "Christmas Island";
    "CC" = "Cocos (Keeling) Islands";
    "CO" = "Colombia";
    "KM" = "Comoros";
    "CG" = "Congo";
    "CD" = "Congo, Democratic Republic";
    "CK" = "Cook Islands";
    "CR" = "Costa Rica";
    "CI" = "Cote D'Ivoire";
    "HR" = "Croatia";
    "CU" = "Cuba";
    "CY" = "Cyprus";
    "CZ" = "Czech Republic";
    "DK" = "Denmark";
    "DJ" = "Djibouti";
    "DM" = "Dominica";
    "DO" = "Dominican Republic";
    "EC" = "Ecuador";
    "EG" = "Egypt";
    "SV" = "El Salvador";
    "GQ" = "Equatorial Guinea";
    "ER" = "Eritrea";
    "EE" = "Estonia";
    "ET" = "Ethiopia";
    "FK" = "Falkland Islands (Malvinas)";
    "FO" = "Faroe Islands";
    "FJ" = "Fiji";
    "FI" = "Finland";
    "FR" = "France";
    "GF" = "French Guiana";
    "PF" = "French Polynesia";
    "TF" = "French Southern Territories";
    "GA" = "Gabon";
    "GM" = "Gambia";
    "GE" = "Georgia";
    "DE" = "Germany";
    "GH" = "Ghana";
    "GI" = "Gibraltar";
    "GR" = "Greece";
    "GL" = "Greenland";
    "GD" = "Grenada";
    "GP" = "Guadeloupe";
    "GU" = "Guam";
    "GT" = "Guatemala";
     "GG" = "Guernsey";
    "GN" = "Guinea";
    "GW" = "Guinea-Bissau";
    "GY" = "Guyana";
    "HT" = "Haiti";
    "HM" = "Heard Island & Mcdonald Islands";
    "VA" = "Holy See (Vatican City State)";
    "HN" = "Honduras";
    "HK" = "Hong Kong";
    "HU" = "Hungary";
    "IS" = "Iceland";
    "IN" = "India";
    "ID" = "Indonesia";
    "IR" = "Iran, Islamic Republic Of";
    "IQ" = "Iraq";
    "IE" = "Ireland";
    "IM" = "Isle Of Man";
    "IL" = "Israel";
    "IT" = "Italy";
    "JM" = "Jamaica";
    "JP" = "Japan";
    "JE" = "Jersey";
    "JO" = "Jordan";
    "KZ" = "Kazakhstan";
    "KE" = "Kenya";
    "KI" = "Kiribati";
    "KR" = "Korea";
    "KW" = "Kuwait";
    "KG" = "Kyrgyzstan";
     "LA" = "Lao People's Democratic Republic";
    "LV" = "Latvia";
    "LB" = "Lebanon";
    "LS" = "Lesotho";
    "LR" = "Liberia";
    "LY" = "Libyan Arab Jamahiriya";
    "LI" = "Liechtenstein";
    "LT" = "Lithuania";
    "LU" = "Luxembourg";
    "MO" = "Macao";
    "MK" = "Macedonia";
    "MG" = "Madagascar";
    "MW" = "Malawi";
    "MY" = "Malaysia";
    "MV" = "Maldives";
     "ML" = "Mali";
    "MT" = "Malta";
    "MH" = "Marshall Islands";
    "MQ" = "Martinique";
    "MR" = "Mauritania";
    "MU" = "Mauritius";
    "YT" = "Mayotte";
    "MX" = "Mexico";
    "FM" = "Micronesia, Federated States Of";
    "MD" = "Moldova";
    "MC" = "Monaco";
    "MN" = "Mongolia";
    "ME" = "Montenegro";
    "MS" = "Montserrat";
    "MA" = "Morocco";
    "MZ" = "Mozambique";
    "MM" = "Myanmar";
    "NA" = "Namibia";
    "NR" = "Nauru";
    "NP" = "Nepal";
    "NL" = "Netherlands";
    "AN" = "Netherlands Antilles";
    "NC" = "New Caledonia";
    "NZ" = "New Zealand";
    "NI" = "Nicaragua";
    "NE" = "Niger";
    "NG" = "Nigeria";
    "NU" = "Niue";
    "NF" = "Norfolk Island";
    "MP" = "Northern Mariana Islands";
    "NO" = "Norway";
     "OM" = "Oman";
    "PK" = "Pakistan";
    "PW" = "Palau";
    "PS" = "Palestinian Territory, Occupied";
    "PA" = "Panama";
    "PG" = "Papua New Guinea";
    "PY" = "Paraguay";
    "PE" = "Peru";
    "PH" = "Philippines";
    "PN" = "Pitcairn";
    "PL" = "Poland";
    "PT" = "Portugal";
    "PR" = "Puerto Rico";
    "QA" = "Qatar";
    "RE" = "Reunion";
    "RO" = "Romania";
    "RU" = "Russian Federation";
    "RW" = "Rwanda";
    "BL" = "Saint Barthelemy";
    "SH" = "Saint Helena";
    "KN" = "Saint Kitts And Nevis";
    "LC" = "Saint Lucia";
    "MF" = "Saint Martin";
    "PM" = "Saint Pierre And Miquelon";
    "VC" = "Saint Vincent And Grenadines";
    "WS" = "Samoa";
    "SM" = "San Marino";
    "ST" = "Sao Tome And Principe";
    "SA" = "Saudi Arabia";
    "SN" = "Senegal";
    "RS" = "Serbia";
    "SC" = "Seychelles";
    "SL" = "Sierra Leone";
    "SG" = "Singapore";
     "SK" = "Slovakia";
    "SI" = "Slovenia";
    "SB" = "Solomon Islands";
    "SO" = "Somalia";
    "ZA" = "South Africa";
    "GS" = "South Georgia And Sandwich Isl.";
    "ES" = "Spain";
     "LK" = "Sri Lanka";
    "SD" = "Sudan";
    "SR" = "Suriname";
    "SJ" = "Svalbard And Jan Mayen";
    "SZ" = "Swaziland";
     "SE" = "Sweden";
    "CH" = "Switzerland";
    "SY" = "Syrian Arab Republic";
    "TW" = "Taiwan";
    "TJ" = "Tajikistan";
     "TZ" = "Tanzania";
    "TH" = "Thailand";
    "TL" = "Timor-Leste";
    "TG" = "Togo";
    "TK" = "Tokelau";
    "TO" = "Tonga";
    "TT" = "Trinidad And Tobago";
    "TN" = "Tunisia";
    "TR" = "Turkey";
    "TM" = "Turkmenistan";
    "TC" = "Turks And Caicos Islands";
    "TV" = "Tuvalu";
    "UG" = "Uganda";
    "UA" = "Ukraine";
    "AE" = "United Arab Emirates";
    "GB" = "United Kingdom";
    "US" = "United States";
    "UM" = "United States Outlying Islands";
    "UY" = "Uruguay";
    "UZ" = "Uzbekistan";
    "VU" = "Vanuatu";
    "VE" = "Venezuela";
    "VN" = "Viet Nam";
    "VG" = "Virgin Islands, British";
    "VI" = "Virgin Islands, U.S.";
    "WF" = "Wallis And Futuna";
    "EH" = "Western Sahara";
    "YE" = "Yemen";
    "ZM" = "Zambia";
     "ZW" = "Zimbabwe"
};

function GetCountryName ([string] $countryCode) {
    if ($isoCountries.Contains($countryCode)) {
        return $isoCountries[$countryCode].ToLower();
    } else {
         return $countryCode.ToLower();
    }
}

#GetCountryName "FR"

import-module MSOnline

$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $secureStringPwd

connect-msolservice -credential $creds

Get-MsolUser  -All | Where-Object {$_.isLicensed -eq "True"} |Select-Object -Property UserPrincipalName, DisplayName, @{name='AADCountryName';Expression={$_.Country.ToLower()}}, @{name='UserLocationCountryName';Expression={GetCountryName($_.UsageLocation)}},  @{name='UsageLocationCountryCode';Expression={$_.UsageLocation}} | Export-Csv -Path "Office365AzureADLicensedAccounts.csv"

Excel sera alors votre meilleur ami pour travailler ce fichier selon votre besoin.

English version available here:

Fabrice Romelard [MVP]

PowerShell: Comment avoir le Country Name depuis un Country Code

Une demande classique en PowerShell est de pouvoir sortir une liste avec le nom de pays, mais en ayant en source uniquement le code ISO de celui-ci.

Une solution rapide et souple est la suivante en me basant sur le script suivant:

Il vous suffit alors d’intégrer la fonction suivants dans votre script et de l’utiliser dans celui-ci:

$isoCountries = @{
    "AF" = "Afghanistan";
    "AX" = "Aland Islands";
    "AL" = "Albania";
    "DZ" = "Algeria";
    "AS" = "American Samoa";
    "AD" = "Andorra";
    "AO" = "Angola";
    "AI" = "Anguilla";
    "AQ" = "Antarctica";
    "AG" = "Antigua And Barbuda";
    "AR" = "Argentina";
    "AM" = "Armenia";
    "AW" = "Aruba";
    "AU" = "Australia";
    "AT" = "Austria";
    "AZ" = "Azerbaijan";
     "BS" = "Bahamas";
    "BH" = "Bahrain";
    "BD" = "Bangladesh";
    "BB" = "Barbados";
    "BY" = "Belarus";
    "BE" = "Belgium";
    "BZ" = "Belize";
    "BJ" = "Benin";
    "BM" = "Bermuda";
    "BT" = "Bhutan";
    "BO" = "Bolivia";
    "BA" = "Bosnia And Herzegovina";
    "BW" = "Botswana";
    "BV" = "Bouvet Island";
    "BR" = "Brazil";
    "IO" = "British Indian Ocean Territory";
    "BN" = "Brunei Darussalam";
    "BG" = "Bulgaria";
    "BF" = "Burkina Faso";
    "BI" = "Burundi";
    "KH" = "Cambodia";
    "CM" = "Cameroon";
    "CA" = "Canada";
    "CV" = "Cape Verde";
    "KY" = "Cayman Islands";
    "CF" = "Central African Republic";
    "TD" = "Chad";
    "CL" = "Chile";
    "CN" = "China";
    "CX" = "Christmas Island";
    "CC" = "Cocos (Keeling) Islands";
    "CO" = "Colombia";
    "KM" = "Comoros";
    "CG" = "Congo";
    "CD" = "Congo, Democratic Republic";
    "CK" = "Cook Islands";
    "CR" = "Costa Rica";
    "CI" = "Cote D'Ivoire";
    "HR" = "Croatia";
    "CU" = "Cuba";
    "CY" = "Cyprus";
    "CZ" = "Czech Republic";
    "DK" = "Denmark";
     "DJ" = "Djibouti";
    "DM" = "Dominica";
    "DO" = "Dominican Republic";
    "EC" = "Ecuador";
    "EG" = "Egypt";
    "SV" = "El Salvador";
    "GQ" = "Equatorial Guinea";
    "ER" = "Eritrea";
    "EE" = "Estonia";
    "ET" = "Ethiopia";
    "FK" = "Falkland Islands (Malvinas)";
    "FO" = "Faroe Islands";
    "FJ" = "Fiji";
    "FI" = "Finland";
    "FR" = "France";
    "GF" = "French Guiana";
    "PF" = "French Polynesia";
    "TF" = "French Southern Territories";
    "GA" = "Gabon";
    "GM" = "Gambia";
    "GE" = "Georgia";
    "DE" = "Germany";
    "GH" = "Ghana";
    "GI" = "Gibraltar";
    "GR" = "Greece";
    "GL" = "Greenland";
    "GD" = "Grenada";
    "GP" = "Guadeloupe";
    "GU" = "Guam";
    "GT" = "Guatemala";
    "GG" = "Guernsey";
    "GN" = "Guinea";
    "GW" = "Guinea-Bissau";
    "GY" = "Guyana";
    "HT" = "Haiti";
    "HM" = "Heard Island & Mcdonald Islands";
    "VA" = "Holy See (Vatican City State)";
    "HN" = "Honduras";
    "HK" = "Hong Kong";
    "HU" = "Hungary";
    "IS" = "Iceland";
    "IN" = "India";
    "ID" = "Indonesia";
    "IR" = "Iran, Islamic Republic Of";
    "IQ" = "Iraq";
    "IE" = "Ireland";
    "IM" = "Isle Of Man";
    "IL" = "Israel";
    "IT" = "Italy";
    "JM" = "Jamaica";
    "JP" = "Japan";
    "JE" = "Jersey";
    "JO" = "Jordan";
    "KZ" = "Kazakhstan";
    "KE" = "Kenya";
    "KI" = "Kiribati";
    "KR" = "Korea";
    "KW" = "Kuwait";
    "KG" = "Kyrgyzstan";
    "LA" = "Lao People's Democratic Republic";
    "LV" = "Latvia";
    "LB" = "Lebanon";
     "LS" = "Lesotho";
    "LR" = "Liberia";
    "LY" = "Libyan Arab Jamahiriya";
    "LI" = "Liechtenstein";
    "LT" = "Lithuania";
    "LU" = "Luxembourg";
    "MO" = "Macao";
    "MK" = "Macedonia";
    "MG" = "Madagascar";
    "MW" = "Malawi";
    "MY" = "Malaysia";
    "MV" = "Maldives";
    "ML" = "Mali";
    "MT" = "Malta";
    "MH" = "Marshall Islands";
    "MQ" = "Martinique";
    "MR" = "Mauritania";
    "MU" = "Mauritius";
    "YT" = "Mayotte";
    "MX" = "Mexico";
    "FM" = "Micronesia, Federated States Of";
    "MD" = "Moldova";
    "MC" = "Monaco";
    "MN" = "Mongolia";
    "ME" = "Montenegro";
    "MS" = "Montserrat";
    "MA" = "Morocco";
    "MZ" = "Mozambique";
    "MM" = "Myanmar";
    "NA" = "Namibia";
    "NR" = "Nauru";
    "NP" = "Nepal";
    "NL" = "Netherlands";
    "AN" = "Netherlands Antilles";
    "NC" = "New Caledonia";
    "NZ" = "New Zealand";
    "NI" = "Nicaragua";
    "NE" = "Niger";
    "NG" = "Nigeria";
    "NU" = "Niue";
    "NF" = "Norfolk Island";
    "MP" = "Northern Mariana Islands";
    "NO" = "Norway";
    "OM" = "Oman";
    "PK" = "Pakistan";
    "PW" = "Palau";
    "PS" = "Palestinian Territory, Occupied";
    "PA" = "Panama";
    "PG" = "Papua New Guinea";
    "PY" = "Paraguay";
    "PE" = "Peru";
    "PH" = "Philippines";
    "PN" = "Pitcairn";
    "PL" = "Poland";
    "PT" = "Portugal";
    "PR" = "Puerto Rico";
    "QA" = "Qatar";
    "RE" = "Reunion";
    "RO" = "Romania";
    "RU" = "Russian Federation";
    "RW" = "Rwanda";
    "BL" = "Saint Barthelemy";
    "SH" = "Saint Helena";
    "KN" = "Saint Kitts And Nevis";
    "LC" = "Saint Lucia";
    "MF" = "Saint Martin";
    "PM" = "Saint Pierre And Miquelon";
    "VC" = "Saint Vincent And Grenadines";
    "WS" = "Samoa";
    "SM" = "San Marino";
    "ST" = "Sao Tome And Principe";
    "SA" = "Saudi Arabia";
    "SN" = "Senegal";
    "RS" = "Serbia";
    "SC" = "Seychelles";
    "SL" = "Sierra Leone";
    "SG" = "Singapore";
    "SK" = "Slovakia";
    "SI" = "Slovenia";
    "SB" = "Solomon Islands";
    "SO" = "Somalia";
    "ZA" = "South Africa";
    "GS" = "South Georgia And Sandwich Isl.";
    "ES" = "Spain";
    "LK" = "Sri Lanka";
    "SD" = "Sudan";
    "SR" = "Suriname";
    "SJ" = "Svalbard And Jan Mayen";
    "SZ" = "Swaziland";
    "SE" = "Sweden";
    "CH" = "Switzerland";
    "SY" = "Syrian Arab Republic";
    "TW" = "Taiwan";
    "TJ" = "Tajikistan";
    "TZ" = "Tanzania";
    "TH" = "Thailand";
    "TL" = "Timor-Leste";
    "TG" = "Togo";
    "TK" = "Tokelau";
    "TO" = "Tonga";
    "TT" = "Trinidad And Tobago";
    "TN" = "Tunisia";
    "TR" = "Turkey";
    "TM" = "Turkmenistan";
    "TC" = "Turks And Caicos Islands";
    "TV" = "Tuvalu";
    "UG" = "Uganda";
    "UA" = "Ukraine";
    "AE" = "United Arab Emirates";
    "GB" = "United Kingdom";
    "US" = "United States";
    "UM" = "United States Outlying Islands";
    "UY" = "Uruguay";
    "UZ" = "Uzbekistan";
    "VU" = "Vanuatu";
    "VE" = "Venezuela";
    "VN" = "Viet Nam";
    "VG" = "Virgin Islands, British";
    "VI" = "Virgin Islands, U.S.";
     "WF" = "Wallis And Futuna";
    "EH" = "Western Sahara";
    "YE" = "Yemen";
    "ZM" = "Zambia";
    "ZW" = "Zimbabwe"
};

function GetCountryName ([string] $countryCode) {
    if ($isoCountries.Contains($countryCode)) {
        return $isoCountries[$countryCode].ToLower();
    } else {
        return $countryCode.ToLower();
    }
}

GetCountryName "FR"

Fabrice Romelard [MVP]

Office 365: Comment supprimer un compte externe d’un site SharePoint Online en mode Extranet

Dans un Teamsite SharePoint Online, on peut inviter des utilisateurs externes à se connecter en utilisant leur propre identifiant Microsoft.

Cela fonctionne à traver des comptes de Mapping placés dans Azure Active Directory comme on le voit ci-dessous dans le Portal Azure (https://portal.azure.com):

image

Pour des besoins diverses, le propriétaire de site peut vouloir supprimer les comptes externes qui nécessite:

  • de supprimer le Mapping d’Azure AD
  • de supprimer l’utilisateur de la collection de sites

Pour faire ces deux taches, il faut passer par le site d’administration d’Office 365 avec les droits d’administrateur de SharePoint Online pour trouver le menu:

  • Resources > Sites

image

En cliquant sur la ligne, on obtient les détails du partage externe et le nombre de comptes externes invités

image

Vous pouvez alors cliquer sur Modify et voir le détail des utilisateurs invités. Il suffit de cliquer sur l’utilisateur en question pour le déplacer dans les comptes à supprimer

image

En cliquant enfin sur Save, le compte sera supprimé de la liste de mapping, mais aussi de la liste des comptes utilisateurs de la collection de sites.

Attention:

Cette suppression ne supprime pas le mapping dans Azure AD, car ce compte peut être utilisé ailleurs, dans une autre collection de sites.

De ce fait, si vous souhaitez vraiment faire un nettoyage complet, il faudra supprimer la référence d’Azure AD avec les permissions adéquates.

Fabrice Romelard [MVP]

Office 365: Comment reconfigurer le lien “Bloc-notes” d’un teamsite

Dans la vie d’un site SharePoint Online, il peut arriver que le contenu bouge et passe d’un endroit à un autre (migration, déplacement, …).

Un teamsite, qu’il soit à la racine ou en sous-site subit la même évolution et il arrive que le lien “Bloc-notes” mène vers une page d’erreur sous la forme:

image

Cela vient du fait que le format de ce lien bloc-note

image

est particulier puisqu’il contient le GUID du fichier notebook similaire au lien:

Pour corriger ce lien lorsqu’il n’est plus correct, il faut aller dans le contenu de site et choisir la librarie documentaire “Pieces jointes” (ou Site assets en anglais):

image

Dans laquelle vous aurez alors le réel fichier bloc-notes de ce teamsite:

image

En cliquant sur ce fichier pour l’ouvrir:

image

vous aurez alors une URL du format:

Ainsi le GUID correct est donc bien ce qui est entre les chaines de charactères:

  • %7B
  • %7D

Vous n’avez plus qu’à modifier le lien de votre menu de gauche avec le GUID correct et l’erreur ne sera plus présente.

Attention:

Il est possible de passer par les site features pour désactiver et réactiver le notebook site, mais je ne vous garantie pas de ne pas perdre le contenu du fichier notebook. Cette méthode est expliquée ici:

Romelard Fabrice [MVP]

Office 365: Utiliser l’option “Alert Me” de la page de résultat de recherche

SharePoint Online propose de facilement créer un site de recherche (d’ailleurs inclu de base dans le site de publishing de base):

Ce site de recherche va permettre de rechercher à travers votre tenant les informations correspondant au texte donné.

image

Au bas de cette page figure une option (qui est configurable dans la WebPart de résultat):

  • “M’avertir” ou “Alert Me”

image

Cette option vous permet de paramétrer une notification par email de la recherche que vous avez effectué:

image

Vous pouvez alors paramétrer le déclencheur de l’alerte et la fréquence cet email, puis cliquer sur OK pour valider cette création.

Vous recevez une confirmation par email:

image

Suivant la fréquence choisie, vous aurez alors un email sous la forme suivante:

image

Dans le cas ou vous souhaitez supprimer cette alerte, il faut simplement cliquer sur le lien “Préferences”

image

Pour arriver alors sur la page de gestion des préférences et cliquer sur “Alerte de recherche”

image

et retrouver la liste des alertes créées

image

Attention:

  1. Si vous ne recevez pas de confirmation de création ou de mail d’alerte, il faut regarder dans les dossiers “Clutter” ou “Spam” de votre boite email.
  2. Les alertes ne fonctionnent que sur de véritables recherches. Les menus d’affinages ne sont pas supportés par ces alertes. Cet affinage fonctionne sur le jeu de résultat courant et neffectue pas de nouvelle recherche.

image

Romelard Fabrice [MVP]

Office 365: Comment télécharger l’image de profil de Delve

Dans la vie quotidienne d’un utilisateur d’Office 365, il peut rapidement être nécessaire de télécharger l’image de profil d’un utilisateur.

En effet, cette image est gérée par lui même et donc contient souvent une photo qui met en avant cet utilisateur et que lui-même a validé.

De ce fait, une autre personne peut vouloir cette image pour illustrer une news qu’il souhaite publier ou tout autre besoin similaire.

Pour cela, la première étape est de rechercher cet utilisateur via Delve:

image

Puis d’aller sur sa page de profil pour valider de visu la photo:

image

A ce moment, il faut simplement cliquer avec le bouton droit de la souris et sélectionner “Inspect element”

image

Cela va alors lancer l’outil de développement de votre navigateur et vous placer sur la ligne concernant l’objet image en question:

image

Vous avez alors l’adresse URL de l’image de profil sous le format suivant:

  • background-image: url("/mt/v3/people/profileimage?userId=login%40tenant.onmicrosoft.com&size=L");

Il faut alors simplement ajouter cette fin d’adresse à la racine suivante:

Ce qui donne au final quelque chose similaire à:

Vous aurez alors l’image affichée en grande taille:

image

Il ne vous reste plus qu’à utiliser cette image selon votre besoin.

Romelard Fabrice [MVP]

Office 365: Valeur “Country or Region” et “User Location” dans Azure AD

Office 365 est une plateforme qui intègre de nombreux modules avec des interactions potentielles qui peuvent mener à des situations compliquées.

En effet, le pays d’un utilisateur dans Office 365 est défini dans 2 champs bien distincts et cela explique certains comportements.

  • User Location

Le premier est du pure Azure AD et, dans une configuration AD Synch basique, n’est mappé à aucune paramètre de votre Active Directory interne.

Ceci est utilisé dans de nombreux outils Office 365 soumis à la validation par license ou localization, tel que les Skype Call

Il peut être aussi utilisé dans vos applications internes à travers les appels Office Graph concernant l’utilisateur (cas de personnalisation de site)

La gestion de ce champ demande des droits sur le Tenant dans Azure AD

  • Country or Region

Ce second champs le classique de Windows Active Directory associé avec le pays de l’utilisateur, du compte ou de la machine. Donc il est totalement associé avec votre AD si vous passez par AD Sync.

Ainsi, vous pouvez avoir des cas, pour lesquels ces champs ne sont plus avec les mêmes valeurs (cas d’une mutation par exemple). Les process de déplacement d’utilisateurs sont souvent bien fait pour le champs country, mais ce “User Location” est généralement oublié.

Pour confirmer cette différence, il suffit d’aller sur le portal Azure (https://portal.azure.com/), de chercher cet utilisateur et comparer les valeurs comme ci-dessous.

image

De ce fait, il convient ensuite de corriger cette différence pour revenir à une situation plus normale.

Fabrice Romelard [MVP]

Office 365: Menu d’administration non visible dans une page SharePoint

Un cas bateau qui peut rendre vos utilisateurs dingue est de ne plus avoir le menu d’administration dans une page SharePoint.

Ceci est particulièrement le cas dans un site de publishing ou dans un Teamsite avec des pages Wiki.

En effet, l’utilisateur ne pourra alors plus éditer sa page, puisqu’il n’aura que le menu suivant:

image

La première réaction est de vérifier les permissions de cet utilisateur et de vérifier que celui-ci a bien les bon droits nécessaires à cette action.

Une fois ceci effectué il faut aussi bien regarder l’adresse URL que cet utilisateur ouvre pour verifier qu’il n’est pas en mode “Preview”. Cela se vérifie avec le format:

  • xxxxx.aspx?PagePreview=true

Il faut alors demander à l’utilisateur d’enlever cela et valider que les menus sont bien de retour.

Fabrice Romelard [MVP]

Plus de Messages Page suivante »


Les 10 derniers blogs postés

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01

- Office 365: Script PowerShell pour supprimer des comptes utilisateur de collections de sites SharePoint Online par Blog Technique de Romelard Fabrice le 11-19-2018, 16:47

- Retrouvez-moi aux Microsoft experiences18 ! par Blog de Jérémy Jeanson le 11-06-2018, 22:25

- Office 365: Script PowerShell pour extraire les Teams associés à un utilisateur spécifié par Blog Technique de Romelard Fabrice le 11-06-2018, 13:37

- Office 365: Extraire les pages publiées dans un site SharePoint Online de publishing en CSV par Blog Technique de Romelard Fabrice le 11-06-2018, 11:04

- Office 365: Comment créer un jeu de Pages Modernes dans un Modern Site SharePoint Online en utilisant PowerShell depuis un fichier CSV par Blog Technique de Romelard Fabrice le 10-17-2018, 12:50

- Office 365: Comment Utiliser les Modern Pages dans un Site Intranet SharePoint basé sur le Publishing site par Blog Technique de Romelard Fabrice le 10-16-2018, 15:34

- Office 365: Comment changer le nom “Auteur” dans les pages modernes d'un Modern Site SharePoint Online par Blog Technique de Romelard Fabrice le 10-16-2018, 15:07

- Reprise des articles Codes-Sources de 2011 à 2013 par Blog de Jérémy Jeanson le 08-21-2018, 16:08

- Office 365: Modifier les jeux de couleur dans les Thèmes des pages classiques de SharePoint Online par Blog Technique de Romelard Fabrice le 08-08-2018, 17:27