Set-SharePointSiteExperience.ps1
<#PSScriptInfo
.VERSION 1.0 .GUID e8d7e821-6902-44b7-a5a6-a22e05000332 .AUTHOR Aaron Guilmette .COMPANYNAME Microsoft .COPYRIGHT 2020 .TAGS .LICENSEURI .PROJECTURI https://www.undocumented-features.com/2019/05/28/switch-sharepoint-online-lists-between-classic-and-modern-experience/ .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .DESCRIPTION If you need to update/revert your SharePoint Online libraries and lists to Classic experience, look no further. This script will let you switch between Classic and Modern experiences for one or more sites in your tenant. .PRIVATEDATA #> <# .SYNOPSIS Switch SharePoint Online site experience between modern and classic. .PARAMETER AllSites Select all sites in tenant except Group sites (default). .PARAMETER WebAndSiteLevel Configure Classic or Modern every which way but loose. This option is mentioned in the documentation but does not appear to work at this time. .PARAMETER Credential Standard PSCredential object. .PARAMETER Experience Switch between Classic and Modern library/list experiences. .PARAMETER IncludeGroupSites Attempt to update the Experience type for Office 365 Group sites (will most likely not complete successfully). .PARAMETER InputFile List of SharePoint Sites. You can run (Get-SPOSite).Url to get a list of sites in your tenant. .PARAMETER ListLevel Update the ListExperienceOptions on each list item. .PARAMETER Site One or more SharePoint Online site URLs. .PARAMETER SkipValidation By default, script will check to ensure sites exist before attempting to update. If you are attempting to update a large list of sites, you may wish to skip this step. .PARAMETER Tenant Tenant name as either 'tenant.onmicrosoft.com' or 'tenant' .EXAMPLE .\Set-SharePointSiteExperience.ps1 -Credential $cred -Site https://contoso.sharepoint.com/sites/HR -Tenant contoso.sharepoint.com -Experience Classic Switch site https://tenant.sharepoint.com/sites/HR to the Classic library/list experience. .EXAMPLE .\Set-SharePointSiteExperience.ps1 -Credential $cred -Site https://contoso.sharepoint.com/sites/HR,https://contoso.sharepoint.com/sites/Engineering -Tenant contoso -Experience Classic Switch sites https://contoso.sharepoint.com/sites/HR and https://contoso.sharepoint.com/sites/Engineering to the Classic library/list experience. .EXAMPLE .\Set-SharePointSiteExperience.ps1 -Credential $cred -AllSites -Tenant contoso -Experience Modern Switch all sites in tenant contoso to Modern library/list experience. .NOTES 2020-04-21 Updated for PowerShell Gallery. 2019-05-17 Initial release. #> [CmdletBinding(DefaultParametersetName = 'SiteInputA')] Param ( # Credential object [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential]$Credential, # Specify a site or a list of sites [Parameter(ParameterSetName = 'SiteInputA', HelpMessage = 'Input one or more sites, comma separated.')] [array]$Site, [Parameter(ParameterSetName = 'SiteInputB', HelpMessage = 'Input one or more sites in a text file.')] [String]$InputFile, [Parameter(ParameterSetName = 'SiteInputC', HelpMessage = 'Apply to all sites.')] [switch]$AllSites, [Parameter(ParameterSetName = 'SiteInputC')] [switch]$IncludeGroupSites, [parameter(ParameterSetName = 'SiteInputA')] [parameter(ParameterSetName = 'SiteInputB')] [parameter(ParameterSetName = 'SiteInputC')] [switch]$SkipValidation, # Specify a tenant, either as 'tenant.onmicrosoft.com' or just 'tenant' [Parameter(mandatory = $true)] [String]$Tenant, # Site experience [ValidateSet("Classic", "Modern","Auto")] [string]$Experience, # Misc params [switch]$WebAndSiteLevel, [switch]$ListLevel = $true, [string]$Logfile = (Get-Date -Format yyyy-MM-dd) + "_SharePointSiteExperience.txt" ) # End Parameters # Preferences $ErrorActionPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' # Functions function Write-Log([string[]]$Message, [string]$LogFile = $Script:LogFile, [switch]$ConsoleOutput, [ValidateSet("SUCCESS", "INFO", "WARN", "ERROR", "DEBUG")][string]$LogLevel) { $Message = $Message + $Input If (!$LogLevel) { $LogLevel = "INFO" } switch ($LogLevel) { SUCCESS { $Color = "Green" } INFO { $Color = "White" } WARN { $Color = "Yellow" } ERROR { $Color = "Red" } DEBUG { $Color = "Gray" } } if ($Message -ne $null -and $Message.Length -gt 0) { $TimeStamp = [System.DateTime]::Now.ToString("yyyy-MM-dd HH:mm:ss") if ($LogFile -ne $null -and $LogFile -ne [System.String]::Empty) { Out-File -Append -FilePath $LogFile -InputObject "[$TimeStamp] [$LogLevel] $Message" } if ($ConsoleOutput -eq $true) { Write-Host "[$TimeStamp] [$LogLevel] :: $Message" -ForegroundColor $Color } } } function LoadSharePointLibraries { Write-Host -Fore Yellow "Locating SharePoint Server Client Components installation..." If (Test-Path 'c:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll') { Write-Host -ForegroundColor Green "Found SharePoint Server Client Components installation." Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.UserProfiles.dll" } ElseIf ($filename = (Get-ChildItem 'C:\Program Files' -Recurse -ea silentlycontinue | where { $_.name -eq 'Microsoft.SharePoint.Client.DocumentManagement.dll' })[0]) { $Directory = ($filename.DirectoryName)[0] Write-Host -ForegroundColor Green "Found SharePoint Server Client Components at $Directory." Add-Type -Path "$Directory\Microsoft.SharePoint.Client.dll" Add-Type -Path "$Directory\Microsoft.SharePoint.Client.Runtime.dll" Add-Type -Path "$Directory\Microsoft.SharePoint.Client.Taxonomy.dll" Add-Type -Path "$Directory\Microsoft.SharePoint.Client.UserProfiles.dll" } ElseIf (!(Test-Path 'C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll')) { Write-Host -ForegroundColor Yellow "This script requires the SharePoint Server Client Components. Attempting to download and install." wget 'https://download.microsoft.com/download/E/1/9/E1987F6C-4D0A-4918-AEFE-12105B59FF6A/sharepointclientcomponents_15-4711-1001_x64_en-us.msi' -OutFile ./SharePointClientComponents_15.msi wget 'https://download.microsoft.com/download/F/A/3/FA3B7088-624A-49A6-826E-5EF2CE9095DA/sharepointclientcomponents_16-4351-1000_x64_en-us.msi' -OutFile ./SharePointClientComponents_16.msi msiexec /i SharePointClientComponents_15.msi /qb msiexec /i SharePointClientComponents_16.msi /qb Sleep 60 If (Test-Path 'c:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll') { Write-Host -ForegroundColor Green "Found SharePoint Server Client Components." Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll" Add-Type -Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.UserProfiles.dll" } Else { Write-Host -NoNewLine -ForegroundColor Red "Please download the SharePoint Server Client Components from " Write-Host -NoNewLine -ForegroundColor Yellow "https://download.microsoft.com/download/F/A/3/FA3B7088-624A-49A6-826E-5EF2CE9095DA/sharepointclientcomponents_16-4351-1000_x64_en-us.msi " Write-Host -ForegroundColor Red "and try again." Break } } If (!(Get-Module -ListAvailable "*online.sharepoint*")) { Write-Host -ForegroundColor Yellow "This script requires the SharePoint Online Management Shell. Attempting to download and install." wget 'https://download.microsoft.com/download/0/2/E/02E7E5BA-2190-44A8-B407-BC73CA0D6B87/SharePointOnlineManagementShell_6802-1200_x64_en-us.msi' -OutFile ./SharePointOnlineManagementShell.msi msiexec /i SharePointOnlineManagementShell.msi /qb Write-Host -ForegroundColor Yellow "Please close and reopen the Windows Azure PowerShell module and re-run this script." } If (!(Get-Module -ListAvailable SharePointPnPPowerShellOnline | ? { $_.Version -ge '3.4.1812.1' })) { Install-Module SharePointPnPPowerShellOnline -Force } } function ConnectToSPO { If ($tenant -like "*.onmicrosoft.com") { $tenant = $tenant.split(".")[0] } $AdminURL = "https://$tenant-admin.sharepoint.com" Connect-SpoService -Credential $Credential -Url $AdminURL Import-Module SharePointPnPPowerShellOnline } LoadSharePointLibraries ConnectToSPO $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Credential.UserName, $Credential.Password) switch ($PSBoundParameters.Keys) { AllSites { switch ($IncludeGroupSites) { false { $Sites = (Get-SpoSite -Limit All | ? { $_.Url -notmatch "\-my\.sharepoint\.com" -and ($_.Template -ne "GROUP#0") }).Url } true { $Sites = (Get-SpoSite -Limit All | ? { $_.Url -notmatch "\-my\.sharepoint\.com" }).Url } default { $Sites = (Get-SpoSite -Limit All | ? { $_.Url -notmatch "\-my\.sharepoint\.com" -and ($_.Template -ne "GROUP#0") }).Url } } } Site { $Sites = @() If (!($SkipValidation)) { foreach ($url in $Site) { try { $Sites += (Get-SpoSite -Identity $url -ea stop).Url } catch { "Unable to find site $($Site)" } } } Else { [array]$Sites = $Site } } InputFile { $SiteList = Get-Content $InputFile If (!($SkipValidation)) { $Sites = @() { foreach ($url in $SiteList) { try { $Sites += (Get-SpoSite -Identity $url -ea stop).Url } catch { "Unable to find site $($Site)" } } } Else { [array]$Sites = $Site } } } } [int]$SitesTotal = $Sites.Count [int]$s = 1 foreach ($site in $Sites) { Write-Log -LogFile $Logfile -Message "Updating site $($Site) to $($Experience) Experience." -LogLevel INFO Write-Progress -Activity "Updating Sites to $($Experience) Experience" -PercentComplete (($s / $SitesTotal) * 100) -Status "$($SitesTotal - $s) sites remaining" -Id 1 Write-Progress -Activity "Site: $($Site)" -Id 2 -ParentId 1 $cmd = "Connect-PnpOnline -Url $($Site) -credentials `$Credential" Invoke-Expression $cmd If ($ListLevel) { $lists = Get-PnPList -Includes ListExperienceOptions; $ListsTotal = $lists.Count $l = 1 foreach ($list in $lists) { Write-Progress -Activity "Updating list $($list.Title)" -PercentComplete (($l / $ListsTotal) * 100) -Id 3 -ParentId 2 switch ($Experience) { Classic { $list.ListExperienceOptions = 2; } Modern { $list.ListExperienceOptions = 1; } Auto { $list.ListExperienceOptions = auto; } } try { $list.Update(); Invoke-PnPQuery Write-Log -LogFile $Logfile -LogLevel SUCCESS -Message "Updated $($Site)$($list.Title) to $($Experience)." } catch { Write-Log -LogFile $Logfile -LogLevel ERROR -Message "Failed to update $($Site)$($list.Title) to $($Experience) - Not supported for this list/library type." } $l++ } } # Updating Web and Collection settings # These settings are documented, but don't appear to work If ($WebAndSiteLevel) { switch ($Experience) { Classic { Enable-PnPFeature -Identity E3540C7D-6BEA-403C-A224-1A12EAFEE4C4 -Scope Site Enable-PnpFeature -Identity 52E14B6F-B1BB-4969-B89B-C4FAA56745EF -Scope Web } Modern { Disable-PnPFeature -Identity E3540C7D-6BEA-403C-A224-1A12EAFEE4C4 -Scope Site Disable-PnpFeature -Identity 52E14B6F-B1BB-4969-B89B-C4FAA56745EF -Scope Web } } } $s++ } |