À proposExpertiseRéalisationsR&DBlogOutilsCommencerContact

Migrer SharePoint 2016 et 2019 vers Subscription Edition : les scripts

SharePoint 2016 passe directement à Subscription Edition. Il n'y a pas d'escale par 2019, la méthode est le database attach et rien d'autre, et l'ordre des service applications n'est pas une préférence. Toute la séquence en PowerShell, de l'inventaire que l'on prend avant de toucher à quoi que ce soit jusqu'à l'analyse que l'on lance à la fin.

pH7x Systems® · · 19 min de lecture

Le support de SharePoint Server 2016 et 2019 prend fin le 14 juillet 2026, et la seule destination on-premises prise en charge est Subscription Edition. Cet article est la séquence, en PowerShell, avec les points qui bloquent une migration signalés là où ils mordent vraiment.

Une chose avant le code, parce qu'elle change le plan et le budget.

SharePoint 2016 passe directement à Subscription Edition

La croyance la plus coûteuse de ce projet est qu'il faut passer d'abord par 2019. Ce n'est pas le cas.

"SharePoint Server Subscription Edition prend en charge la mise à niveau de version à version N - 1 et N - 2. Vous pouvez mettre à niveau directement depuis les produits SharePoint suivants en utilisant la procédure standard de database attach : SharePoint Server 2019 (y compris Project Server 2019), SharePoint Server 2016 (y compris Project Server 2016)."

Une seule escale, depuis l'un ou l'autre. La double escale n'est obligatoire qu'en dessous de 2016 :

"La mise à niveau directe par database attach depuis des versions de SharePoint antérieures à SharePoint Server 2016 n'est pas prise en charge. SharePoint 2013, SharePoint 2010 et ainsi de suite doivent d'abord être mis à niveau vers SharePoint Server 2016 ou SharePoint Server 2019 par database attach, avant la mise à niveau vers SharePoint Server Subscription Edition."

Chemins de mise à niveau vers Subscription Edition. SharePoint Server 2016 et SharePoint Server 2019 passent tous deux directement à Subscription Edition, en une seule escale par database attach. SharePoint 2013 et antérieurs doivent d'abord être mis à niveau vers 2016 ou 2019, et seulement ensuite vers Subscription Edition. La version minimale de base de données acceptée est 16.0.4351.1000, qui est la build RTM de SharePoint Server 2016

Et il y a un plancher sous tout cela :

"Toutes les bases de données doivent être mises à niveau vers la version 16.0.4351.1000 ou supérieure, faute de quoi la mise à niveau vers SharePoint Server Subscription Edition sera bloquée."

Ce numéro est la build RTM de SharePoint Server 2016. Une base de données née en 2016 le dépasse par définition. Celle qui est refusée est celle qui venait de 2013, a été attachée à une ferme 2016 et n'a jamais vraiment terminé le voyage.

La méthode décide du plan

Il n'y a pas de mise à niveau sur place. La seule voie prise en charge est le database attach, autrement dit vous construisez une seconde ferme et vous y déplacez le contenu. La configuration ne voyage pas : web applications, service applications, stratégies et paramètres se reconstruisent à la main dans la nouvelle ferme. Ce n'est pas une limite à contourner, c'est la forme du projet.

Les quatre phases d'une mise à niveau par database attach vers Subscription Edition, et la contrainte d'ordre à l'intérieur de la phase trois. La phase un crée la ferme Subscription Edition. La phase deux copie les bases de données. La phase trois met à niveau les service applications, où Managed Metadata et User Profile doivent tous deux être mis à niveau avant Search, et tous deux avant tout My Site. La phase quatre teste et monte les bases de données de contenu. Les collections de sites se mettent ensuite à niveau automatiquement

Tout ce qui suit suppose la SharePoint Management Shell ouverte en administrateur élevé, avec le compte détenant db_owner sur chaque base de données mise à niveau, securityadmin sur l'instance SQL, l'appartenance au groupe Administrateurs local, et les droits accordés par Add-SPShellAdmin.

Aucun des scripts ci-dessous n'a été exécuté contre une ferme. Nous n'en avons pas. Chaque cmdlet et chaque paramètre vient de la documentation de Microsoft, mais la séquence entière n'a pas été exécutée : traitez-la comme un plan à répéter, pas comme un script à coller en production. La section de la répétition, à la fin, n'est pas un conseil facultatif.

