选择退出新式列表和库体验

在 2016 年,我们为 SharePoint 引入了一种“新式”体验,它为经过全面改善的用户体验带来了可扩展性、可访问性和响应式设计。 从那时起,新式体验一直是整个 SharePoint 和 OneDrive 创新的基础,尽管经典模式仍受支持并且可用。 在新式体验中,大多数列表和库都可以正常工作,但也有一些列表无法在新式体验中正常工作或缺少相关功能。 这通常是由列表上的自定义(例如 JSLink)或列表表单页面上的自定义(例如使用了多个 Web 部件)所导致。 SharePoint 将检测大多数不兼容的自定义,并显示使用经典体验的受影响的列表和库,而网站中的其他列表和库将会使用新式体验进行显示。 如果不接受在新式体验与经典体验之间进行切换,那么你可以选择退出新式体验中的列表和库。 在本文中,你将了解可用的退出选项,如何检测可从退出新式体验中受益的列表和库,以及如何以最佳方式处理退出。

用于选择退出新式体验中的列表和库的选项

选择从网站集级别退出

你可以选择退出使用“新式”体验的网站集,方法是启用 ID 为 E3540C7D-6BEA-403C-A224-1A12EAFEE4C4 的功能。 使用以下 PnP PowerShell 启用/禁用所需的功能:

# Connect to a site
$cred = Get-Credential
Connect-PnPOnline -Url https://[tenant].sharepoint.com/sites/siteurl -Credentials $cred

# Opt out from modern lists and libraries at site collection level
Enable-PnPFeature -Identity E3540C7D-6BEA-403C-A224-1A12EAFEE4C4 -Scope Site
# And again enable modern lists and libraries at site collection level
#Disable-PnPFeature -Identity E3540C7D-6BEA-403C-A224-1A12EAFEE4C4 -Scope Site

选择从 Web 级别退出

你可以选择退出使用“新式”体验的 Web,方法是启用 ID 为 52E14B6F-B1BB-4969-B89B-C4FAA56745EF 的功能。 使用以下 PnP PowerShell 启用/禁用所需的功能:

# Connect to a site
$cred = Get-Credential
Connect-PnPOnline -Url https://[tenant].sharepoint.com/sites/siteurl -Credentials $cred

# Opt out from modern lists and libraries at web level
Enable-PnPFeature -Identity 52E14B6F-B1BB-4969-B89B-C4FAA56745EF  -Scope Web
# And again enable modern lists and libraries at web level
#Disable-PnPFeature -Identity 52E14B6F-B1BB-4969-B89B-C4FAA56745EF  -Scope Web

注意

PnP PowerShell 是一种开放源代码解决方案,其中包含为其提供支持的活动社区。 没有用于 Microsoft 开放源代码工具支持的 SLA。

选择从列表级别退出

要控制库级别的体验,你可以转到“列表设置”>“高级设置”,然后更改相关行为。

列表体验配置

也可以使用 PnP PowerShell 完成相同操作,如下面的代码片段所示:

# Connect to a site
$cred = Get-Credential
Connect-PnPOnline -Url https://[tenant].sharepoint.com/sites/siteurl -Credentials $cred

# Get the list to update
$list = Get-PnPList -Identity "Shared Documents" -Includes ListExperienceOptions

# Set the list experience (0 = Auto, 1 = modern, 2 = classic)
$list.ListExperienceOptions = 2
$list.Update()
Invoke-PnPQuery

注意

  • 库级别的设置将覆盖 Web 或网站集级别的设置。

如何检测可以选择退出新式体验的候选列表和库

只有在某些情况下才需要选择退出新式体验,如本文中所述。 上一章介绍了如何执行选择退出,但是如何确定哪些列表和库才是可以选择退出新式体验的候选列表和库呢?

SharePoint 新式化扫描程序将为你提供所需的答案:如果你在“完全扫描”或“新式列表体验准备情况”模式下运行扫描程序,则扫描程序将收集有关你的列表的所有数据。 通过使用所生成的新式 UI 列表准备情况 Excel 报告,你可以找到具有自定义的列表,如分析和使用扫描程序数据一文中所述。

