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: Script PowerShell pour auditer l’usage des Office Groups de votre tenant

Après les précédents scripts publiés pour auditer votre tenant Office 365:

Il faut maintenant fournir les informations d’usage des Office Groups, c’est ce que fait ce script.


[string]$ReportPath = ".\Reports\"
[string]$username = "Admin@yourtenant.onmicrosoft.com"

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

#$userCredential = Get-Credential

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $session

$AllExistingGroups = Get-UnifiedGroup -IncludeAllProperties | Select ExternalDirectoryObjectId,Id,ServerName,Name,DisplayName,Alias,EmailAddresses,PrimarySmtpAddress,SharePointSiteUrl,Notes,Language, ManagedBy,ManagedByDetails,AccessType,GroupType,AutoSubscribeNewMembers,GroupMemberCount,GroupExternalMemberCount,WhenCreatedUTC,WhenChangedUTC

$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$fileName = Join-Path -Path $ReportPath  -ChildPath $("O365-Groups_"+ $datestring + ".csv")

Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
$AllExistingGroups | Export-csv $fileName -NoTypeInformation
Write-host " -----------------------------------------" -ForegroundColor Green


Vous pouvez adapter et utiliser ce script selon vos propres besoins.

Romelard Fabrice

Version Anglaise:

Sources utilisées:

Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant

Après les précédents scripts publiés pour auditer votre tenant Office 365:

Il faut maintenant fournir les informations d’usage de Microsoft Teams, c’est ce que fait ce script.


Import-Module MSOnline
Import-Module MicrosoftTeams

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

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $cred -Authentication Basic -AllowRedirection
Import-PSSession $session

#Connect-MicrosoftTeams -Credential $cred
Connect-MicrosoftTeams

[int]$i = 1;
$data = @()
[string]$ListOfChannelNames = ""
[string]$TeamOwnersEmails = ""
[string]$TeamMembersEmails = ""
[string]$TeamGuestsEmails = ""

$ListOfTeams = Get-Team  -user $username #Test command to focus
#$ListOfTeams = Get-Team

Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor Magenta


foreach($MyTeams in $ListOfTeams)
{
    Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green

    $TeamUnifiedGroup = Get-UnifiedGroup -Identity $MyTeams.GroupId
    Write-Host "    ===-> Teams GroupID:", $MyTeams.GroupId, "- Name:", $MyTeams.DisplayName, "- Description:", $MyTeams.Description  -ForegroundColor Yellow
    Write-Host "    ===-> GroupEmail:", $TeamUnifiedGroup.PrimarySmtpAddress

    # Current Teams Configuration implemented
    Write-Host "    ===-> Get-TeamMemberSettings:" -ForegroundColor Yellow
    $TeamMemberSettings = Get-TeamMemberSettings -GroupId $MyTeams.GroupId
    Write-Host "          ====> ", $TeamMemberSettings.AllowCreateUpdateChannels

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

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

    Write-Host "    ===-> Get-TeamFunSettings:" -ForegroundColor Yellow
    $TeamFunSettings = Get-TeamFunSettings -GroupId $MyTeams.GroupId
    Write-Host "          ====> ", $TeamFunSettings.AllowGiphy

    $ListOfChannelNames = ""
    $TeamOwnersEmails = ""
    $TeamMembersEmails = ""
    $TeamGuestsEmails = ""
    $CurrentListOfChannelList = Get-TeamChannel -GroupId $MyTeams.GroupId
    foreach($MyChannel in $CurrentListOfChannelList)
     {
        Write-host "      ------------------ " -ForegroundColor green
        Write-Host "      ===-> Channel Name:", $MyChannel.Id, "- Name:", $MyChannel.DisplayName, "- Description:", $MyChannel.Description  -ForegroundColor Magenta
        $ListOfChannelNames += " -|- "+ $MyChannel.DisplayName
    }

    $TeamUsers = Get-TeamUser -GroupId $MyTeams.GroupId
    Write-Host "    ===-> Get-TeamUser:", $TeamUsers.Count -ForegroundColor Yellow
    if ([array]$MyTeamGuest = $TeamUsers | Where {$_.Role -eq "guest"})
    {
        $TeamGuestsCount = $MyTeamGuest.Count
         $MyTeamGuest.ForEach({ $TeamGuestsEmails += "|"+ $_.User  })
        Write-Host "       ===-> TeamGuestsEmails:", $TeamGuestsEmails -ForegroundColor Magenta
    }
    else
    {
        $TeamGuestsCount = 0
        $TeamGuestsEmails = ""
    }

    if ([array]$MyTeamMembers = $TeamUsers | Where {$_.Role -eq "member"})
    {
        $TeamMembersCount = $MyTeamMembers.Count
         $MyTeamMembers.ForEach({ $TeamMembersEmails += "|"+ $_.User  })
        Write-Host "       ===-> TeamMembersEmails:", $TeamMembersEmails -ForegroundColor Magenta
    }
    else
    {
        $TeamMembersCount = 0
        $TeamMembersEmails = ""
    }

    if ([array]$MyTeamOwners = $TeamUsers | Where {$_.Role -eq "owner"})
    {
        $TeamOwnersCount = $MyTeamOwners.Count
         $MyTeamOwners.Foreach({ $TeamOwnersEmails += "|"+ $_.User  })
        Write-Host "       ===-> TeamOwnersEmails:", $TeamOwnersEmails -ForegroundColor Magenta
    }
    else
    {
        $TeamOwnersCount = 0
        $TeamOwnersEmails = ""
    }

#Team name    TeamMail    Channels    MembersCount    OwnersCount    GuestsCount    Privacy

    $data += @(
        [pscustomobject]@{
         GroupID = $MyTeams.GroupId
        GroupTeamMail = $TeamUnifiedGroup.PrimarySmtpAddress
        GroupHiddenfromOutlook = $TeamUnifiedGroup.HiddenFromExchangeClientsEnabled
        GroupAccessType = $TeamUnifiedGroup.AccessType
        GroupExternalMemberCount = $TeamUnifiedGroup.GroupExternalMemberCount
        TeamName = $MyTeams.DisplayName
        TeamDescription = $MyTeams.Description
        TeamMemberSettingsAllowCreateUpdateChannels = $TeamMemberSettings.AllowCreateUpdateChannels
        TeamMemberSettingsAllowDeleteChannels = $TeamMemberSettings.AllowDeleteChannels
        TeamMemberSettingsAllowAddRemoveApps = $TeamMemberSettings.AllowAddRemoveApps
        TeamMemberSettingsAllowCreateUpdateRemoveTabs = $TeamMemberSettings.AllowCreateUpdateRemoveTabs
        TeamMemberSettingsAllowCreateUpdateRemoveConnectors = $TeamMemberSettings.AllowCreateUpdateRemoveConnectors
         TeamMessagingSettingsAllowUserEditMessages = $TeamMessagingSettings.AllowUserEditMessages
        TeamMessagingSettingsAllowUserDeleteMessages = $TeamMessagingSettings.AllowUserDeleteMessages
        TeamMessagingSettingsAllowOwnerDeleteMessages = $TeamMessagingSettings.AllowOwnerDeleteMessages
        TeamMessagingSettingsAllowTeamMentions = $TeamMessagingSettings.AllowTeamMentions
        TeamMessagingSettingsAllowChannelMentions = $TeamMessagingSettings.AllowChannelMentions
        TeamGuestSettingsAllowCreateUpdateChannels = $TeamGuestSettings.AllowCreateUpdateChannels
        TeamGuestSettingsAllowDeleteChannels = $TeamGuestSettings.AllowDeleteChannels
        TeamFunSettingsAllowGiphy = $TeamFunSettings.AllowGiphy
        TeamFunSettingsGiphyContentRating = $TeamFunSettings.GiphyContentRating
        TeamFunSettingsAllowStickersAndMemes = $TeamFunSettings.AllowStickersAndMemes
        TeamFunSettingsAllowCustomMemes = $TeamFunSettings.AllowCustomMemes
        TeamChannelsCount = $CurrentListOfChannelList.Count
        TeamChannelsNames = $ListOfChannelNames
         TeamOwnersCount = $TeamOwnersCount
        TeamOwnersEmails = $TeamOwnersEmails
        TeamMembersCount = $TeamMembersCount
        TeamMembersEmails = $TeamMembersEmails
        TeamGuestsCount = $TeamGuestsCount
        TeamGuestsEmails = $TeamGuestsEmails
        }
    )


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

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

$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$fileName = Join-Path -Path $ReportPath  -ChildPath $("O365-TeamsDetails_"+ $datestring + ".csv")
   
Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
$data | Export-csv $fileName -NoTypeInformation -enc utf8
Write-host " -----------------------------------------" -ForegroundColor Green


Vous pouvez adapter et utiliser ce script selon vos propres besoins.

Romelard Fabrice

Version Anglaise:

Sources utilisées:

Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant

Après les précédents scripts publiés pour auditer votre tenant Office 365:

Il faut maintenant fournir les informations d’usage de OneDrive for Business, c’est ce que fait ce script.


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

[string]$ReportPath = ".\Reports\"
[string]$TenantUrl = "
https://YourTenant-admin.sharepoint.com"

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

    # Load assemblies to PowerShell session

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

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

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

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

$secureStringPwd = ConvertTo-SecureString -string (Get-Content $PwdTXTPath)
$adminCreds = New-Object System.Management.Automation.PSCredential $username, $secureStringPwd
#Connect-SPOService -Url $TenantUrl -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

Connect-SPOService -Url $TenantUrl -ErrorAction SilentlyContinue -ErrorVariable Err

$data = @()

#Retrieve all site collection infos
#$sitesInfo = Get-SPOSite -IncludePersonalSite $true -Limit 100 -Filter "Url -like '-my.sharepoint.com/personal/" | Sort-Object -Property url | Select *

$sitesInfo = Get-SPOSite -IncludePersonalSite $true -Limit All -Filter "Url -like '-my.sharepoint.com/personal/" | Sort-Object -Property url | Select *

[int]$i = 1;
[string]$CheckInfoPathStatus = ""
[string]$CheckWorkFlowStatus = ""
$data = @()

Write-Host "--------------------------------------------------------------------------------------------"
#Retrieve and print all sites
foreach ($site in $sitesInfo)
{
    Write-Host "SiteColl Number:", $i, "- of:", $sitesInfo.Count;
    $i += 1;
        
    Write-Host "SPO Site collection:", $site.Url, "- Title:", $site.Title
    Write-Host "   => Creation Date:", $RootSiteCreatedDate, "- LastItemModifiedDate", $site.LastContentModifiedDate
    Write-Host "   => External Sharing:", $site.SharingCapability
    Write-Host "   => Site Template Used:", $site.Template
    Write-Host "   => Storage Quota:", $site.StorageQuota
     Write-Host "   => Storage used:", $site.StorageUsageCurrent
     Write-Host "   => Storage Warning Level:", $site.StorageQuotaWarningLevel
    Write-Host "   => Resource Quota:", $site.ResourceQuota, "- Resource used:", $site.ResourceUsageCurrent

    $SuborRootSite = "RootSite"
    $data += @(
        [pscustomobject]@{
        UPN = $site.Owner
        SiteCollectionURL = $site.Url
        SiteName = $site.Title
        WebTemplate = $site.Template
        LastItemModifiedDate = $site.LastContentModifiedDate
        ExternalSharingCapability = $site.SharingCapability
        StorageQuotaMB = $site.StorageQuota
        StorageUsageCurrentMB = $site.StorageUsageCurrent
        }
    )
}

#Write-Host $data

$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$fileName = Join-Path -Path $ReportPath  -ChildPath $("O365-OneDriveDetails_"+ $datestring + ".csv")
   
Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
$data | Export-csv $fileName -NoTypeInformation -enc utf8
Write-host " -----------------------------------------" -ForegroundColor Green


Vous pouvez adapter et utiliser ce script selon vos propres besoins.

Romelard Fabrice

Version Anglaise:

Sources utilisées:

Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant

Nous avons vu dans un précédent message comment extraire les informations d’Exchange OnLine en cas d’audit d’un Tenant Office 365:

La question est la même pour la partie SharePoint Online du tenant Office 365.

Ce script permet donc d’exporter en CSV toutes les informations utiles de ce tenant. Il fera une boucle sur l’ensemble des collections de sites et des sous-sites en prenant en compte les volumes et la personnalisation (en mode old School SharePoint).


[boolean]$DebugGlobalMode = $True #$False
[string]$username = "Admin@yourtenant.onmicrosoft.com"

[string]$PwdTXTPath = "C:\SECUREDPWD\ExportedPWD-$($username).txt"
[string]$CSVFolderReport = "C:\SHAREPOINT\Reports\"
[string]$AdminTenantURL = "
https://YourTenant-admin.sharepoint.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 Get-SPOWebs(){
param(
    $Url = $(throw "Please provide a Site Collection Url"),
    $Credential = $(throw "Please provide a Credentials")
)

    $context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Credential.UserName,$Credential.Password)
    $context.RequestTimeout = 1000000 # milliseconds
    $web = $context.Web
    $context.Load($web)
    $context.Load($web.Webs)
    $context.ExecuteQuery()
    foreach($myweb in $web.Webs)
    {
        Get-SPOWebs -Url $myweb.Url -Credential $Credential
        $myweb
    }
}

