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

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]

Office 365: Comment avoir un minimum de statistiques d’usage de votre site SharePoint Online

Avec Office 365 et surtout SharePoint Online, le feedback d’usage est toujours la partie pauvre de la plateforme.

Malgré tout il existe quelques manières d’avoir un minimum d’information sur l’utilisation de votre site.

Le self service pour la période très reçente

Ceci se passe directement depuis les “Site Contents”

image

Puis vous avez le lien “Site Usage” qui est dans la partie haute (dans certains cas, un message vous invite même à y aller):

image

Vous avez alors un affichage sur les 7 derniers jours, puis un detail par élément sur les 2 dernières semaines:

image

Le principe est de vous donner un trend et non une précision dans ces statistiques.

Les statistiques d’accès sur plus longue période

Cette option vous donne d’autres information, plus spécialement sur les accès (Hits) et visiteurs uniques, mais pas sur le contenu lui-même, dans un fichier Excel:

image

Pour avoir ce fichier, il faut aller cette fois dans les “Site Settings” et choisir les “Popularity Trends”:

image

Vous aurez alors les Usage Reports:

image

Si vous souhaitez plus d’information, il faudra se tourner vers d’autres outils du marché payant ou gratuits.

Attention:

Beaucoup de ces outils sont dédié pour du site Web et non pour une plateforme de content management, ainsi vous aurez peu de chance de voir le nombre de téléchargement de fichiers via ces solutions.

Fabrice Romelard [MVP]

Office 365: Reconfigure la gestion des demande d’accès dans SharePoint

Dans SharePoint Online, il est possible de déléguer la gestion des validation d’accès (Access request) à une personne ou un groupe de personnes.

Ceci se fait avec le chemin:

  • Site Settings > Site Permissions > Access Request Settings

image

Pour différentes raisons, ce système peut ne plus fonctionner correctement, comme par exemple envoyer le message correctement, mais ne pas autoriser cette personne la gestion, malgré des droits “Full control”

Bien souvent, Ce cas du à une mauvaise configuration des groupes SharePoint par défaut comme expliqué ici:

  • https://sharepoint.stackexchange.com/questions/239007/access-request-settings-is-raising-the-following-error-members-cannot-share-thi

Ainsi, il faut donc reparamétrer cette configuration des groupes par défaut en ouvrant le lien suivant:

  • http://yourServer/sites/yourSite/YourSubsite/_layouts/15/permsetup.aspx

Cette page vous propose alors la sélection "(ou création des groupes par défaut, visitors / members / owners):

image

Après avoir reparamétré les groupes par défaut, vous pouver retourner dans l’écran de gestion des demandes d’accès et valider le changement:

image

Il reste à valider avec vos utilisateurs le bon fonctionnement.

Fabrice Romelard [MVP]

Office 365: Comment supprimer les SharePoint Site MailBoxes de votre tenant

Dans SharePoint 2013, une “application” était disponible permettant de créer une boite email associée avec votre site SharePoint (quelque soit le niveau).

Cette feature est désormais révoquée dans Office 365, car remplacée par les Office 365 Groups et surtout Teams.

En revanche, de nombreux utilisateurs peuvent avoir créé ces site Mailboxes (souvent pour tester) et il est bon de faire le nettoyage de ceci avant de déployer de Office 365 Groups / Teams.

Pour cela, je me suis basé sur l’article suivant:

La première étape est de collecter les Boites Emails concernée qui sont toutes créés avec le format SMO-xxxx@Yourtenant.onmicrosoft.com

Il suffit donc d’exécuter en Exchange Admin la commande PowerShell:

  • Get-Mailbox SMO-*

Avec cette liste, on doit ouvrir en Echange ou Tenant Admin l’url au format suivant pour valider si la boite email est utilisée ou non:

Le lien vers le site SharePoint concerné se trouve sur le haut à gauche:

image

ATTENTION:

