Aug 08 2018 07:39 AM
Into a previous message, we saw how to configure and implement the Modern Site Theme using a PowerShell script:
The question of the classical Theme management, is due to the presence of the link "Classic change the look options" into the modern site theme management screen.
That option will send you to the old SharePoint 2013 "Change the Look" solution.
From an admin point of view, the Theme management is different between Modern and Classic:
That is interesting to delegate the color management to the site owner, but always let them move back to the corporate colors if they want to.
So from the Tenant admin point of view, it's useful to have a solution to configure directly the site collections (root site and subsites) directly with a selection based on filtering.
It could reconfigure all the SharePoint standard sites or the group site, … depending of the filter you will apply into.
You need also to prepare the resource files (spconf, spcolor, backgroundfile and logo file).
The PowerShell script you can use and adapt as you need was used to reset more than 2000 site collections with a huge number of subsites without issue.
[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 " ---------------------------------------------- "
The source sites used to build that script are
This solution can also adapt it into your provisioning solution creating the Office 365 Teams or Groups.
Fabrice Romelard
Aug 08 2018 08:36 AM
The French version of the same article:
Fab