function Check-InfoPath-Usage($myspoWebSite, $myspcontext)
{
    [string]$InfotpathStatus = ""
    [boolean]$DebugMode = $false #$DebugGlobalMode
    $AllspwebLists = $myspoWebSite.lists
    $myspcontext.Load($AllspwebLists)
    $myspcontext.ExecuteQuery()
    Write-Host " ---------------------------------------------- "
    if($DebugMode) {Write-Host "         -->InfoPath:",$($myspoWebSite.Id), "-",$($myspoWebSite.Url), "-",$($myspoWebSite.Title) -ForegroundColor Yellow}
    foreach($myList in $AllspwebLists)
    {
         $myspcontext.Load($myList)
        $myspcontext.ExecuteQuery()
        $listTitle = $myList.Title
        $listType = $myList.BaseTemplate
        $listUrl = $myList.DefaultViewUrl
         try
        {
            if($DebugMode) {Write-Host "         -->Infopath: List Check", $listTitle, "(", $listType, ") at WebURL", $myspoWebSite.url -ForegroundColor Green}
            if($listType -eq 100 -or $listType -eq 101)
            {
                 if($DebugMode) {Write-Host "            -->Infopath: Line 70 - listType:", $listType}
                $isSysList = $myList.IsSystemList
                $IswebCatalog =  $myList.IsCatalog
                $IsAppList =  $myList.IsApplicationList
                 $listForms = $myList.Forms
                $myspcontext.Load($listForms)
                $myspcontext.ExecuteQuery()
                 if($DebugMode) {Write-Host "            -->Infopath: Line 77 - isSysList:", $isSysList}
                if($DebugMode) {Write-Host "            -->Infopath: Line 78 - IsCatalog:", $IswebCatalog}
                if($DebugMode) {Write-Host "            -->Infopath: Line 79 - IsApplicationList:", $IsAppList}
                if($isSysList -or $IswebCatalog -or $IsAppList)
                {
                    if($DebugMode) {Write-Host "            -->Infopath: System, Application or Catalog List Ignore", $listTitle, "at URL", $myspoWebSite.url -ForegroundColor Yellow}
                }
                else
                {
                    if($listType -eq 101)
                    {
                        if($DebugMode) {Write-Host "            -->Infopath: Line 88 - listType:",  $listType}
                         if($myList.AllowContentTypes)
                        {
                            if($DebugMode) {Write-Host "            -->Infopath: Line 89 - AllowContentTypes:", $myList.AllowContentTypes}
                            $contentTyps = $myList.ContentTypes
                            $myspcontext.Load($contentTyps)
                            $myspcontext.ExecuteQuery()
                            forEach($contType in $contentTyps)
                            {
                                if($DebugMode) {Write-Host "            -->Infopath: Line 97 - contType.Name:", $contType.Name}
                                if($contType.Name -eq "Form")
                                {
                                     Write-Host "            -->InfoPath: Found in Library", $listTitle, "at URL", $myspoWebSite.url -ForegroundColor Magenta
                                    $InfotpathStatus += "Infopath:"+ $myspoWebSite.url +";"
                                 }
                            }
                         }
                        if($DebugMode) {Write-Host "            -->Infopath: Line 105 - listType:", $listType}
                    }
                    else
                     {
                        forEach($listFm in $listForms)
                         {
                            $listPath = $listFm.ServerRelativeUrl
                            if($DebugMode) {Write-Host "            -->Infopath: Line 112 - listPath:", $listPath}
                            if ($listPath -like '*displayifs.aspx')
                            {
                                 Write-Host "            -->InfoPath: Found in List", $listTitle, "at URL", $myspoWebSite.url -ForegroundColor Magenta
                                $InfotpathStatus += "Infopath:"+ $myspoWebSite.url +";"
                            }
                         }
                    }
                }

            }
        }
        catch
        {
            Write-Host "         -->Infopath: Error Check for list:",  $listTitle -ForegroundColor Red
            Write-Host "             ErrorMessage:", $_.Exception -ForegroundColor Red
        }
    }

    return $InfotpathStatus
}