Si ce lien ne fonctionne pas il faut modifier les permissions de la boite Email via la commande:

  • add-mailboxpermission -id "SMO-xxxxxx@Yourtenant.onmicrosoft.com"  -user "YourEmailAddress@Yourtenant.com" -InheritanceType All -AccessRights FullAccess -Automapping $false

Avec le lien de ce site SharePoint, vous devez supprimer la référence placée dedans en vous connectant au site en tant que SharePoint ou Tenant admin et en mode SharePoint Classique:

image

Une fois la suppression effectuée dans SharePoint, il faut maintenant supprimer le tout dans Exchange via les commandes PowerShell suivantes (avec PS ISE en step by step):

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

[string]$SiteMailBoxName = "SMO-xxxxxx"
[string]$SiteMailAddress = "SMO-xxxxxx@Yourtenant.onmicrosoft.com"
# --------------------------------------------------------
# EXCHANGE MAILBOX
#Verification before deletion
Get-Mailbox $SiteMailBoxName
#Remove the mailbox
Remove-Mailbox $SiteMailBoxName
#Verification after deletion from the list of existing Teamsite Mailbox
Get-Mailbox -RecipientTypeDetails Teammailbox
# --------------------------------------------------------
# EXCHANGE EMAIL REFERENCE
#Verification before deletion
Get-MsolUser -Userprincipalname $SiteMailAddress
#Delete the Email reference
Remove-MsolUser -Userprincipalname $SiteMailAddress                        #>> could give an error
Get-Msoluser -returndeletedusers -Userprincipalname $SiteMailAddress
Remove-Msoluser -Userprincipalname $SiteMailAddress -removeFromRecycleBin
#Verification after deletion
Get-Msoluser -returndeletedusers -Userprincipalname $SiteMailAddress       #>> could give an error
# --------------------------------------------------------

Quand cette tache est terminée, vous pouvez controler à nouveau qu’il n’y ait plus cette boite:

  • Get-Mailbox SMO-*

Vous pourrez alors vous concentrer sur Office 365 Groups et Teams sans vous soucier du passé.

Fabrice Romelard [MVP]

Office 365: Ajouter ou retirer des comptes utilisateurs des administrateurs de collections de site via PowerShell

Pour de nombreuses raisons, on peut vouloir modifier la liste des administrateurs de collections de sites pour l’ensemble des Teamsites de son tenant Office 365.

Il peut être utile pour ajouter ou retirer un compte administrateur de ces sites SharePoint sans pour autant les promouvoir SharePoint Tenant Admin (cas d’équipe de support ou de compte de service).

Ce petit script vous permet (en modifiant juste ce qui vous concerne) de pouvoir effectuer la commande dans les deux sens:

[string]$username = "YourAdminAccount@yourtenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWDFOLDER\ExportedPWD-$($username).txt"

[string]$CompteouGroupeAADavecGUIDO365= "c:0-.f|rolemanager|s-1-5-21-1575671886-733387139-3803724931-1933543"
[string]$CompteIdentifiantSP201X= "i:0#.f|membership|myUserLogin@mydomain.com"

[string]$Compteavecsimplelogin= "loginAdmin@yourtenant.onmicrosoft.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)
}


function ChangeUserStatusForSiteCollectionAdmin
{
    Param(
        [string]$SiteCollURL,
        [string]$LoginToSet,
        [boolean]$ToSiteCollAdminorNot
    )

    if ($ToSiteCollAdminorNot)
     {
        Set-SPOUser -Site $SiteCollURL -LoginName $LoginToSet -IsSiteCollectionAdmin $ToSiteCollAdminorNot;
        Write-Host "  >>>>>>>>", $LoginToSet, " - is now part of Site Collection Collection admins" -foregroundcolor green;
    }
    else
    {
        try
        {
            $CheckUserList = $Null
             $CheckUserList = Get-SPOUser -Site $SiteCollURL -LoginName $LoginToSet
            Set-SPOUser -Site $SiteCollURL -LoginName $CheckUserList.LoginName -IsSiteCollectionAdmin $ToSiteCollAdminorNot;
            Write-Host "  >>>>>>>>", $CheckUserList.LoginName, " - Set to Site Collection Collection admin: ",  $ToSiteCollAdminorNot  -foregroundcolor green;
        }
        catch
        {
            write-host "     >>>> $LoginToSet  ---Error info: $($_.Exception.Message)" -foregroundcolor red
        }
    }
}

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