Phase 0 : l'inventaire, pris avant que quoi que ce soit ne bouge

La nouvelle ferme doit pouvoir répondre de tout ce que l'ancienne avait. Prenez l'inventaire d'abord, gardez-le sous contrôle de version, et comparez-le à la fin. Ceci s'exécute sur l'ancienne ferme.

powershell
# INVENTORY.PS1: runs on the SharePoint 2016 or 2019 farm.
# Reads only. Produces the record that the new farm gets compared against.
$out = "C:\Migration\inventory"
New-Item -ItemType Directory -Path $out -Force | Out-Null

# Patch level of every SharePoint product in the farm. This is the documented
# way to see what is actually installed, server by server.
Get-SPProduct |
  Select-Object ProductName, @{n='Patches';e={ $_.PatchableUnitDisplayNames -join '; ' }} |
  Export-Csv "$out\products.csv" -NoTypeInformation -Encoding UTF8

# Web applications with their URLs and authentication. The new farm has to
# reproduce these URLs exactly, or every link inside the content breaks.
Get-SPWebApplication -IncludeCentralAdministration |
  Select-Object DisplayName, Url,
    @{n='Zones';e={ ($_.AlternateUrls | ForEach-Object { "$($_.UrlZone)=$($_.IncomingUrl)" }) -join ' | ' }},
    @{n='ClaimsMode';e={ $_.UseClaimsAuthentication }} |
  Export-Csv "$out\webapps.csv" -NoTypeInformation -Encoding UTF8

# Content databases, their sizes and how many site collections each holds.
# The counts are what tells you which mount will take twenty minutes and
# which will take six hours.
Get-SPContentDatabase |
  Select-Object Name, Server, WebApplication, CurrentSiteCount,
    @{n='SizeGB';e={ [math]::Round($_.DiskSizeRequired / 1GB, 2) }} |
  Export-Csv "$out\contentdbs.csv" -NoTypeInformation -Encoding UTF8

# Farm solutions. These have to be deployed to the new farm BEFORE the content
# databases are tested, and this list is what you deploy.
Get-SPSolution |
  Select-Object Name, Deployed, ContainsGlobalAssembly, ContainsWebApplicationResource,
    @{n='DeployedTo';e={ ($_.DeployedWebApplications | ForEach-Object { $_.Url }) -join ' | ' }} |
  Export-Csv "$out\solutions.csv" -NoTypeInformation -Encoding UTF8

# Service applications and their databases. Five of these can be upgraded.
# Everything else on this list is a rebuild, and it is better to know now.
Get-SPServiceApplication |
  Select-Object DisplayName, TypeName, Status |
  Export-Csv "$out\serviceapps.csv" -NoTypeInformation -Encoding UTF8

Get-SPDatabase |
  Select-Object Name, Type, Server,
    @{n='SizeGB';e={ [math]::Round($_.DiskSizeRequired / 1GB, 2) }} |
  Export-Csv "$out\databases.csv" -NoTypeInformation -Encoding UTF8

# Every site collection, with its template. The templates are what a missing
# feature shows up as later, so this is the list you check against.
Get-SPSite -Limit All |
  Select-Object Url, @{n='Template';e={ $_.RootWeb.WebTemplate + '#' + $_.RootWeb.Configuration }},
    ContentDatabase, Owner |
  Export-Csv "$out\sites.csv" -NoTypeInformation -Encoding UTF8

Write-Host "Inventory written to $out" -ForegroundColor Green

Deux de ces fichiers gagnent leur place immédiatement. solutions.csv devient la phase 2, et webapps.csv devient la phase 1, parce que les URL de la nouvelle ferme doivent correspondre aux anciennes caractère pour caractère.

Phase 1 : la ferme qui reçoit

Construisez la ferme Subscription Edition, puis recréez les web applications. Une décision à prendre délibérément : si vous comptez mettre à niveau les bases de données des service applications, n'utilisez pas le Farm Configuration Wizard pour les créer. L'assistant les crée vides, et une service application Managed Metadata vide n'est pas quelque chose que l'on pointe ensuite vers son ancienne base de données.

Les certificats d'abord, parce que Subscription Edition les gère dans la ferme et qu'une web application peut en recevoir un dès sa création.