由于 SharePoint 的经典回退机制,找到的列表将显示在经典体验中。 但是,如果你希望提供完整的经典用户体验,那么你可能会选择从新式列表和库中退出完整的网站集。 为简便起见,扫描程序将生成名为 SitesWithCustomizations.csv 的 CSV 文件,它列出了包含一个或多个可选择退出的列表的所有网站集。

此 CSV 文件是不含标题的网站集 URL 的简单列表,如以下示例所示:

"https://contoso.sharepoint.com/sites/siteA"
"https://contoso.sharepoint.com/sites/siteB"
"https://contoso.sharepoint.com/sites/siteC"

如何以最佳方式处理所选网站集的退出

你可以使用前文所述的选项从新式列表和库中退出列表、Web 或网站集。 如果你已使用扫描程序生成可以选择退出新式体验的候选网站集列表,则可以使用以下 PnP PowerShell 脚本执行“批量”选择退出。

<#
.SYNOPSIS
Enables or disables the modern list and library experience at site collection level. The script can handle a single site collection or a list of site collections provided via a CSV file. 

To get the CSV file you can run the Modernization Scanner, version 2.3 or higher, and use the "Lists and Library" mode (see https://aka.ms/sppnp-modernizationscanner) or alternatively 
create the file yourselves:

"https://contoso.sharepoint.com/sites/siteA"
"https://contoso.sharepoint.com/sites/siteB"
"https://contoso.sharepoint.com/sites/siteC"

.EXAMPLE
PS C:\> .\SetModernListUsage.ps1
#>

#region Logging and generic functions
function LogWrite
{
    param([string] $log , [string] $ForegroundColor)

    $global:strmWrtLog.writeLine($log)
    if([string]::IsNullOrEmpty($ForegroundColor))
    {
        Write-Host $log
    }
    else
    {    
        Write-Host $log -ForegroundColor $ForegroundColor
    }
}

function LogError
{
    param([string] $log)
    
    $global:strmWrtError.writeLine($log)
}

function UsageLog
{
    try 
    {
        $cc = Get-PnPContext
        $cc.Load($cc.Web)
        $cc.ClientTag = "SPDev:ModernListUsage"
        $cc.ExecuteQuery()
    }
    catch [Exception] { }
}
#endregion

function SiteCollectionUsesModernLists
{
    param([string] $siteCollectionUrl, 
          [Boolean] $useModern,
          $credentials,
          $tenantContext,
          [string] $adminUPN)
    
    
    #region Ensure access to the site collection, if needed promote the calling account to site collection admin
    # Check if we can access the site...if not let's 'promote' ourselves as site admin
    $adminClaim = "i:0#.f|membership|$adminUPN"    
    $adminWasAdded = $false
    $siteContext = $null    
    $siteCollectionUrl = $siteCollectionUrl.TrimEnd("/");

    Try
    {
        LogWrite "User running script: $adminUPN"
        LogWrite "Connecting to site $siteCollectionUrl"
        $siteContext = Connect-PnPOnline -Url $siteCollectionUrl -Credentials $credentials -Verbose -ReturnConnection
    }
    Catch [Exception]
    {
        # If Access Denied then use tenant API to add current tenant admin user as site collection admin to the current site
        if ($_.Exception.Response.StatusCode -eq "Unauthorized")
        {
            LogWrite "Temporarily adding user $adminUPN as site collection admin"
            Set-PnPTenantSite -Url $siteCollectionUrl -Owners @($adminUPN) -Connection $tenantContext
            $adminWasAdded = $true
            LogWrite "Second attempt to connect to site $siteCollectionUrl"
            $siteContext = Connect-PnPOnline -Url $siteCollectionUrl -Credentials $credentials -Verbose -ReturnConnection
        }
        else 
        {
            $ErrorMessage = $_.Exception.Message
            LogWrite "Error for site $siteCollectionUrl : $ErrorMessage" Red
            LogError $ErrorMessage
            return              
        }
    }
    #endregion

    Try
    {
        #region Adding admin
        # Check if current tenant admin is part of the site collection admins, if not add the account        
        $siteAdmins = $null
        if ($adminWasAdded -eq $false)
        {
            try 
            {
                # Eat exceptions here...resulting $siteAdmins variable will be empty which will trigger the needed actions                
                $siteAdmins = Get-PnPSiteCollectionAdmin -Connection $siteContext -ErrorAction Ignore
            }
            catch [Exception] { }
            
            $adminNeedToBeAdded = $true
            foreach($admin in $siteAdmins)
            {
                if ($admin.LoginName -eq $adminClaim)
                {
                    $adminNeedToBeAdded = $false
                    break
                }
            }

            if ($adminNeedToBeAdded)
            {
                LogWrite "Temporarily adding user $adminUPN as site collection admin"
                Set-PnPTenantSite -Url $siteCollectionUrl -Owners @($adminUPN) -Connection $tenantContext
                $adminWasAdded = $true
            }
        }

        UsageLog
        #endregion
        
        #region Enable/disable the modern list experience at site collection level
        if ($useModern)
        {
            LogWrite "Disabling the modern list blocking feature"
            Disable-PnPFeature -Identity "E3540C7D-6BEA-403C-A224-1A12EAFEE4C4" -Scope Site -Force -Connection $siteContext
        }
        else
        {
            LogWrite "Enabling the modern list blocking feature"
            Enable-PnPFeature -Identity "E3540C7D-6BEA-403C-A224-1A12EAFEE4C4" -Scope Site -Force -Connection $siteContext
        }
        #endregion

        #region Cleanup updated permissions
        LogWrite "Configuration is done, let's cleanup the configured permissions"
    
        # Remove the added site collection admin - obviously this needs to be the final step in the script :-)
        if ($adminWasAdded)
        {
            LogWrite "Remove $adminUPN from site collection administrators"            
            Remove-PnPSiteCollectionAdmin -Owners @($adminUPN) -Connection $siteContext
        }
        #endregion

        LogWrite "Configuration done for site collection $siteCollectionUrl" Green
        
        # Disconnect PnP Powershell from site
        Disconnect-PnPOnline
    }
    Catch [Exception]
    {
        $ErrorMessage = $_.Exception.Message
        LogWrite "Error: $ErrorMessage" Red
        LogError $ErrorMessage

        #region Cleanup updated permissions on error
        # Configuration did not complete...remove the added tenant admin to restore site permissions as final step in the cleanup
        if ($adminWasAdded)
        {
            try 
            {
                # Final step, remove the added site collection admin
                Remove-PnPSiteCollectionAdmin -Owners @($adminUPN) -Connection $siteContext
            }
            catch [Exception] { }
        }
        #endregion

        LogWrite "Configuration failed for site collection $siteCollectionUrl" Red
    } 

}

#######################################################
# MAIN section                                        #
#######################################################

# OVERRIDES
# If you want to automate the run and make the script ask less questions, feel free to hardcode these 2 values below. Otherwise they'll be asked from the user or parsed from the values they input

# Tenant admin url
$tenantAdminUrl = "" # e.g. "https://contoso-admin.sharepoint.com"
# If you use credential manager then specify the used credential manager entry, if left blank you'll be asked for a user/pwd
$credentialManagerCredentialToUse = ""

#region Setup Logging
$date = Get-Date
$logfile = ((Get-Item -Path ".\" -Verbose).FullName + "\ModernListUsage_log_" + $date.ToFileTime() + ".txt")
$global:strmWrtLog=[System.IO.StreamWriter]$logfile
$global:Errorfile = ((Get-Item -Path ".\" -Verbose).FullName + "\ModernListUsage_error_" + $date.ToFileTime() + ".txt")
$global:strmWrtError=[System.IO.StreamWriter]$Errorfile
#endregion

#region Load needed PowerShell modules
# Ensure PnP PowerShell is loaded

$minimumVersion = New-Object System.Version("3.4.1812.2")
if (-not (Get-InstalledModule -Name SharePointPnPPowerShellOnline -MinimumVersion $minimumVersion -ErrorAction Ignore)) 
{
    Install-Module SharePointPnPPowerShellOnline -MinimumVersion $minimumVersion -Scope CurrentUser
}
Import-Module SharePointPnPPowerShellOnline -DisableNameChecking -MinimumVersion $minimumVersion
#endregion

#region Gather set modern list usage run input
# Url of the site collection to remediate
$siteCollectionUrlToConfigure = ""
$enableModern = $false

# Get the input information
$siteURLFile = Read-Host -Prompt "Input either single site collection URL (e.g. https://contoso.sharepoint.com/sites/teamsite1) or name of .CSV file (e.g. SitesWithCustomizations.csv) ?"
if (-not $siteURLFile.EndsWith(".csv"))
{
    $siteCollectionUrlToConfigure = $siteURLFile
}
# If we are using a CSV, we'll need to get the tenant admin url from the user or use the hardcoded one
else 
{
    if ($tenantAdminUrl -eq $null -or $tenantAdminUrl.Length -le 0) 
    {
        $tenantAdminUrl = Read-Host -Prompt "Input the tenant admin site URL (like https://contoso-admin.sharepoint.com)"
    }
}

$enableModernString = Read-Host -Prompt "Do you want to enable modern lists and libraries for this site collection? Enter True for yes, False otherwise"
try 
{
    $enableModern = [System.Convert]::ToBoolean($enableModernString) 
} 
catch [FormatException]
{
    $enableModern = $false
}

# We'll parse the tenantAdminUrl from site url (unless it's set already!)
if ($tenantAdminUrl -eq $null -or $tenantAdminUrl.Length -le 0) 
{
    if ($siteURLFile.IndexOf("/teams") -gt 0) 
    {
        $tenantAdminUrl = $siteURLFile.Substring(0, $siteURLFile.IndexOf("/teams")).Replace(".sharepoint.", "-admin.sharepoint.")
    }
    else 
    {
        $tenantAdminUrl = $siteURLFile.Substring(0, $siteURLFile.IndexOf("/sites")).Replace(".sharepoint.", "-admin.sharepoint.")
    }
}

# Get the tenant admin credentials.
$credentials = $null
$adminUPN = $null
if(![String]::IsNullOrEmpty($credentialManagerCredentialToUse) -and (Get-PnPStoredCredential -Name $credentialManagerCredentialToUse) -ne $null)
{
    $adminUPN = (Get-PnPStoredCredential -Name $credentialManagerCredentialToUse).UserName
    $credentials = $credentialManagerCredentialToUse
}
else
{
    # Prompts for credentials, if not found in the Windows Credential Manager.
    $adminUPN = Read-Host -Prompt "Please enter admin UPN (e.g. admin@contoso.onmicrosoft.com)"
    $pass = Read-host -AsSecureString "Please enter admin password"
    $credentials = new-object management.automation.pscredential $adminUPN,$pass
}

if($credentials -eq $null) 
{
    Write-Host "Error: No credentials supplied." -ForegroundColor Red
    exit 1
}
#endregion

#region Connect to SharePoint
# Get a tenant admin connection, will be reused in the remainder of the script
LogWrite "Connect to tenant admin site $tenantAdminUrl"
$tenantContext = Connect-PnPOnline -Url $tenantAdminUrl -Credentials $credentials -Verbose -ReturnConnection
#endregion

#region Configure the site(s)
if (-not $siteURLFile.EndsWith(".csv"))
{
    # Remediate the given site collection
    SiteCollectionUsesModernLists $siteCollectionUrlToConfigure $enableModern $credentials $tenantContext $adminUPN
}
else 
{
    $csvRows = Import-Csv $siteURLFile -Header SiteCollectionUrl
    
    foreach($row in $csvRows)
    {
        if($row.SiteCollectionUrl -ne "")
        {
            $siteUrl = $row.SiteCollectionUrl
            SiteCollectionUsesModernLists $siteUrl $enableModern $credentials $tenantContext $adminUPN
        }
    }
}
#endregion

#region Close log files
if ($global:strmWrtLog -ne $NULL)
{
    $global:strmWrtLog.Close()
    $global:strmWrtLog.Dispose()
}

if ($global:strmWrtError -ne $NULL)
{
    $global:strmWrtError.Close()
    $global:strmWrtError.Dispose()
}
#endregion