$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 *
[int]$i = 1;


foreach ($site in $sitesInfo)
{
    Write-Host "SiteColl Number:", $i, "- of:", $sitesInfo.Count;
    $i += 1;
    Write-Host "SPO Site collection:", $site.Url, "- Title:", $site.Title

    ChangeUserStatusForSiteCollectionAdmin $site.Url $Compteavecsimplelogin $false
    Remove-SPOUser -Site $site.Url -LoginName $Compteavecsimplelogin; #If you want to remove all reference to the account

    ChangeUserStatusForSiteCollectionAdmin $site.Url $CompteIdentifiantSP201X $false
    Remove-SPOUser -Site $site.Url -LoginName $CompteIdentifiantSP201X; #If you want to remove all reference to the account

    ChangeUserStatusForSiteCollectionAdmin $site.Url $CompteouGroupeAADavecGUIDO365 $true

}

Vous pouvez simplement adapter votre commande de selection suivant votre propre besoin.

Attention pour les “Group Sites” qui ne sont plus simplement des sites SharePoint basiques, mais un mélange entre SharePoint, Azure AD et Exchange (voir les autres modules additionnels).

Fabrice Romelard [MVP]

Office 365: Extraire dans un fichier CSV une liste de tous les Teamsites présents dans votre tenant Office 365

Une fois la migration terminée, il est primordial de surveiller son instance Office 365 en faisant une extraction de tous les sites du tenant dans un fichier Excel:

[string]$username = "YourAdminAccount@yourtenant.onmicrosoft.com"
[string]$PwdTXTPath = "C:\SECUREDPWDFOLDER\ExportedPWD-$($username).txt"
[string]$ExportAllUserLogin = ""


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 " ---------------------------------------------- "
Load-DLLandAssemblies
Write-Host " ---------------------------------------------- "

$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

$CSVFileToExport = "C:\YOUREXPORTFOLDER\AllSiteCollectionInformation.csv"
if (Test-Path $CSVFileToExport) {
    Remove-Item $CSVFileToExport -Force
}

$ExportSiteCollectionList = ""

#Retrieve all site collection infos
$sitesInfo = Get-SPOSite -Template "STS#0" -Limit ALL | Sort-Object -Property url | Select *
[int]$i = 1;

Write-Host "--------------------------------------------------------------------------------------------"
#Retrieve and print all sites
foreach ($site in $sitesInfo)
{
    $ExportAllUserLogin = ""
    Write-Host "SiteColl Number:", $i, "- of:", $sitesInfo.Count;
    $i += 1;
   
    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 "   => Owner:", $site.Owner

    #Get-SPOUser -Limit ALL -Site $site.Url -IsSiteCollectionAdmin $true < NOT WORKING
   
     $AllUsers = Get-SPOUser -Limit ALL -Site $site.Url #| FT LoginName, IsSiteAdmin -AutoSize #%{if($_.IsSiteAdmin -eq $True)
    $AllUsers | %{if($_.IsSiteAdmin -eq $True) {
                $ExportAllUserLogin += $_.LoginName + '|';
        }
    }

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

    $ExportSiteCollectionList += @(
          [pscustomobject]@{
            SiteURL = $site.Url
            SiteTitle = $site.Title
            SharingCapability = $site.SharingCapability
            StorageQuota = $site.StorageQuota
            StorageUsageCurrent = $site.StorageUsageCurrent
            PercentQuotaUsed = $($site.StorageUsageCurrent / $site.StorageQuota * 100)
            SiteCollAdmin = $ExportAllUserLogin
            }  )

}

