SharePoint 2016 und 2019 auf Subscription Edition migrieren: die Skripte
SharePoint 2016 geht direkt auf Subscription Edition. Es gibt keinen Zwischenschritt über 2019, die Methode ist Database Attach und sonst keine, und die Reihenfolge der Service Applications ist keine Vorliebe. Die ganze Abfolge in PowerShell, von der Bestandsaufnahme vor dem ersten Handgriff bis zum Crawl am Ende.
Der Support für SharePoint Server 2016 und 2019 endet am 14. Juli 2026, und das einzige unterstützte On-Premises-Ziel ist Subscription Edition. Dieser Artikel ist die Abfolge, in PowerShell, mit den Stellen, die eine Migration blockieren, dort markiert, wo sie tatsächlich zubeißen.
Eines noch vor dem Code, denn es verändert Plan und Budget.
SharePoint 2016 geht direkt auf Subscription Edition
Die teuerste Annahme in diesem Projekt ist, man müsse zuerst über 2019 gehen. Muss man nicht.
"SharePoint Server Subscription Edition unterstützt sowohl N - 1 als auch N - 2 Versionsupgrades. Sie können direkt von den folgenden SharePoint-Produkten aus aktualisieren, mit dem üblichen Database-Attach-Verfahren: SharePoint Server 2019 (einschließlich Project Server 2019), SharePoint Server 2016 (einschließlich Project Server 2016)."
Ein Schritt, von beiden aus. Der doppelte Schritt ist nur unterhalb von 2016 vorgeschrieben:
"Ein direktes Upgrade per Database Attach von SharePoint-Versionen vor SharePoint Server 2016 wird nicht unterstützt. SharePoint 2013, SharePoint 2010 und so weiter müssen zuerst per Database Attach auf SharePoint Server 2016 oder SharePoint Server 2019 aktualisiert werden, bevor auf SharePoint Server Subscription Edition aktualisiert wird."

Und darunter liegt ein Boden:
"Alle Datenbanken müssen auf Version 16.0.4351.1000 oder höher aktualisiert sein, sonst wird das Upgrade auf SharePoint Server Subscription Edition blockiert."
Diese Nummer ist der RTM-Build von SharePoint Server 2016. Eine Datenbank, die 2016 entstanden ist, liegt per Definition darüber. Abgewiesen wird die, die aus 2013 kam, an eine 2016er-Farm angehängt wurde und die Reise nie wirklich beendet hat.
Die Methode bestimmt den Plan
Ein In-Place-Upgrade gibt es nicht. Der einzige unterstützte Weg ist Database Attach, das heißt, Sie bauen eine zweite Farm und verschieben Inhalte dorthin. Die Konfiguration wandert nicht mit: Webanwendungen, Service Applications, Richtlinien und Einstellungen werden in der neuen Farm von Hand nachgebaut. Das ist keine Einschränkung, die man umgeht, das ist die Form des Projekts.

