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.
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."

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.

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.
# 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.
# 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.
# 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."
# 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."
# 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.
-- 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;
-- 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.
# 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.
# --- 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.
# --- 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.
$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 où 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.
# 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.
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
# 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-SPContentDatabaseavec-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