function Check-SPWorkflow($myspoWebSite, $myspcontext)
{
    [string]$WorkflowStatus = ""
    [boolean]$DebugMode = $false #$DebugGlobalMode
    $AllspwebLists = $myspoWebSite.lists
    $myspcontext.Load($AllspwebLists)
    $myspcontext.ExecuteQuery()
    if($DebugMode) {Write-Host "         --> WorkFlow: ",$($myspoWebSite.Id), "-",$($myspoWebSite.Url), "-",$($myspoWebSite.Title) -ForegroundColor Yellow}
    foreach($list in $AllspwebLists)
    {
        if($DebugMode) {Write-Host "         -->SPWorkflow: List Check", $list.Title, " at WebURL", $myspoWebSite.url -ForegroundColor Green}
        try
        {
             $myspcontext.Load($list.WorkflowAssociations)
             $myspcontext.ExecuteQuery()
            foreach($wfAssociation in $list.WorkflowAssociations)
            {
                if($DebugMode) {Write-Host "                 -->SPWorkflow: List ", $list.Title, "- Wokflow:", $wfAssociation.Name -ForegroundColor Magenta}
                $WorkflowStatus += "`"$($list.Title)`",`"$($wfAssociation.Name)`",`"$($wfAssociation.TaskListTitle)`","
                #$WorkflowStatus += "`"$($wfAssociation.HistoryListTitle)`",$($wfAssociation.Created),$($wfAssociation.Modified)"
            } 
        }
        catch
        {
             Write-Host "         -->WorkFlowCHeck: Error Check for list:",  $list.Title -ForegroundColor Red
            Write-Host "             ErrorMessage:", $_.Exception -ForegroundColor Red
         }
    }
    return $WorkflowStatus
}

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

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

Connect-SPOService -Url $AdminTenantURL -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

$data = @()

#Retrieve all site collection infos
#$sitesInfo = Get-SPOSite -Limit 10 | Sort-Object -Property url | Select *
#$sitesInfo = Get-SPOSite -Template "STS#0" -Limit 10 | Sort-Object -Property url | Select *
$sitesInfo = Get-SPOSite -Limit ALL | Sort-Object -Property url | Select *

[int]$i = 1;
[string]$CheckInfoPathStatus = ""
[string]$CheckWorkFlowStatus = ""
$data = @()

Write-Host "--------------------------------------------------------------------------------------------"
#Retrieve and print all sites
foreach ($site in $sitesInfo)
{
    Write-Host "SiteColl Number:", $i, "- of:", $sitesInfo.Count;
    $i += 1;
    $RootSiteCreatedDate = get-date "1900-01-01"
    try
    {
        $Rootcontext = New-Object Microsoft.SharePoint.Client.ClientContext($site.Url)
        $Rootcontext.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($adminCreds.UserName,$adminCreds.Password)
        $Rootcontext.RequestTimeout = 1000000 # milliseconds
        $RootWeb = $Rootcontext.web
        $Rootcontext.Load($RootWeb)
        $Rootcontext.ExecuteQuery()
        $RootSiteCreatedDate = $RootWeb.Created
        $CheckInfoPathStatus = Check-InfoPath-Usage $RootWeb $Rootcontext
         $CheckWorkFlowStatus = Check-SPWorkflow $RootWeb $Rootcontext
    }
    catch
    {
        Write-host "  =====>>>> Impossible to get the RootSite " -ForegroundColor Red
        Write-host "  =====>>>> RootSite:", $site.Url -ForegroundColor Yellow
    }
       
    Write-Host "SPO Site collection:", $site.Url, "- Title:", $site.Title
    Write-Host "   => Creation Date:", $RootSiteCreatedDate, "- LastItemModifiedDate", $site.LastContentModifiedDate
    Write-Host "   => External Sharing:", $site.SharingCapability
    Write-Host "   => Site Template Used:", $site.Template
    Write-Host "   => Storage Quota:", $site.StorageQuota
    Write-Host "   => Storage used:", $site.StorageUsageCurrent
    Write-Host "   => Storage Warning Level:", $site.StorageQuotaWarningLevel
    Write-Host "   => Resource Quota:", $site.ResourceQuota, "- Resource used:", $site.ResourceUsageCurrent

    $SuborRootSite = "RootSite"
    $data += @(
        [pscustomobject]@{
        SiteCollectionURL = $site.Url
        SiteCollectionTitle = $site.Title
        SPType = $site.Template
        SubsiteURL = $site.Url
        SuborRootSite = $SuborRootSite
         WebTemplate = $site.Template
        WebCreationDate = $RootSiteCreatedDate
        LastItemModifiedDate = $site.LastContentModifiedDate
        ExternalSharingCapability = $site.SharingCapability
        StorageQuotaMB = $site.StorageQuota
        StorageUsageCurrentMB = $site.StorageUsageCurrent
        StorageQuotaWarningLevelMB = $site.StorageQuotaWarningLevel
        ResourceQuota = $site.ResourceQuota
        ResourceUsageCurrent = $site.ResourceUsageCurrent
        DevCustomCreated = ""
        DevCustomSPWorkflow = $CheckWorkFlowStatus
        DevSPFxCreated = ""
        DevMSFloworPowerAppsCreated = ""
        DevInforpathForm = $CheckInfoPathStatus
        }
    )
    try
    {
         $AllWebs = Get-SPOWebs -Url $site.Url -Credential $adminCreds
        if($DebugMode) {$AllWebs | %{ Write-Host "   >>", $_.Title, "-", $_.Url}}
        Write-Host "--------------------------------------------------------------------------------------------"

        foreach($mySPWeb in $AllWebs)
        {
             Write-Host "         >> Subsite:", $mySPWeb.Url -ForegroundColor magenta
            $CheckInfoPathStatus = Check-InfoPath-Usage $RootWeb $Rootcontext
            $CheckWorkFlowStatus = Check-SPWorkflow $RootWeb $Rootcontext
            $SuborRootSite = "SubSite"
            $data += @(
                [pscustomobject]@{
                SiteCollectionURL = $site.Url
                 SiteCollectionTitle = $site.Title
                SPType = $site.Template
                SubsiteURL = $mySPWeb.Url
                 SuborRootSite = $SuborRootSite
                WebTemplate = $mySPWeb.WebTemplate
                WebCreationDate = $mySPWeb.Created
                LastItemModifiedDate = $mySPWeb.LastItemModifiedDate
                ExternalSharingCapability = $site.SharingCapability
                StorageQuotaMB = $site.StorageQuota
                StorageUsageCurrentMB = $site.StorageUsageCurrent
                StorageQuotaWarningLevelMB = $site.StorageQuotaWarningLevel
                ResourceQuota = $site.ResourceQuota
                ResourceUsageCurrent = $site.ResourceUsageCurrent
                DevCustomCreated = ""
                 DevCustomSPWorkflow = $CheckWorkFlowStatus
                DevSPFxCreated = ""
                DevMSFloworPowerAppsCreated = ""
                DevInforpathForm = $CheckInfoPathStatus
                 }
            )
        }
    }
    catch
    {
         Write-host "  =====>>>> Impossible to get the Subsites " -ForegroundColor Red
        Write-host "  =====>>>> RootSite:", $site.Url -ForegroundColor Yellow
    }

}

#Write-Host $data

$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$CSVFileToExport = Join-Path -Path $CSVFolderReport  -ChildPath $("SharePoint_"+ $datestring + ".csv")
   
Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $CSVFileToExport) -ForegroundColor Green
$data | Export-csv $CSVFileToExport -NoTypeInformation -enc utf8
Write-host " -----------------------------------------" -ForegroundColor Green


Vous pouvez adapter et utiliser ce script selon vos propres besoins.

Romelard Fabrice

Version Anglaise:

Sources utilisées:

Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant

Dans la suite des précédents articles pour auditer un Tenant Office 365, voici un script dédié à l’utilisation du moteur Exchange Online.

Ce script permet de générer un simple fichier CSV utilisable dans Excel.


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

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

#$adminCreds = get-credential

$ReportPath = "C:\EXCHANGE\Reports\"
$data = @()

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-LiveID/ -Credential $adminCreds -Authentication Basic -AllowRedirection
Import-PSSession $Session

$MbxUsers = get-mailbox -resultsize unlimited
#$MbxUsers = get-mailbox  # < for testing only first 1000 mailbox
#$MbxUsers = get-mailbox -RecipientTypeDetails SharedMailbox -resultsize 50 # < for testing only first 50 shared MB

foreach($user in $mbxusers)
{
    $UPN = $user.userprincipalname
    $Mbx = Get-MailboxStatistics $UPN
    $TotalMBSize = [math]::Round((($Mbx.TotalItemSize.Value.ToString()).Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2) #"69.48 MB (72,854,427 bytes)"

    Write-host " >> MailBox UPN:", $user.userprincipalname, "- MailBoxType:", $user.RecipientTypeDetails, "- Mailbox ItemNumber:", $Mbx.ItemCount -ForegroundColor Magenta
    Write-host "    >> MailBox Size Text:", $Mbx.TotalItemSize ," - MailBox SizeMB:", $TotalMBSize
    Write-host "    >> ProhibitSendQuota:", $user.ProhibitSendQuota, "- ProhibitSendReceiveQuota:", $user.ProhibitSendReceiveQuota
   
    $Properties = @{
        Logoff = $Mbx.lastlogofftime
        Logon = $Mbx.lastlogontime
        IsEncrypted = $Mbx.IsEncrypted
         ProhibitSendReceiveQuotaMB = $user.ProhibitSendReceiveQuota
        ProhibitSendQuotaMB = $user.ProhibitSendQuota
        TotalSizeMB = $TotalMBSize.ToString()
        ItemCount = $Mbx.ItemCount
        IsArchiveMailbox = $Mbx.IsArchiveMailbox
         RecipientTypeDetails = $user.RecipientTypeDetails
        Alias = $user.alias
        UPN = $user.userprincipalname
         Displayname = $Mbx.Displayname
        Name = $user.name
         }
    $data += New-Object psobject -Property $properties
}
 
$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$fileName = Join-Path -Path $ReportPath  -ChildPath $("ExchangeMailbox_"+ $datestring + ".csv")
   
Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
$data | Select-Object Name,D isplayname, UPN, Alias, RecipientTypeDetails, IsArchiveMailbox, IsEncrypted, ItemCount, TotalSizeMB,ProhibitSendQuotaMB, ProhibitSendReceiveQuotaMB, Logon, Logoff | Export-csv $fileName -NoTypeInformation -enc utf8
Write-host " -----------------------------------------" -ForegroundColor Green

Remove-PSSession $Session


Vous pouvez utiliser ce script et l’adapter selon vos propres besoins.

Fabrice Romelard

Sources utilisées:

Version Anglaise:

Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal

Dans un précédent message, nous avons vu comment exporter les informations de la solution Video Portal d’un tenant Office 365:

Cette fois, la question se pose aussi pour Office 365 Stream, qui est la nouvelle plateforme de vidéo proposée par Microsoft dans un Tenant Office 365.

Il se trouve que Microsoft n’a pas encore fourni les API publiques pour Office 365 Stream (prévu Q2/Q3 2019) et donc ne permet pas de procéder de la même manière.

En revanche, le portail Web de Stream (https://web.microsoftstream.com) utilise des API internes pour ses propres pages de navigation comme par exemple:

Liste des O365 Groups:

Liste des videos pour un O365 Group:

Liste des Channels

Ces API, qui fournissent les résultats en JSON, peuvent être appelées une fois l’authentification faite sur le portal avec un navigateur web. Et parce que ce sont des API Internes, j’ai préférer rester dans ce passage avec le navigateur.

De ce fait le process à suivre (intégré dans le script PowerShell) est le suivant:

  1. Ouvrir le portail O365 Stream avec votre navigateur Web (et vos credentials admins)
    - https://web.microsoftstream.com/?NoSignUpCheck=1
  2. Avec le même navigateur, (autre tab ou autre fenêtres), ouvrir les liens suivant:
    1. Entre 0 et 100: https://euno-1.api.microsoftstream.com/api/channels?$top=100&$orderby=metrics%2Fvideos%20desc&$expan...
    2. Entre 100 et 200: https://euno-1.api.microsoftstream.com/api/channels?$top=100&$orderby=metrics%2Fvideos%20desc&$expan...
    3. ... : S’arréter quand il n’y a plus d’information dans la page
  3. Sauvegarder chaque résultat JSON dans le répertoire de travail (C:\PSScript\ChannelsJSON\)
    1. channels100.json
    2. channels200.json
  4. Le script PowerShell va générer un fichier CSV cumulé contenant les détails des channels O365 Stream

Avant d’exécuter ce script, vous devez changer les paramêtre suivant, selon votre contexte:

  • [int]$Loopnumber = 2    # << 2 indique entre 100 et 200 channels
  • [string]$PowerShellScriptFolder = "C:\PSScript"

[string]$PowerShellScriptFolder = "C:\PSScript"
[string]$streamJSONfolder = Join-Path -Path $PowerShellScriptFolder -ChildPath "ChannelsJSON"
Remove-Item -path $streamJSONfolder\* -include *.json -Force -Recurse

[string]$StreamPortal = "https://web.microsoftstream.com/?NoSignUpCheck=1"
[string]$StreamPortalChannelRoot = "https://web.microsoftstream.com/channel/"
[string]$StreamAPIChannels100 = "https://euno-1.api.microsoftstream.com/api/channels?NoSignUpCheck=1&`$top=100&`$orderby=metrics%2Fvideos%20desc&`$expand=creator,group&api-version=1.3-private&`$skip="

[int]$Loopnumber = 2

Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host "  =====>>>> PortalURL:", $StreamPortal
Start-Process -FilePath 'iexplore.exe' -ArgumentList $StreamPortal
Write-Host "      Enter your credentials to load O365 Stream portal" -ForegroundColor Magenta
Read-Host -Prompt "Press Enter to continue ...."

for($i=0;$i -lt $Loopnumber; $i++)
{
    Write-host " -----------------------------------------" -ForegroundColor Green
    $StreamAPIChannels100 = $StreamAPIChannels100 + $($i*100)
    Write-Host "  =====>>>> First 100 channels (from", $($i*100), "to", $(($i+1)*100), "):", $StreamAPIChannels100
    Start-Process -FilePath 'iexplore.exe' -ArgumentList $StreamAPIChannels100
    Write-Host "      Save the 100 channels (from", $($i*100), "to", $(($i+1)*100), ") into the folder $streamJSONfolder respecting the name channels100.json" -ForegroundColor Magenta
    Read-Host -Prompt "Press Enter to continue ...."
}

Write-host " -----------------------------------------" -ForegroundColor Green
$ChannelJSONFiles = Get-ChildItem -Path $streamJSONfolder -Recurse -Include *.json
[int]$channelscounter = 0
$ChanneljsonAggregateddata=@()
$data=@()

foreach($channelsjson in $ChannelJSONFiles)
{
    Write-host " -----------------------------------------" -ForegroundColor Green
    Write-Host "     =====>>>> JSON File:", $channelsjson, "- Path:", $channelsjson.FullName -ForegroundColor Yellow
    $Channeljsondata = Get-Content -Raw -Path $channelsjson.FullName | ConvertFrom-Json
    $ChanneljsonAggregateddata += $Channeljsondata
    Write-host " -----------------------------------------" -ForegroundColor Green
     #Write-Host "     =====>>>> Channel JSON Raw data:", $Channeljsondata -ForegroundColor green
    #Read-Host -Prompt "Press Enter to continue ...."
}

foreach($myChannel in $ChanneljsonAggregateddata.value)
{
    if($myChannel.metrics.videos -gt -1)
    {
        $channelscounter += 1
        $datum = New-Object -TypeName PSObject
        Write-host "        -----------------------------------------" -ForegroundColor Green
        Write-Host "        =====>>>> Channel (N°", $channelscounter ,") ID:", $myChannel.id, "- isDefault Channel:", $myChannel.isDefault -ForegroundColor green
        Write-Host "        ---- Channel Name:", $myChannel.name,"- Channel Portal URL:", $($StreamPortalChannelRoot + $myChannel.id)
        Write-Host "        ---- Channel CreationDate:", $myChannel.created,"- Channel ModificationDate:", $myChannel.modified
        Write-Host "        =====>>>> Channel Metrics Followers:", $myChannel.metrics.follows, "- Video Total:", $myChannel.metrics.videos -ForegroundColor Magenta
        Write-Host "        =====>>>> O365 Channel Creator Name: ", $myChannel.creator.name , " - Email:", $myChannel.creator.mail -ForegroundColor Magenta

        Write-Host " O365 GROUP Name:", $myChannel.group.name, "- ID:", $myChannel.group.id -ForegroundColor Yellow
        Write-Host "        =====>>>> O365 Group ID: ", $myChannel.group.id , " - Group Email:", $myChannel.group.aadGroup.mail -ForegroundColor Magenta
        Write-Host "        =====>>>> O365 Group Metrics Channel total:", $myChannel.group.metrics.channels, "- Video Total:", $myChannel.group.metrics.videos -ForegroundColor Magenta

        $datum | Add-Member -MemberType NoteProperty -Name ChannelID -Value $myChannel.id
        $datum | Add-Member -MemberType NoteProperty -Name ChannelName -Value $myChannel.name
        $datum | Add-Member -MemberType NoteProperty -Name ChannelURL -Value $($StreamPortalChannelRoot + $myChannel.id)
        $datum | Add-Member -MemberType NoteProperty -Name ChannelDefault -Value $myChannel.isDefault
        $datum | Add-Member -MemberType NoteProperty -Name ChannelFollowers -Value $myChannel.metrics.follows
        $datum | Add-Member -MemberType NoteProperty -Name ChannelVideos -Value $myChannel.metrics.videos
        $datum | Add-Member -MemberType NoteProperty -Name ChannelCreatorName -Value $myChannel.creator.name
        $datum | Add-Member -MemberType NoteProperty -Name ChannelCreatorEmail -Value $myChannel.creator.mail
        $datum | Add-Member -MemberType NoteProperty -Name ChannelCreationDate -Value $myChannel.created
        $datum | Add-Member -MemberType NoteProperty -Name ChannelModificationDate -Value $myChannel.modified

        $datum | Add-Member -MemberType NoteProperty -Name O365GroupId -Value $myChannel.group.id
        $datum | Add-Member -MemberType NoteProperty -Name O365GroupName -Value $myChannel.group.name
        $datum | Add-Member -MemberType NoteProperty -Name O365GroupEmail -Value $myChannel.group.aadGroup.mail
        $datum | Add-Member -MemberType NoteProperty -Name O365GroupTotalChannels -Value $myChannel.group.metrics.channels
        $datum | Add-Member -MemberType NoteProperty -Name O365GroupTotalVideos -Value $myChannel.group.metrics.videos

        $data += $datum
    }
}

$datestring = (get-date).ToString("yyyyMMdd-hhmm")
$fileName = ($PowerShellScriptFolder + "\O365StreamDetails_" + $datestring + ".csv")
   
Write-host " -----------------------------------------" -ForegroundColor Green
Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
$data | Export-csv $fileName -NoTypeInformation
Write-host " -----------------------------------------" -ForegroundColor Green


Vous pouvez utiliser et adapter ce script selon votre cadre et besoin.

Fabrice Romelard

English version:

Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal

Office 365 Video Portal est désormais remplacé par Office 365 Stream.

En revanche la migration de son contenu est pour le moment laissée au soin des clients, une solution de migration devrait arriver, mais aucune date n’est encore connue.

La situation demande quoi qu’il en soit une analyse du contenu pour savoir à quelle montagne on s’attaque et c’est le but de ce script.

Le script PowerShell suivant vous permet d’exporter en CSV les informations de chaque fichier placé dans un Channel Office 365 Video portal avec les details suivant:

  • ChannelName
  • ChannelURL
  • ChannelStorageinMB
  • FileTotal
  • FileName
  • FileType
  • FileSizeMB
  • FileAbsoluteURL

Vous pouvez de ce fait l’adapter ou l’utiliser comme bon vous semble et selon vos besoins.

function Invoke-RestSPO
{
    Param(
    [Parameter(Mandatory=$True)]
    [String]$AdminPortalUrl,

    [Parameter(Mandatory=$True)]
    [String]$SPOUrl,

    [Parameter(Mandatory=$True)]
    [String]$UserName,

    [Parameter(Mandatory=$True)]
    [String]$Password
     )

    [string]$VideoListName = "Videos"
   
    Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client").location)
    Add-Type -Path ([System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.runtime").location)

    $SecurePassword = ConvertTo-SecureString -string (Get-Content $Password)
    $creds = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $SecurePassword
    #$creds = Get-Credential

    $SPOQueryUrl= $SPOUrl + "/_api/search/query?querytext=%27contentclass:sts_site WebTemplate:POINTPUBLISHINGTOPIC%27&SelectProperties=%27Sitename%27&rowlimit=5000"
   
    Write-Host "Performing the SPO Search Query to get all the Office 365 Video Channels..." -ForegroundColor Green
    $request = [System.Net.WebRequest]::Create($SPOQueryUrl)
    $request.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName,$creds.Password)
    $request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
    $request.Accept = "application/json;odata=verbose"
    #$request.Method=$Method
    $request.Method=[Microsoft.PowerShell.Commands.WebRequestMethod]::Get
    $response = $request.GetResponse()
    $requestStream = $response.GetResponseStream()
    $readStream = New-Object System.IO.StreamReader $requestStream
     $data=$readStream.ReadToEnd()
   
    $results = $data | ConvertFrom-Json
    $N4result=$results.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results.Cells.results
    $Channels = @()
            foreach($r in $N4result){
                If($r.Key -eq "SiteName")
                {
                $Channels +=$r.Value
                }          
            }

    Write-Host "Collecting the Office 365 Video Channel Storage Details..." -ForegroundColor Green
    Connect-SPOService -Url $AdminPortalUrl -Credential $creds

    $data=@()
    Write-Host
    Write-Host "Office 365 Video Channel Storage Details:" -ForegroundColor Green
    Write-Host "-----------------------------------------" -ForegroundColor Green
    Write-Host
    foreach($chname in $Channels)
    {
        Write-Host "  ---------------------------------------------------------------------------  "
        Write-Host "Channel URL                  :",  $chname
        $site = Get-SPOSite -Identity $chname -Detailed
       
        $ctx=New-Object Microsoft.SharePoint.Client.ClientContext($site.URL)
        #$creds = New-Object System.Management.Automation.PSCredential -ArgumentList ($Username, $AdminPassword)
        $ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName,$creds.Password)
        $ctx.RequestTimeout = 1000000 # milliseconds
        $spoweb = $ctx.Web
        $ctx.Load($spoweb)
        $ctx.ExecuteQuery()
         Write-Host
        #write-host "Channel Name                 :", $spoweb.Title
        #Write-Host "Site collection Url          :", $ctx.Url #-BackgroundColor White -ForegroundColor DarkGreen
       
        Write-Host "Channel Name                 :", $site.Title -foregroundcolor Green
        Write-Host "Channel URL                  :", $site.URL -foregroundcolor Yellow
         Write-Host "ChannelStorageinMB           :", $site.StorageUsageCurrent -foregroundcolor Yellow
        write-host "Total Files                  :", $ListItems.Count -foregroundcolor Yellow

        $MyVideoslist = $spoweb.Lists.GetByTitle($VideoListName)
        $ListItems = $MyVideoslist.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
        $ctx.Load($ListItems)
        $ctx.ExecuteQuery()

        foreach($MyListItem in $ListItems)
        {
            $datum = New-Object -TypeName PSObject
            Write-Host "   > file:", $MyListItem["Title"], "- FileType:",  $MyListItem["File_x0020_Type"], "- Size (MB):", ([math]::round(($MyListItem["File_x0020_Size"]/(1024*1024)), 2)), "- FileURL:", $($MyListItem["FileDirRef"] +"/"+ $MyListItem["FileLeafRef"])
           
            $datum | Add-Member -MemberType NoteProperty -Name ChannelName -Value $site.Title
            $datum | Add-Member -MemberType NoteProperty -Name ChannelURL -Value $site.URL
            $datum | Add-Member -MemberType NoteProperty -Name ChannelStorageinMB -Value $site.StorageUsageCurrent
            $datum | Add-Member -MemberType NoteProperty -Name FileTotal -Value $ListItems.Count
            $datum | Add-Member -MemberType NoteProperty -Name FileName -Value $MyListItem["Title"]
            $datum | Add-Member -MemberType NoteProperty -Name FileType -Value $MyListItem["File_x0020_Type"]
            $datum | Add-Member -MemberType NoteProperty -Name FileSizeMB -Value ([math]::round(($MyListItem["File_x0020_Size"]/(1024*1024)), 2))
            $datum | Add-Member -MemberType NoteProperty -Name FileAbsoluteURL -Value  $($MyListItem["FileDirRef"] +"/"+ $MyListItem["FileLeafRef"])
            $data += $datum
        }
       
        #Write-Host "StorageQuotainGB             :", ($site.StorageQuota/1024) -foregroundcolor Green
        #Write-Host "StorageQuotaWarningLevelinGB :", ($site.StorageQuotaWarningLevel/1024) -foregroundcolor Green
        Write-Host ""
        Write-Host "  ---------------------------------------------------------------------------  "
    }

    $datestring = (get-date).ToString("yyyyMMdd-hhmm")
    $fileName = ("C:\VideoPortal\VideoPortalDetails_" + $datestring + ".csv")
   
     Write-host " -----------------------------------------" -ForegroundColor Green
    Write-Host (" >>> writing to file {0}" -f $fileName) -ForegroundColor Green
    $data | Export-csv $fileName -NoTypeInformation
    Write-host " -----------------------------------------" -ForegroundColor Green
       
}


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

# Get needed information from end user
[string]$SPOAdminPortal = "
https://yourtenant-admin.sharepoint.com"
[string]$SPOSiteURL = "https://yourtenant.sharepoint.com"

Invoke-RestSPO -AdminPortalUrl $SPOAdminPortal -SPOUrl $SPOSiteURL -UserName $username -Password $PwdTXTPath

Vous aurez alors la possibilité d’importer les détails dans un fichier Excel et obtenir la vue suivante:

Capture-ListOfFile

Vous pourrez alors avoir une meilleure idée de la tache à accomplir en migration ou intégration.

Romelard Fabrice

Version anglaise:

Informations additionnelles:

Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis

Dans un cadre de gestion Office 365, il est courant de devoir surveiller ou contrôler l’activité autour de l’ensemble du tenant O365 selon des critères définis (cas d’utilisation douteuse par exemple).

Depuis le site d’administration

Le site d’administration d’Office 365 vous permet d’accéder (selon vos droits) à la partie “Security & Compliance” :

Cette page vous permet alors de fournir certains critères de recherche:

  • Activity type
  • Start & End DateTime
  • UsersID (email or O365 login)
  • File, folder, url or site

Ces options permettent alors d’exécuter cette recherche et l’expoter en CSV ou de créer une alerte .

Toutes les informations sont fournis pour ce site:

En revanche, quelques restrictions existent sur cette solution dont:

  • Nombre de lignes (ou Events) limité à 50’000 max
  • Nombre de signes exportés dans la colonne AuditData est limité aux premiers 3’060 chars

Depuis PowerShell

A partir de nombreuses sources sur le Web, je vous fourni le script PowerShell suivant utilisable comme outil de base. Il travaille directement le jeu de résultat en mémoire pour exporter en CSV un résultat compréhensible.

La commande PowerShell utilisée est détaillée ici:


Function Split-O365AuditLogs-FromO365 ()
{
    #Get the content to process
    Write-host " -----------------------------------------" -ForegroundColor Green

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

    #This will prompt the user for credential
#    $UserCredential = Get-Credential

    $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-LiveID/ -Credential $UserCredential -Authentication Basic -AllowRedirection
    Import-PSSession $Session

    [DateTime]$startDate = "01/01/2019 00:00" #Format: mm/dd/yyyy hh:MM
    [DateTime]$endDate = "01/11/2019 23:59" #Format: mm/dd/yyyy hh:MM
    $SpecifiedUserIDs = "Youremailtoscan@yourtenant.com", "Youremailtoscan2@yourtenant.com" #syntax: "<value1>","<value2>",..."<valueX>".

    $scriptStart=(get-date)
     $sessionName = (get-date -Format 'u')+'o365auditlog'
    # Reset user audit accumulator
    $aggregateResults = @()
    $i = 0 # Loop counter
    Do {
        Write-host "  >> Audit Request Details: StartDate=", $startDate, "- EndDate=", $endDate, "SpecifiedUserIDs=", $SpecifiedUserIDs
        $currentResults = Search-UnifiedAuditLog -StartDate $startDate -EndDate $enddate -SessionId $sessionName -SessionCommand ReturnLargeSet -ResultSize 1000 -UserIds $SpecifiedUserIDs
        if ($currentResults.Count -gt 0)
        {
            Write-Host ("  Finished {3} search #{1}, {2} records: {0} min" -f [math]::Round((New-TimeSpan -Start $scriptStart).TotalMinutes,4), $i, $currentResults.Count, $user.UserPrincipalName )
            # Accumulate the data
             $aggregateResults += $currentResults
            # No need to do another query if the # recs returned <1k - should save around 5-10 sec per user
            if ($currentResults.Count -lt 1000)
            {
                $currentResults = @()
             }
            else
            {
                $i++
             }
        }
    } Until ($currentResults.Count -eq 0) # --- End of Session Search Loop --- #
   
    [int]$IntemIndex = 1
    $data=@()
    foreach ($line in $aggregateResults)
    {
        Write-host "  ItemIndex:", $IntemIndex, "- Creation Date:", $line.CreationDate, "- UserIds:", $line.UserIds, "- Operations:", $line.Operations
        Write-host "      > AuditData:", $line.AuditData
        $datum = New-Object -TypeName PSObject
         $Converteddata = convertfrom-json $line.AuditData
       
        $datum | Add-Member -MemberType NoteProperty -Name Id -Value $Converteddata.Id
        $datum | Add-Member -MemberType NoteProperty -Name CreationTimeUTC -Value $Converteddata.CreationTime
        $datum | Add-Member -MemberType NoteProperty -Name CreationTime -Value $line.CreationDate
        $datum | Add-Member -MemberType NoteProperty -Name Operation -Value $Converteddata.Operation
        $datum | Add-Member -MemberType NoteProperty -Name OrganizationId -Value $Converteddata.OrganizationId
         $datum | Add-Member -MemberType NoteProperty -Name RecordType -Value $Converteddata.RecordType
        $datum | Add-Member -MemberType NoteProperty -Name ResultStatus -Value $Converteddata.ResultStatus
        $datum | Add-Member -MemberType NoteProperty -Name UserKey -Value $Converteddata.UserKey
        $datum | Add-Member -MemberType NoteProperty -Name UserType -Value $Converteddata.UserType
        $datum | Add-Member -MemberType NoteProperty -Name Version -Value $Converteddata.Version
        $datum | Add-Member -MemberType NoteProperty -Name Workload -Value $Converteddata.Workload
        $datum | Add-Member -MemberType NoteProperty -Name UserId -Value $Converteddata.UserId
        $datum | Add-Member -MemberType NoteProperty -Name ClientIPAddress -Value $Converteddata.ClientIPAddress
        $datum | Add-Member -MemberType NoteProperty -Name ClientInfoString -Value $Converteddata.ClientInfoString
        $datum | Add-Member -MemberType NoteProperty -Name ClientProcessName -Value $Converteddata.ClientProcessName
        $datum | Add-Member -MemberType NoteProperty -Name ClientVersion -Value $Converteddata.ClientVersion
         $datum | Add-Member -MemberType NoteProperty -Name ExternalAccess -Value $Converteddata.ExternalAccess
        $datum | Add-Member -MemberType NoteProperty -Name InternalLogonType -Value $Converteddata.InternalLogonType
        $datum | Add-Member -MemberType NoteProperty -Name LogonType -Value $Converteddata.LogonType
        $datum | Add-Member -MemberType NoteProperty -Name LogonUserSid -Value $Converteddata.LogonUserSid
        $datum | Add-Member -MemberType NoteProperty -Name MailboxGuid -Value $Converteddata.MailboxGuid
        $datum | Add-Member -MemberType NoteProperty -Name MailboxOwnerSid -Value $Converteddata.MailboxOwnerSid
        $datum | Add-Member -MemberType NoteProperty -Name MailboxOwnerUPN -Value $Converteddata.MailboxOwnerUPN
         $datum | Add-Member -MemberType NoteProperty -Name OrganizationName -Value $Converteddata.OrganizationName
        $datum | Add-Member -MemberType NoteProperty -Name OriginatingServer -Value $Converteddata.OriginatingServer
        $datum | Add-Member -MemberType NoteProperty -Name SessionId -Value $Converteddata.SessionId
   
        $data += $datum
        $IntemIndex += 1
     }
    $datestring = (get-date).ToString("yyyyMMdd-hhmm")
    $fileName = ("C:\AuditLogs\CSVExport\" + $datestring + ".csv")
    
    Write-Host (" >>> writing to file {0}" -f $fileName)
    $data | Export-csv $fileName -NoTypeInformation

    Remove-PSSession $Session
}

Split-O365AuditLogs-FromO365


Vous pouvez utiliser ce script et l’adapter selon vos besoins.

Attention:

La limitation du champs AuditData reste présente même PowerShell, mais Microsoft Support connait le problème et travaille avec le groupe produit pour le fixer

Liens additionnels:

Fabrice Romelard

Version anglaise:

SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés

Office 365 possède l’option de gestion des droits de contenu basé sur les modules IRM. Cette option est soumise à license très élevée alors que son activation est globale.

Le fait est que lors de l’activation du module sur le tenant Office 365, n’importe quel content manager de site peut activer cette option dans sa propre liste. Une fois cette activation effectuée dans une liste de ce site, tous les utilisateurs y accédant devront avoir une licence E3.

Ainsi pour limiter ce gap de licence, le script suivant en préparant d’abord le fichier CSV d’exclusion:

SiteCollectionURL;

https://mytenant.sharepoint.com/sites/mysitecollwithIRMaccepted;

Le script PowerShell va obtenir tous les sites du tenant avec les commandes suivantes:

$sitesInfo1 = Get-SPOSite -Template "STS#0" -IncludePersonalSite:$false -Limit ALL | Sort-Object -Property url | Select *

$sitesInfo2 = Get-SPOSite -Template "GROUP#0" -IncludePersonalSite:$false -Limit ALL | Sort-Object -Property url | Select *

$sitesInfo = $sitesInfo2 + $sitesInfo1 | Sort url

Basé sur cette liste de collections, le script va alors bouclé dans toutes les listes de tous les sous-sites pour vérifier le status de l’option IRM:

  • S’il est désactivé: le script passe à la liste suivante et log le statut
  • S’il est activé: le script désactive l’option et enregistre le changement dans le log

Une fois terminé, le script va alors envoyé le log zippé par email avec un résumé des désactivations effectuées dans le body du mail.

Le script complet est le siuvant:

[string]$GLOBAL:Logtofile = ""
[string]$GLOBAL:LogtoEmail = ""

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

[string]$CSVExclusionFilePath = "C:\IRMCHECK\SiteCollectionsWithAuthorizedIRM.csv"

[string]$EmailAddressFrom = "supportteam@Yourdomain.com"
[string]$EmailAddressToSend = "supportteam@Yourdomain.com"
[string]$EmailSubject = "SHAREPOINT ONLINE IRM CHECK - "+ $(Get-Date).ToString("yyyy-MM-dd-hh:mm")
[string]$EmailSMTPServer = "smtp.Yourdomain.net"
[string]$EmailSMTPPort = "25"
$EmailencodingMail = [System.Text.Encoding]::UTF8

[string]$AllSiteWithListenableIRMLog = "AllSiteWithListenableIRM.log"
[string]$FolderDestinationLogFile = "D:\IRMCHECK\LOGS\"
[string]$DestinationLogFilePath = ""
[string]$ZippedLogFilePath = ""
[string]$MyRootFolderListURL = ""
$OFS = "`r`n"

[System.Diagnostics.Stopwatch] $sw;
$sw = New-Object System.Diagnostics.StopWatch
$sw.Start()

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

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

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

function Get-SPOWebs(){
param(
   $Url = $(throw "Please provide a Site Collection Url"),
   $Credential = $(throw "Please provide a Credentials")
)

  $context = New-Object Microsoft.SharePoint.Client.ClientContext($Url) 
  $context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Credential.UserName,$Credential.Password)
  $context.RequestTimeout = 1000000 # milliseconds
  $web = $context.Web
  $context.Load($web)
  $context.Load($web.Webs)
  $context.ExecuteQuery()
  foreach($web in $web.Webs)
  {
       Get-SPOWebs -Url $web.Url -Credential $Credential
       $web
  }
}

function Check-All-SPOWebLists(){
param(
   $Url = $(throw "Please provide a Site Collection Url"),
   $Credential = $(throw "Please provide a Credentials")
)
    $GLOBAL:Logtofile += " ------------------------------------------------------------------------------------ " + $OFS
    $GLOBAL:Logtofile += " Checks into the Subsite: "+ $Url + $OFS
   
    $context = New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Credential.UserName,$Credential.Password)
    $context.RequestTimeout = 1000000 # milliseconds
    $web = $context.Web
    $Mylists = $web.Lists;
    $Context.Load($Mylists)
    $Context.ExecuteQuery();
    Write-host "     -------------------- CHECK IN LISTS -------------------- "
    foreach($myList in $MyLists)
     {
        Write-host "           ==== List Name:", $mylist.Title  -ForegroundColor Magenta
        if($mylist.IrmEnabled)
         {
            Write-host "                IRM Status (IrmEnabled):", $mylist.IrmEnabled -ForegroundColor Red
            Write-host "                >>> NEED TO CONTROL OR DISABLE THE SETTING" -ForegroundColor Red
           
            # GET the Owner if possible ??
           
            #Force the IRM Disable at the list level
            $mylist.IrmEnabled = $false
             $mylist.Update()
            $Context.ExecuteQuery()
                 
            #Logging the change
            $GLOBAL:Logtofile += " IRM ACTIVE from the list: "+ $mylist.Title +" - in SPWeb: "+ $Url + $OFS
            $GLOBAL:LogtoEmail += " IRM ACTIVE from the list: "+ $mylist.Title +" - in SPWeb: "+ $Url + $OFS
        }
        else
        {
            Write-host "                IRM Status (IrmEnabled):", $mylist.IrmEnabled -ForegroundColor Green
            $GLOBAL:Logtofile += "   IRM Not active from the list: "+ $mylist.Title +" - in SPWeb: "+ $Url + $OFS
        }
    }
    $GLOBAL:Logtofile += " ------------------------------------------------------------------------------------ " + $OFS

}

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://tenant-admin.sharepoint.com -credential $adminCreds -ErrorAction SilentlyContinue -ErrorVariable Err

Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green
$SiteToExcludeList = Import-Csv -encoding UTF8 $CSVExclusionFilePath -delimiter ";"
#$SiteToExcludeList | Format-Table
Write-host "   >>> CSV File content loaded:", $CSVExclusionFilePath, "- Total Lines:", $SiteToExcludeList.count -ForegroundColor Yellow
Write-host " -------------------------------------------------------------------------------------------- " -ForegroundColor green

$TempPathFilename = $(Get-Date).ToString("yyyyMMdd-hhmmss-fff")+"_"+ $AllSiteWithListenableIRMLog
$DestinationLogFilePath = Join-Path -Path $FolderDestinationLogFile -ChildPath $TempPathFilename
if (Test-Path $DestinationLogFilePath)
{
    Remove-Item $DestinationLogFilePath -Force
}

#Retrieve all site collection infos (GroupSite and Classic TeamSite)
$sitesInfo1 = Get-SPOSite -Template "STS#0" -IncludePersonalSite:$false  -Limit ALL | Sort-Object -Property url | Select *
$sitesInfo2 = Get-SPOSite -Template "GROUP#0" -IncludePersonalSite:$false  -Limit ALL | Sort-Object -Property url | Select *

$sitesInfo = $sitesInfo2 + $sitesInfo1  | Sort url
#$sitesInfo = $sitesInfo1  | Sort url | Select-Object -First 2 #TO CHECK ONLY THE FIRST 2 CLASSIC TEAMSITE COLLECTION

Write-Host "--------------------------------------------------------------------------------------------"
Write-Host " =>>>>>>>  Site collections number to check:", $sitesInfo.count -ForegroundColor Magenta
Write-Host "--------------------------------------------------------------------------------------------"

foreach($SiteToExclude in $SiteToExcludeList)
{
    $sitesInfo = $sitesInfo | where {$_.url -ne $SiteToExclude.SiteCollectionURL} #remove all the excluded items from the site list
}

Write-Host "--------------------------------------------------------------------------------------------"
Write-Host " =>>>>>>>  Site collections number to check:", $sitesInfo.count -ForegroundColor Magenta
Write-Host "--------------------------------------------------------------------------------------------"

$GLOBAL:Logtofile += "--------------------------------------------------------------------------------------------" + $OFS
$GLOBAL:Logtofile +=  " =>>>>>>>  Site collections number to check: "+ $($sitesInfo.count) + $OFS
$GLOBAL:Logtofile +=  "--------------------------------------------------------------------------------------------" + $OFS

#Retrieve and print all sites
foreach ($site in $sitesInfo)
{
    #$SiteToExcludeList |Where-Object {$_.SiteCollectionURL -match $site.Url}

    Write-Host "==================================================================================================="
    Write-Host " => SPO Site collection:", $site.Url, "- Title:", $site.Title -ForegroundColor green
    Write-Host "   => External Sharing:", $site.SharingCapability, "- Site Template Used:", $site.Template
    Write-Host "--------------------------------------------------------------------------------------------"

    $GLOBAL:Logtofile += "===================================================================================================" + $OFS
    $GLOBAL:Logtofile += " => SPO Site collection: "+ $($site.Url) +" - Title: "+ $($site.Title) + $OFS
    $GLOBAL:Logtofile += "   => External Sharing: "+ $($site.SharingCapability) +" - Site Template Used: "+ $($site.Template) + $OFS
    $GLOBAL:Logtofile += "--------------------------------------------------------------------------------------------" + $OFS

    # ===> TO DO AND GET THE OFFICIAL SITE OWNER
    #Write-Host "   => Owner:", $site.Owner

    Check-All-SPOWebLists  -Url $site.Url -Credential $adminCreds -MyLogToFill

    $AllWebs = Get-SPOWebs -Url $site.Url -Credential $adminCreds
   
    foreach($MySPWeb in $AllWebs)
    {
        $GLOBAL:Logtofile += " ------------------------------------------------------------------------  " + $OFS
        $GLOBAL:Logtofile += "    => Subsite: "+ $($MySPWeb.Url) +" - Title: "+ $($MySPWeb.Title) + $OFS
        Write-Host "--------------------------------------------------------------------------------------------" -ForegroundColor yellow
        Write-Host "        ==>>", $MySPWeb.Title, "-", $MySPWeb.Url -ForegroundColor yellow
        Check-All-SPOWebLists  -Url $MySPWeb.Url -Credential $adminCreds -MyLogToFill
    }
    Write-Host "--------------------------------------------------------------------------------------------"
    $GLOBAL:Logtofile += " ------------------------------------------------------------------------  " + $OFS
}

$sw.Stop()

Write-host " ===================================================================================================" -ForegroundColor Green
write-host "     ===>>>>IRM Check and fix: ", $sw.Elapsed.ToString() -foreground Yellow
Write-host " ===================================================================================================" -ForegroundColor Green

$GLOBAL:Logtofile += " ===================================================================================================" + $OFS
$GLOBAL:Logtofile += "     ===>>>>IRM Check and fix: "+ $($sw.Elapsed.ToString()) + $OFS
$GLOBAL:Logtofile += " ===================================================================================================" + $OFS

if($GLOBAL:LogtoEmail -eq "")
{
    $GLOBAL:LogtoEmail += " There is no place where IRM is enable" + $OFS + $OFS
}

$GLOBAL:LogtoEmail += " ===================================================================================================" + $OFS
$GLOBAL:LogtoEmail += "  FIND THE DETAILS INTO THE LOG FILE AVAILABLE INTO THE SERVER FOLDER: "+ $DestinationLogFilePath + $OFS
$GLOBAL:LogtoEmail += " ===================================================================================================" + $OFS

add-content -Encoding UTF8 -Path $DestinationLogFilePath -Value $GLOBAL:Logtofile -Force

#Add the ZIP Action for the generated log file
$ZippedLogFilePath = $DestinationLogFilePath +".zip"
Compress-Archive -LiteralPath $DestinationLogFilePath -CompressionLevel Optimal -Update -Force -DestinationPath $ZippedLogFilePath

Send-MailMessage -From $EmailAddressFrom -to $EmailAddressToSend -Subject $EmailSubject -Body $GLOBAL:LogtoEmail -SmtpServer $EmailSMTPServer -port $EmailSMTPPort -Attachments $ZippedLogFilePath -Encoding $EmailencodingMail

Vous pouvez adapter et utiliser ce script à votre convenance.

Romelard Fabrice

Sites utilisés:

Version Anglaise:

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

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

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

Libre à vous de l’adapter à votre convenance.

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

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

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

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

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

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

Fabrice Romelard

Version anglaise:

Sources utilisées:

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

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

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

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

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

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

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

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

    # Load assemblies to PowerShell session

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

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

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

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

Load-DLLandAssemblies

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

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

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

[int]$i = 1;

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

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

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

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

}