powershell
# CERTIFICATES. Subscription Edition deploys imported certificates to the
# Windows certificate store on every server in the farm automatically, and
# to any server that joins later.
$pfxPassword = Read-Host -AsSecureString -Prompt 'PFX password'
Import-SPCertificate -Path '\\fileserver\certs\sharepoint.contoso.com.pfx' `
                     -Password $pfxPassword -Exportable

# The whole chain has to be present, not just the leaf, or SSL connections fail.
Import-SPCertificate -Path '\\fileserver\certs\issuing-ca.p7b'

# Confirm what landed, and in which store.
Get-SPCertificate | Select-Object DisplayName, Store, NotAfter, Thumbprint

# Warn earlier than the default. The health rules then chase expiry for you.
Set-SPCertificateSettings -CertificateExpirationWarningThreshold 45

Puis les web applications, en accord avec l'inventaire.

powershell
# WEB APPLICATIONS. The URL must match the old farm exactly: it is written
# into links, into search results and into anything anyone ever bookmarked.
$appPoolAccount = Get-SPManagedAccount 'CONTOSO\svc-sp-content'

# Windows claims. Classic mode was REMOVED for content web applications in
# Subscription Edition, so a farm that was still classic changes here, not later.
$ap = New-SPAuthenticationProvider

New-SPWebApplication -Name 'Contoso Intranet' `
    -ApplicationPool 'ContosoIntranetPool' `
    -ApplicationPoolAccount $appPoolAccount `
    -AuthenticationProvider $ap `
    -Port 443 -SecureSocketsLayer `
    -HostHeader 'sharepoint.contoso.com' `
    -Url 'https://sharepoint.contoso.com' `
    -Certificate 'sharepoint.contoso.com' `
    -UseServerNameIndication `
    -DatabaseName 'SP_Content_Placeholder'

# Server Name Indication is what lets several web applications share port 443
# with their own certificates. Without it they all share one certificate.

La base de données de remplissage est délibérée : la web application en a besoin d'une pour exister, et les vraies bases de contenu arrivent en phase 4. Supprimez-la ensuite, une fois les vraies montées.

Un piège qui coûte une interruption de service. Si vous modifiez plus tard les liaisons avec Set-SPWebApplication, redonnez-les toutes :

"Tous les paramètres de liaison IIS doivent être respécifiés lors de la mise à jour de la liaison d'un site IIS via le cmdlet Set-SPWebApplication. Cela comprend l'URL, le paramètre secure sockets layer, le numéro de port, le host header et le certificat. Si un paramètre de liaison n'est pas respécifié, il reviendra à sa valeur par défaut."

powershell
# Right: every binding setting stated, even the ones that are not changing.
Set-SPWebApplication -Identity 'https://sharepoint.contoso.com' -Zone Default `
    -Port 443 -SecureSocketsLayer `
    -HostHeader 'sharepoint.contoso.com' `
    -Url 'https://sharepoint.contoso.com' `
    -Certificate 'sharepoint.contoso.com' `
    -UseServerNameIndication

Phase 2 : les personnalisations passent avant le contenu

C'est l'erreur d'ordre qui produit la session de diagnostic la plus longue et la moins utile du projet. Test-SPContentDatabase signale chaque fonctionnalité, modèle et assembly que le contenu référence et ne trouve pas. Lancez-le avant que les solutions soient déployées et vous obtenez un rapport de centaines d'entrées qui sont toutes le même problème.

Microsoft la désigne comme la cause fréquente :

"Une cause fréquente d'échec pendant la mise à niveau est que l'environnement n'a pas les fonctionnalités, solutions ou autres éléments personnalisés."

powershell
# SOLUTIONS. Driven from solutions.csv, produced by the inventory.
$wsps = Import-Csv 'C:\Migration\inventory\solutions.csv'

foreach ($w in $wsps) {
    $path = Join-Path 'C:\Migration\wsp' $w.Name
    if (-not (Test-Path $path)) {
        Write-Warning "MISSING: $($w.Name). Find the package, or the sites that use it will not upgrade cleanly"
        continue
    }

    $solution = Add-SPSolution -LiteralPath $path

    # GACDeployment is required when the package contains a global assembly.
    # The inventory recorded that per solution, so it is not a guess.
    $gac = [bool]::Parse($w.ContainsGlobalAssembly)

    if ($w.ContainsWebApplicationResource -eq 'True') {
        Install-SPSolution -Identity $solution -AllWebApplications `
                           -GACDeployment:$gac -Force
    } else {
        Install-SPSolution -Identity $solution -GACDeployment:$gac -Force
    }
}