Write-Host $ExportSiteCollectionList

$ExportSiteCollectionList | Export-Csv -Path  $CSVFileToExport -Encoding UTF8

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

Vous pouvez ensuite prendre ce fichier CSV et l’utiliser pour vos besoins d’administration ou de listing/reporting.

Fabrice Romelard [MVP]

Reference:

SharePoint 2007: Forcer le Check-In des fichiers avant la migration vers SharePoint Online

Lors des migrations de Sites SharePoint 2007, un point particulièrement pénible est lié aux fichiers bloqués en mode “Checked Out” voir jamais “Checked In” (cas des listes avec métadonnées obligatoires non renseignées).

Ces petits scripts PowerShell peuvent être utilisés pour vous débloquer cette situation avec les deux fonctions suivantes:

Devenir le propriétaire de tous les fichiers en attente de Check In:

function CheckOuttoAdmin([string]$WebURL, [string]$LibraryName)
{
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
    Write-Host " -------------------------------------------------------- "
    Write-Host "SPWeb URL to configure:", $WebURL  -foregroundcolor Red
    $site = new-object Microsoft.SharePoint.SPSite($WebURL)
    $web = $site.openweb()
    Write-Host "    >> SPWeb URL from Object:", $web.URL -foregroundcolor Green
    $getLib = $web.Lists[$LibraryName]
   
    $getLib.CheckedOutFiles | %{
        Write-Host "Taking over Checkout $($_.LeafName)"
        $myFile = $_
        $myFile.TakeOverCheckOut()
    }

    $web.Dispose()
    $site.Dispose()
}

CheckOuttoAdmin "http://YourSP2007WebApp/sites/YourSiteCollection" "Your Document Library Name"

Forcer le Check-in de tous les fichiers encore en mode “Checked Out”:

function CheckInDocument([string]$WebURL, [string]$LibraryName)
{
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
    Write-Host " -------------------------------------------------------- "
    Write-Host "SPWeb URL to configure:", $WebURL  -foregroundcolor Red
    $site = new-object Microsoft.SharePoint.SPSite($WebURL)
    $web = $site.openweb()
    Write-Host "    >> SPWeb URL from Object:", $web.URL -foregroundcolor Green

    $getLib = $web.Lists[$LibraryName]
   
    $getLib.CheckedOutFiles | %{
         Write-Host "Checked Out file: $($_.LeafName)"
        $myCheckedOutFile = $_
        Write-Host "    >>>>>>ExactURL:", $myCheckedOutFile.DirName #"sites/boss-site"

        $myExactFolderName = $myCheckedOutFile.DirName.SubString(16) #//This is //to get the exact folder path without the /sites/sitename, this number may //be different for you
        Write-Host "       >>>>> ExactURL:", $myExactFolderName

        $getFolder = $web.GetFolder($myExactFolderName)
        $getFolder.Files | Where { $_.CheckOutStatus -ne "None" } | ForEach {
            Write-Host "$($_.Name) is Checked out To: $($_.CheckedOutBy)"
            $_.CheckIn("Checked In By Administrator")
             Write-Host "$($_.Name) Checked In" -ForeGroundColor Green
        }
    }
    $web.Dispose()
    $site.Dispose()
}

CheckInDocument "http://YourSP2007WebApp/sites/YourSiteCollection" "Your Document Library Name"

Il ne vous reste plus qu’à adapter les deux scripts à vos propres configurations et ensuite lancer la migration des contenus avec votre outil de migration préféré.

Fabrice Romelard [MBA]

Sources de référence:

Office 365: Comment configurer l’ouverture des fichiers stockés dans une Document Library