Vous pouvez bien sur modifier ce script selon votre besoin.

Fabrice Romelard

Version anglaise:

Sources:

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

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

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

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


Import-Module MicrosoftTeams

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

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

Connect-MicrosoftTeams -Credential $cred


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

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

$ListOfMyTeams = Get-Team  -user $LoginToUser

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

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

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

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

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

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

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

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


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

Fabrice Romelard

Version Anglaise:

Sources utilisées pour le script:

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

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

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

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

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

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

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

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

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


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

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

[int]$TempUserID = 0

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

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

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

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

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

}

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

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

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

}

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

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

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

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

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

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

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

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

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

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

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

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

Write-host " "

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


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

Fabrice Romelard

Version Anglaise:

Les sources utilisées pour la construction:

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

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

Les avantages d’utiliser les Modern Pages

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

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

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

Présentation du Business Case

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

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

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

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

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

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


Task Title: Collect the Data from the Business

Topic:
  • 01. BASIC TASKS
Description:

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

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

PowerShell script:

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Get-PnPConnection
    $AllQuicklaunchNodes = Get-PnPNavigationNode

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


Résultat:

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

Untitled-HelpPageCreated-02

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

Untitled-HelpPageCreated-01

Exécution Post creation

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

Conclusion

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

Romelard Fabrice