# Deployment is asynchronous: it runs on a timer job. Wait for it, or the
# next phase tests against a farm that is still deploying.
do {
    Start-Sleep -Seconds 15
    $pending = Get-SPSolution | Where-Object { $_.JobExists }
    Write-Host "Waiting for $($pending.Count) solution job(s)..."
} while ($pending)

Get-SPSolution | Select-Object Name, Deployed, DeploymentState | Format-Table -AutoSize

Ce qui reste sur la liste des manquants est une décision, pas un avertissement. Soit le paquet est retrouvé et reconstruit, soit les sites qui en dépendent sont inventoriés et traités avant la migration, pas pendant.

Phase 3 : geler, copier, dégeler

L'ancienne ferme passe en lecture seule plutôt que hors ligne, pour que les gens continuent de lire pendant la copie. Ceci est du T-SQL, sur l'instance source.

sql
-- ON THE OLD FARM'S SQL INSTANCE.
-- Read-only, not offline: people keep reading during the copy window.
ALTER DATABASE [WSS_Content_Intranet] SET READ_ONLY WITH ROLLBACK IMMEDIATE;

-- COPY_ONLY leaves the existing backup chain intact. Without it, this backup
-- becomes part of the chain and the scheduled restore plan quietly changes.
-- CHECKSUM makes the restore refuse a backup that was damaged in transit.
BACKUP DATABASE [WSS_Content_Intranet]
    TO DISK = N'\\fileserver\migration\WSS_Content_Intranet.bak'
    WITH COPY_ONLY, COMPRESSION, CHECKSUM, STATS = 5;
sql
-- ON THE SUBSCRIPTION EDITION FARM'S SQL INSTANCE.
RESTORE DATABASE [WSS_Content_Intranet]
    FROM DISK = N'\\fileserver\migration\WSS_Content_Intranet.bak'
    WITH MOVE 'WSS_Content_Intranet'     TO N'E:\SQLData\WSS_Content_Intranet.mdf',
         MOVE 'WSS_Content_Intranet_log' TO N'F:\SQLLogs\WSS_Content_Intranet_log.ldf',
         REPLACE, STATS = 5;

-- A restored copy inherits the read-only state, and a read-only database
-- cannot be attached. This is the step people forget, and Mount fails on it.
ALTER DATABASE [WSS_Content_Intranet] SET READ_WRITE WITH ROLLBACK IMMEDIATE;

Les trois mêmes instructions s'appliquent aux bases de données des service applications, avec une exception traitée à la phase suivante : la base d'administration de Search est copiée plus tard, et seulement après que Search a été suspendu.

Phase 4 : les service applications, dans l'ordre qui n'est pas une préférence

Cinq bases de données de service applications peuvent être mises à niveau : Business Data Connectivity, Managed Metadata, Secure Store, User Profile et Search. Tout le reste se reconfigure à la main, et deux sont explicitement refusées :

"Word Automation Services et Machine Translation Services ne peuvent pas être mis à niveau. Il faudra créer une nouvelle instance du service."

L'ordre est fixé par les dépendances. Managed Metadata et User Profile passent tous deux avant Search, et tous deux avant tout My Site.

powershell
# SERVICE APPLICATIONS. Order matters: MMS and UPA before Search.
$applicationPool = Get-SPServiceApplicationPool -Identity 'SharePoint Web Services default'

# --- Secure Store -------------------------------------------------------
# The passphrase is from the OLD farm. Without it the stored credentials are
# unreadable, and no amount of restoring gets them back.
$sss  = New-SPSecureStoreServiceApplication -Name 'Secure Store' `
            -ApplicationPool $applicationPool `
            -DatabaseName 'Secure_Store_Service_DB' -AuditingEnabled
$sssp = New-SPSecureStoreServiceApplicationProxy -Name 'Secure Store Proxy' `
            -ServiceApplication $sss -DefaultProxyGroup

$oldPassphrase = Read-Host -Prompt 'Secure Store passphrase from the old farm'
Update-SPSecureStoreApplicationServerKey -Passphrase $oldPassphrase `
            -ServiceApplicationProxy $sssp