Alles Folgende setzt die SharePoint Management Shell als erhöhter Administrator voraus, mit einem Konto, das db_owner auf jeder zu aktualisierenden Datenbank hat, securityadmin auf der SQL-Instanz, Mitgliedschaft in der lokalen Administratorengruppe und die über Add-SPShellAdmin erteilten Rechte.
Keines der Skripte unten wurde gegen eine Farm ausgeführt. Wir haben keine. Jedes Cmdlet und jeder Parameter stammt aus Microsofts Dokumentation, aber die Abfolge als Ganzes ist nicht gelaufen: behandeln Sie sie als Plan zum Proben, nicht als Skript zum Einfügen in die Produktion. Der Abschnitt zur Generalprobe am Ende ist kein optionaler Rat.
Phase 0: die Bestandsaufnahme, vor dem ersten Handgriff
Die neue Farm muss für alles geradestehen können, was die alte hatte. Nehmen Sie die Bestandsaufnahme zuerst, legen Sie sie in die Versionsverwaltung, und vergleichen Sie am Ende dagegen. Das läuft auf der alten Farm.
# 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
Zwei dieser Dateien verdienen ihren Platz sofort. solutions.csv wird zu Phase 2, und webapps.csv wird zu Phase 1, denn die URLs in der neuen Farm müssen zeichengenau zu den alten passen.
Phase 1: die Farm, die es aufnimmt
Bauen Sie die Subscription-Edition-Farm und legen Sie dann die Webanwendungen neu an. Eine Entscheidung, die bewusst zu treffen ist: wenn Sie die Datenbanken der Service Applications aktualisieren wollen, benutzen Sie dafür nicht den Farm Configuration Wizard. Der Assistent legt sie leer an, und eine leere Managed-Metadata-Service-Application lässt sich später nicht mehr auf Ihre alte Datenbank richten.
Zuerst die Zertifikate, denn Subscription Edition verwaltet sie in der Farm, und eine Webanwendung kann schon bei der Erstellung eines bekommen.
# 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
Dann die Webanwendungen, passend zur Bestandsaufnahme.
# 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.
Die Platzhalter-Datenbank ist Absicht: die Webanwendung braucht eine, um zu existieren, und die echten Inhaltsdatenbanken kommen in Phase 4. Löschen Sie den Platzhalter danach, sobald die echten gemountet sind.
Eine Falle, die einen Ausfall kostet. Wenn Sie später Bindungen mit Set-SPWebApplication ändern, geben Sie alle erneut an:
"Alle IIS-Bindungseinstellungen sollten erneut angegeben werden, wenn die Bindung einer IIS-Website über das Cmdlet
Set-SPWebApplicationgeändert wird. Dazu gehören die URL, die Secure-Sockets-Layer-Einstellung, die Portnummer, der Hostheader und das Zertifikat. Wird eine Bindungseinstellung nicht erneut angegeben, fällt sie auf ihren Standardwert zurück."
# 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: die Anpassungen kommen vor dem Inhalt
Das ist der Reihenfolgefehler, der die längste und nutzloseste Fehlersuche des Projekts erzeugt. Test-SPContentDatabase meldet jedes Feature, jede Vorlage und jede Assembly, die der Inhalt referenziert und nicht findet. Lassen Sie es laufen, bevor die Lösungen bereitgestellt sind, und Sie bekommen einen Bericht mit Hunderten Einträgen, die alle dasselbe Problem sind.
Microsoft nennt es als die häufige Ursache:
"Eine häufige Ursache für Fehler beim Upgrade ist, dass der Umgebung angepasste Features, Lösungen oder andere Elemente fehlen."
# 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
Was auf der Fehlliste stehen bleibt, ist eine Entscheidung, keine Warnung. Entweder das Paket wird gefunden und neu gebaut, oder die davon abhängigen Websites werden erfasst und vor der Migration behandelt, nicht währenddessen.
Phase 3: einfrieren, kopieren, auftauen
Die alte Farm geht auf schreibgeschützt statt offline, damit weitergelesen werden kann, während die Kopie läuft. Das ist T-SQL, auf der Quellinstanz.
-- 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;
Dieselben drei Anweisungen gelten für die Datenbanken der Service Applications, mit einer Ausnahme, die in der nächsten Phase behandelt wird: die Search-Administrationsdatenbank wird später kopiert, und erst nachdem Search angehalten wurde.
Phase 4: die Service Applications, in der Reihenfolge, die keine Vorliebe ist
Fünf Service-Application-Datenbanken lassen sich aktualisieren: Business Data Connectivity, Managed Metadata, Secure Store, User Profile und Search. Alles andere wird von Hand neu konfiguriert, und zwei werden ausdrücklich abgelehnt:
"Word Automation Services und Machine Translation Services können nicht aktualisiert werden. Es muss eine neue Dienstinstanz erstellt werden."
Die Reihenfolge ergibt sich aus den Abhängigkeiten. Managed Metadata und User Profile kommen beide vor Search, und beide vor jeder 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 kommt zuletzt, und mittendrin hat es einen Schritt, der auf der alten Farm läuft.
# --- 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 ''
Wenn dieses Restore scheitert, und Netz- oder SQL-Latenz reicht dafür aus, ist der dokumentierte Weg zurück nicht, es darüber erneut zu versuchen: die halb aktualisierte Search-Administrationsdatenbank löschen, die Sicherungskopie erneut einspielen, sie auf lesen und schreiben setzen und den Befehl noch einmal ausführen.
Prüfen Sie danach, dass alle Proxys in der Standardgruppe gelandet sind, denn eine Service Application, die läuft, deren Proxy aber nicht in der Standardgruppe steht, verhält sich genau wie eine fehlende.
$pg = Get-SPServiceApplicationProxyGroup -Identity ''
$pg.Proxies | Select-Object DisplayName, TypeName | Format-Table -AutoSize
Phase 5: testen, und erst dann mounten
Mounten Sie nie zuerst. Test-SPContentDatabase ändert nichts und ist das Einzige, was Ihnen sagt, was fehlt, solange es noch billig zu beheben ist.
Zwei Parameter verdienen ihren Platz. -ShowLocation sagt, wo ein fehlendes Feature verwendet wird, was aus einer GUID eine Website mit einem Besitzer macht. Es ist langsam, gehört also in die Generalprobe und nicht in den echten Lauf. Und -ExtendedCheck:
"Prüft während des Database-Attach-Upgrades auf inkonsistente Authentifizierungsmodi. Der gewählte Modus, Claims oder klassisch, muss in beiden Versionen derselbe sein."
Der wiegt schwerer, als er klingt, denn der klassische Modus wurde für Inhaltswebanwendungen in Subscription Edition entfernt. Eine Farm, die noch mit klassischer Authentifizierung läuft, erfährt es hier, oder sie erfährt es mitten in einem 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
}
Wenn eine Datenbank Tausende Websitesammlungen hält und das Mount-Fenster eng ist, verschiebt -SkipSiteUpgrade das Website-Upgrade auf den ersten Aufruf. Das ist ein Terminwerkzeug, keine Abkürzung: die Arbeit fällt trotzdem an, nur verteilt und unter der Last echter Benutzer.
Mount-SPContentDatabase -Name 'WSS_Content_Archive' -WebApplication $webApp -SkipSiteUpgrade
Und das Modell hat sich geändert. Kompatibilitätsmodi gibt es nicht mehr:
"Das Konzept der 'Kompatibilitätsmodi für Websitesammlungen' gibt es in SharePoint Server Subscription Edition nicht. Sie müssen jederzeit die neueste Version ausführen."
Phase 6: was zu prüfen ist, bevor jemand hineindarf
# 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
Danach die alte Farm. Lassen Sie sie schreibgeschützt und laufend, bis die neue eine volle Arbeitswoche hinter sich hat, denn das schnellste Rollback in diesem ganzen Projekt ist eine DNS-Änderung zurück auf eine Farm, die noch funktioniert.
Erst proben, dann machen
Jede Zahl im Plan ist eine Vermutung, bis die Generalprobe sie liefert. Spielen Sie eine Kopie der Produktionsdatenbanken auf der neuen Farm ein, lassen Sie die ganze Abfolge laufen, und schreiben Sie drei Dinge auf: wie lange jeder Mount gedauert hat, was Test-SPContentDatabase -ShowLocation gefunden hat, und welche der fehlenden Features niemand erklären konnte.
Dann werfen Sie diese Farm weg und machen es im echten Fenster noch einmal. Der zweite Lauf ist der mit realistischen Zeiten, einer bereits vollständigen Lösungsliste und keinen Überraschungen im Testbericht, weil sie alle beim ersten Mal gefunden wurden.
Bevor Sie anfangen
- Klären Sie die Richtung: 2016 und 2019 gehen beide direkt auf Subscription Edition, und nur 2013 und älter brauchen einen Zwischenschritt
- Prüfen Sie, dass jede Datenbank auf 16.0.4351.1000 oder höher steht, denn darunter wird das Upgrade rundweg blockiert
- Nehmen Sie die Bestandsaufnahme, bevor Sie irgendetwas anfassen, und legen Sie sie in die Versionsverwaltung
- Benutzen Sie den Farm Configuration Wizard nicht für die Service Applications, deren Datenbanken Sie aktualisieren wollen
- Bilden Sie die alten URLs in den neuen Webanwendungen exakt nach
- Stellen Sie die Farm Solutions bereit, bevor Sie
Test-SPContentDatabaselaufen lassen, sonst ist der Bericht unlesbar - Besorgen Sie die Secure-Store-Passphrase der alten Farm, bevor Sie sie brauchen
- Lassen Sie
Test-SPContentDatabasemit-ExtendedChecklaufen und lesen Sie den Bericht auch dann, wenn nichts blockiert - Setzen Sie die Datenbanken nach dem Restore zurück auf lesen und schreiben, denn eine schreibgeschützte Datenbank lässt sich nicht mounten
- Geben Sie bei
Set-SPWebApplicationjede Bindung erneut an, sonst fallen die ausgelassenen zurück - Planen Sie den vollständigen Crawl, und planen Sie ihn für die Zeit nach der letzten gemounteten Inhaltsdatenbank
- Halten Sie die alte Farm nach dem Umschalten eine Woche lang schreibgeschützt und erreichbar