English version published:

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

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

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

Donc la question vient très rapidement:

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

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

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

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

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

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

Capture-RepostPage-01

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

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

Capture-RepostPage-02

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

Capture-RepostPage-03

Mais aussi dans la page racine du Tenant:

Capture-RepostPage-04

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

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

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

Basé sur un autre message publié ici:

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

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

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

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

[int]$TempUserID = 0

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

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

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

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

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

}

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

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

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

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

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

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

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

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

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

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

   
}

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

    $GlobalNewsPageCSV | Format-Table

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

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

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


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

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

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

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

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

            $MyDestinationPagectx.ExecuteQuery()

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Write-host " "

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

Get-All-CSVNews-ComparedToPageList $Myctx $MyspoRootweb

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


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

Romelard Fabrice

Version en Anglais:

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

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

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

WebPartHomeNewsModernPage

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

WebPartHomeNewsModernPage03

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

WebPartHomeNewsModernPage02

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

Write-host " "

Get-All-PageList-UpdateMetadata $Myctx $MyspoRootweb



Vous pouvez l’adapter à vos besoins.

Fabrice Romelard

Message en Anglais:

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

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

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

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

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

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

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


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

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

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

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

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

    # Load assemblies to PowerShell session

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    $ExternalSharingSetting = $site.SharingCapability

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

    #Remove-SPOTheme -Name $themePaletteCustomName

    $AllThemes = Get-SPOTheme

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

ChangeTheLookModernPage-01

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

Fabrice Romelard

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

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

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

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

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

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

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

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

    # Load assemblies to PowerShell session

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

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

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

Load-DLLandAssemblies

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

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

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

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

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

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

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

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

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

Fabrice Romelard

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

planner_logo

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

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

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

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

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

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

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

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

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

SnipImage-CreateSubPlan-01

Dans la sélection, vous devez choisir Planner

SnipImage-CreateSubPlan-02

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

SnipImage-CreateSubPlan-03


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

SnipImage-CreateSubPlan-04

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

SnipImage-CreateSubPlan-05


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

SnipImage-CreateSubPlan-06

Attention:

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

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

Fabrice Romelard [MVP]

Plus de Messages Page suivante »


Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01