# --- Business Data Connectivity ----------------------------------------
# The only one that creates its own proxy and puts it in the default group.
New-SPBusinessDataCatalogServiceApplication -Name 'BDC Service' `
    -ApplicationPool $applicationPool -DatabaseName 'BDC_Service_DB'

# --- Managed Metadata ---------------------------------------------------
$mms = New-SPMetadataServiceApplication -Name 'Managed Metadata Service' `
           -ApplicationPool $applicationPool `
           -DatabaseName 'Managed_Metadata_Service_DB'
New-SPMetadataServiceApplicationProxy -Name 'Managed Metadata Proxy' `
    -ServiceApplication $mms -DefaultProxyGroup

# --- User Profile -------------------------------------------------------
# After Managed Metadata, and before any My Site is touched. The Sync
# database is NEW: only Profile and Social come across.
New-SPProfileServiceApplication -Name 'User Profile Service Application' `
    -ApplicationPool $applicationPool `
    -ProfileDBName 'UPA_ProfileDB' `
    -SocialDBName  'UPA_SocialDB' `
    -ProfileSyncDBName 'UPA_SyncDB'

$upa = Get-SPServiceApplication | Where-Object { $_.TypeName -eq 'User Profile Service Application' }
New-SPProfileServiceApplicationProxy -Name 'User Profile Proxy' -ServiceApplication $upa

$upaProxy = Get-SPServiceApplicationProxy |
            Where-Object { $_.TypeName -eq 'User Profile Service Application Proxy' }
Add-SPServiceApplicationProxyGroupMember -member $upaProxy -identity ''

Search vient en dernier, et comporte une étape qui s'exécute sur l'ancienne ferme en plein milieu.

powershell
# --- Search, part one: ON THE OLD FARM ---------------------------------
# The Search Administration database is copied later than the others, because
# Search has to be paused first. While it is paused the old index stops
# updating, so results on the old farm get staler during the window.
$ssaOld = Get-SPEnterpriseSearchServiceApplication 'Search Service Application'
Suspend-SPEnterpriseSearchServiceApplication -Identity $ssaOld
# Now set the Search Admin DB read-only, back it up and restore it, as in phase 3.
powershell
# --- Search, part two: ON THE SUBSCRIPTION EDITION FARM ----------------
# The Search service instance cannot be started from Central Administration
# until a Search service application exists, so PowerShell it is.
$searchInst = Get-SPEnterpriseSearchServiceInstance -local
Start-SPServiceInstance $searchInst