Dans le cadre de migration de ferme SharePoint 2007 (c’est d’ailleurs la fin de vie de cette plateforme), l’ouverture des documents des listes SharePoint via Ofice Web Apps est un point pénible de la migration de base.

En effet, SharePoint 2007 ne possède pas nativement de configuration pour Office Web apps, et donc la migration de la liste basiquement maintient cette configuration.

Depuis le site SharePoint

Il est donc utile de modifier la configuration de la liste juste avant cette exécution par un paramètre disponible dans les doclib SP2007:

  • Document library Settings > Advanced Settings

image

Il faut donc prendre la seconde option “Display as a Web Page” pour supporter cette migration dans SharePoint Online et utiliser Office Web Apps dans cette liste.

Dans SPO, le paramètre deviendra donc:

image

En PowerShell

La seconde option est donc de passer par un script PowerShell qui effectuera le même changement, mais pour toutes les listes de tous les sites et sous-sites d’une collection SharePoint 2007:

function Check-DocumentLibraryOpenSettings([string]$SiteCollectionURL)
{
     [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null

     Write-Host " -------------------------------------------------------- "
     Write-Host "Site collection URL to configure:", $SiteCollectionURL  -foregroundcolor Red
     $Thesite = new-object Microsoft.SharePoint.SPSite($SiteCollectionURL)

    #Loop all Sub Sites
     foreach($Web in $TheSite.AllWebs)
     {
         Write-Host "-----------------------------------------------------"
         Write-Host "Site Name: '$($web.Title)' at $($web.URL)"  -foregroundcolor green
         Write-Host "-----------------------------------------------------"
         foreach($list in $Web.Lists)
         {
             #Filter Doc Libs, Eliminate Hidden ones
             if(($List.BaseType -eq "DocumentLibrary") -and ($List.Hidden -eq $false) )
             {
                 Write-Host "List Name: '$($List.Title)'", "- Open Option before the change:", $List.DefaultItemOpen  -foregroundcolor Magenta

                 $List.DefaultItemOpen =  [Microsoft.SharePoint.DefaultItemOpen]::Browser; #Mode Web Application
                 #$List.DefaultItemOpen =  [Microsoft.SharePoint.DefaultItemOpen]::PreferClient; #Mode MS Office rich client
                 $List.Update();
            
             }
         }
     }
     Write-Host " -------------------------------------------------------- "
    
}

cls
Check-DocumentLibraryOpenSettings “http://myWebApplication2007/sites/MySiteCollection”

Une fois le paramètre appliqué, vous pouvez utiliser votre outil de migration pour passer ces librairies documentaires dans SharePoint Online.

Fabrice Romelard [MVP]

Sites de réference utilisés:

Plus de Messages Page suivante »


Les 10 derniers blogs postés

- 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

- Office 365: Modifier les jeux de couleur dans les Thèmes des pages modernes de SharePoint Online par Blog Technique de Romelard Fabrice le 07-04-2018, 13:26

- Office 365: Script PowerShell pour fixer le Quota Warning de toutes les collections d’un tenant par Blog Technique de Romelard Fabrice le 07-03-2018, 14:16

- MVP Award 2018-2019 par Blog de Jérémy Jeanson le 07-02-2018, 20:39

- Reprise des articles de 2014 à aujourd’hui par Blog de Jérémy Jeanson le 06-20-2018, 13:00

- Office 365: Comment créer un sous-plan dans Office 365 Planner par Blog Technique de Romelard Fabrice le 06-14-2018, 17:19

- Office 365: Script PowerShell de création de sous-sites basés sur CSOM ou PnP par Blog Technique de Romelard Fabrice le 06-12-2018, 14:58

- Office 365: Comment exporter tous les comptes Azure Active Directory ayant une license via PowerShell par Blog Technique de Romelard Fabrice le 05-17-2018, 13:46

- PowerShell: Comment avoir le Country Name depuis un Country Code par Blog Technique de Romelard Fabrice le 05-17-2018, 13:20