# Restore, not New: this is what upgrades the admin database instead of
# creating an empty one. It keeps the search schema, the result sources and
# the query rules. It does NOT keep the index.
Restore-SPEnterpriseSearchServiceApplication `
    -Name 'Search Service Application' `
    -applicationpool $applicationPool `
    -databasename 'Search_Service_Application_DB' `
    -databaseserver 'SQLSE01' `
    -AdminSearchServiceInstance $searchInst

$ssa  = Get-SPEnterpriseSearchServiceApplication
New-SPEnterpriseSearchServiceApplicationProxy -Name 'Search Proxy' -SearchApplication $ssa
$ssap = Get-SPEnterpriseSearchServiceApplicationProxy
Add-SPServiceApplicationProxyGroupMember -member $ssap -identity ''

Si ce restore échoue, et la latence réseau ou SQL suffit à le faire échouer, la récupération documentée n'est pas de réessayer par-dessus : supprimer la base d'administration de Search à demi mise à niveau, restaurer de nouveau la copie de sauvegarde, la remettre en lecture-écriture, et relancer la commande.

Confirmez ensuite que tous les proxys ont bien atterri dans le groupe par défaut, car une service application qui fonctionne mais dont le proxy n'est pas dans le groupe par défaut se comporte exactement comme une qui manque.

powershell
$pg = Get-SPServiceApplicationProxyGroup -Identity ''
$pg.Proxies | Select-Object DisplayName, TypeName | Format-Table -AutoSize

Phase 5 : tester, et seulement ensuite monter

Ne montez jamais en premier. Test-SPContentDatabase ne change rien, et c'est la seule chose qui vous dit ce qui manque tant que c'est encore bon marché à corriger.

Deux paramètres méritent leur place. -ShowLocation dit une fonctionnalité manquante est utilisée, ce qui transforme un GUID en un site qui a un propriétaire. C'est lent, donc cela appartient à la répétition et non à la vraie exécution. Et -ExtendedCheck :

"Vérifie la présence de modes d'authentification incohérents pendant le processus de mise à niveau par database attach. Le mode choisi, claims ou classique, doit être le même dans les deux versions."

Celui-là compte plus qu'il n'y paraît, car le mode classique a été supprimé pour les web applications de contenu dans Subscription Edition. Une ferme encore en authentification classique l'apprend ici, ou l'apprend au milieu d'un mount.

powershell
# TEST THEN MOUNT. Driven from the inventory, one database at a time.
$dbs    = Import-Csv 'C:\Migration\inventory\contentdbs.csv'
$webApp = 'https://sharepoint.contoso.com'
$report = 'C:\Migration\reports'
New-Item -ItemType Directory -Path $report -Force | Out-Null

foreach ($db in $dbs) {

    Write-Host "`n=== $($db.Name) ===" -ForegroundColor Cyan

    # -ExtendedCheck catches a claims/classic mismatch, which Subscription
    # Edition cannot resolve later: classic mode is gone for content web apps.
    $issues = Test-SPContentDatabase -Name $db.Name -WebApplication $webApp -ExtendedCheck

    $issues | Export-Clixml "$report\$($db.Name).test.xml"
    $issues | Format-List | Out-File "$report\$($db.Name).test.txt" -Encoding UTF8

    # UpgradeBlocking is the property that separates "fix this now" from
    # "write this down". Read the file either way: a non-blocking missing
    # web part is still a broken page for whoever put it there.
    $blocking = $issues | Where-Object { $_.UpgradeBlocking }

    if ($blocking) {
        Write-Host "BLOCKED: $($blocking.Count) blocking issue(s). Not mounting." -ForegroundColor Red
        $blocking | Format-List Category, Message, Remedy
        continue
    }

    if ($issues) {
        Write-Host "$($issues.Count) non-blocking issue(s), logged. Mounting." -ForegroundColor Yellow
    }

    # Mount-SPContentDatabase, not Central Administration: attaching a database
    # through the Central Administration pages is not supported for upgrading.
    # Site collections upgrade automatically as part of this, which is the
    # default and the recommended behaviour.
    Mount-SPContentDatabase -Name $db.Name -WebApplication $webApp -Verbose

    Write-Host "MOUNTED: $($db.Name)" -ForegroundColor Green
}

Si une base de données contient des milliers de collections de sites et que la fenêtre du mount est serrée, -SkipSiteUpgrade reporte la mise à niveau des sites au premier accès. C'est un outil de calendrier, pas un raccourci : le travail a lieu quand même, simplement étalé et sous la charge d'utilisateurs réels.

powershell
Mount-SPContentDatabase -Name 'WSS_Content_Archive' -WebApplication $webApp -SkipSiteUpgrade

Et le modèle a changé. Il n'y a plus de modes de compatibilité :

"Il n'existe pas de notion de « modes de compatibilité de collection de sites » dans SharePoint Server Subscription Edition. Vous devez exécuter la dernière version à tout moment."

Phase 6 : ce qu'il faut vérifier avant de laisser entrer quiconque

powershell
# 1. Every site collection accounted for, against the inventory.
$before = Import-Csv 'C:\Migration\inventory\sites.csv'
$after  = Get-SPSite -Limit All | Select-Object -ExpandProperty Url
$missing = $before.Url | Where-Object { $_ -notin $after }
if ($missing) { $missing | ForEach-Object { Write-Warning "MISSING SITE: $_" } }
else { Write-Host "All $($before.Count) site collections present." -ForegroundColor Green }

# 2. Site collection upgrade status, per site. The logs from Mount-based
# upgrades live inside the Upgrade*.log files, not in separate SiteUpgrade
# files, which is where people go looking and find nothing.
Get-SPSite -Limit All | ForEach-Object {
    $info = Get-SPSiteUpgradeSessionInfo -Site $_.Url -ErrorAction SilentlyContinue
    [pscustomobject]@{
        Url       = $_.Url
        Status    = $info.Status
        Errors    = $info.ErrorCount
        Warnings  = $info.WarningCount
    }
} | Where-Object { $_.Errors -gt 0 -or $_.Status -ne 'Completed' } | Format-Table -AutoSize

# 3. The index is EMPTY. The topology in the new farm is new, so a full crawl
#    over the whole corpus is mandatory, and only once every content database
#    is mounted. Starting it earlier just means crawling twice.
$ssa = Get-SPEnterpriseSearchServiceApplication
Get-SPEnterpriseSearchCrawlContentSource -SearchApplication $ssa |
  ForEach-Object { $_.StartFullCrawl() }

# 4. Which feature release ring this farm should be on. Standard is the
#    default; Early gets new experiences sooner. Record the decision.
Get-SPFeatureReleasePreference

Ensuite, l'ancienne ferme. Laissez-la en lecture seule et en fonctionnement jusqu'à ce que la nouvelle ait passé une semaine de travail complète, car le rollback le plus rapide de tout ce projet est un changement de DNS vers une ferme qui marche encore.

Répétez d'abord, faites ensuite

Tous les chiffres du plan sont une supposition tant que la répétition ne les a pas produits. Restaurez une copie des bases de données de production sur la nouvelle ferme, exécutez toute la séquence, et notez trois choses : combien de temps a pris chaque mount, ce que Test-SPContentDatabase -ShowLocation a trouvé, et lesquelles des fonctionnalités manquantes personne n'a su expliquer.

Puis jetez cette ferme et recommencez, sur la vraie fenêtre. La seconde exécution est celle qui a des durées réalistes, une liste de solutions déjà complète et aucune surprise dans le rapport de test, parce qu'elles ont toutes été trouvées à la première.

Avant de commencer

  • Confirmez la direction : 2016 et 2019 vont tous deux directement vers Subscription Edition, et seuls 2013 et antérieurs ont besoin d'une escale intermédiaire
  • Vérifiez que chaque base de données est en 16.0.4351.1000 ou supérieure, car en dessous la mise à niveau est bloquée d'emblée
  • Prenez l'inventaire avant de toucher à quoi que ce soit, et gardez-le sous contrôle de version
  • N'utilisez pas le Farm Configuration Wizard pour les service applications dont vous comptez mettre à niveau les bases de données
  • Reproduisez exactement les anciennes URL dans les nouvelles web applications
  • Déployez les farm solutions avant de lancer Test-SPContentDatabase, sinon le rapport est illisible
  • Trouvez la passphrase du Secure Store de l'ancienne ferme avant d'en avoir besoin
  • Lancez Test-SPContentDatabase avec -ExtendedCheck, et lisez le rapport même quand rien ne bloque
  • Remettez les bases de données en lecture-écriture après la restauration, car une base en lecture seule ne peut pas être montée
  • Respécifiez toutes les liaisons en utilisant Set-SPWebApplication, sinon celles que vous omettez reviendront à leur valeur par défaut
  • Planifiez l'analyse complète, et planifiez-la après que la dernière base de contenu est montée
  • Gardez l'ancienne ferme en lecture seule et joignable pendant une semaine après la mise en service

Commentaires

Poursuivre la lecture

Migrations

SharePoint 2016, 2019, Subscription Edition et Online : ce qui change vraiment

2016 et 2019 s'arrêtent tous deux le 14 juillet 2026. Subscription Edition n'a pas de date de fin et ne s'achète pas une fois pour toutes. Online a des fonctionnalités que les autres n'auront jamais, et Subscription Edition en a deux qui sont habituellement listées comme impossibles. Une comparaison pratique, avec la licence qui tranche.

·22 min de lecture
Développement et automatisation

Développer pour SharePoint Server Subscription Edition : les pratiques qui tiennent

Subscription Edition est pris en charge jusqu'en 2035 au moins et son plafond SharePoint Framework n'a pas bougé depuis 2023. Cette combinaison, c'est tout le travail : une longue piste sur une base stable. Comment bien construire dessus, avec du code qui tourne sur la version que votre ferme accepte réellement.

·24 min de lecture
IA et agents

Un manifeste d'agent Copilot est une frontière de sécurité. Voici le vérificateur.

Toutes les propriétés de portée d'un manifeste d'agent Microsoft 365 Copilot sont facultatives et, dans six cas, en omettre une donne la portée la plus large au lieu de la plus étroite. Un validateur JSON Schema approuve ces manifestes, parce qu'aucun n'a quoi que ce soit d'invalide : il manque quelque chose de facultatif. Nous avons donc écrit la vérification qui les attrape. Elle trouve six problèmes dans un manifeste qui passe tous les autres tests.

·7 min de lecture