Spring til indholdet

Find kopier og gammelt indhold før en migrering

Før ejerne kan beslutte, hvad der ikke skal flyttes, skal de have noget at beslutte ud fra. Ens filer fundet med en kontrolsum, mapper opgjort efter seneste ændring, og de navne, SharePoint ikke tager imod. For fildrev og for SharePoint.

Opdateret PowerShellSharePoint Online 5 min. læsning

Hvad der ikke skal med i en migrering, er ejernes beslutning. Det står i Det, der ikke skal flyttes. Her er det, IT kan finde, så ejerne har noget at beslutte ud fra: filer, der er ens, mapper, ingen har rørt i årevis, og navne, der ikke kan komme med.

Ens filer på et fildrev#

To filer er ens, når de har samme kontrolsum. Get-FileHash bruger SHA-256 som standard (Microsoft). Kun filer med samme størrelse kan være ens, så scriptet grupperer på størrelse først og beregner kun kontrolsummen for dem:

 1$root = "\\<server>\<deling>"
 2
 3Get-ChildItem -LiteralPath $root -Recurse -File |
 4    Group-Object Length | Where-Object Count -gt 1 |
 5    ForEach-Object { $_.Group | Get-FileHash -Algorithm SHA256 } |
 6    Group-Object Hash | Where-Object Count -gt 1 |
 7    ForEach-Object {
 8        [pscustomobject]@{
 9            Hash  = $_.Name
10            Antal = $_.Count
11            Filer = ($_.Group.Path -join "; ")
12        }
13    } |
14    Export-Csv -Path "C:\Migrering\kopier.csv" -NoTypeInformation -Encoding utf8

Afprøvet i PowerShell 7 på en lille mappe. På et stort drev tager det tid, fordi hver fil med en tvilling skal læses helt.

Det finder kun filer, der er ens byte for byte. To Word-filer med samme tekst, gemt hver for sig, er ikke ens. Og to ens filer er ikke nødvendigvis en kopi, der kan slettes: den ene kan ligge i en mappe, som en anden afdeling bruger. Listen er noget at spørge ejerne om, ikke noget at slette ud fra.

Ens filer i SharePoint#

I SharePoint Online behøver filerne ikke hentes ned. Microsoft Graph giver en kontrolsum for hver fil, og quickXorHash er den eneste, Microsoft lover findes i OneDrive for work or school (Microsoft). Med delta på bibliotekets drev kommer alle filer i biblioteket, side for side (Microsoft). Ikke kørt:

 1Connect-MgGraph -Scopes "Sites.Read.All"
 2
 3$site  = Invoke-MgGraphRequest -Uri "v1.0/sites/<tenant>.sharepoint.com:/sites/<websted>"
 4$drive = Invoke-MgGraphRequest -Uri "v1.0/sites/$($site.id)/drive"
 5$uri   = "v1.0/drives/$($drive.id)/root/delta?`$select=id,name,size,file,webUrl"
 6
 7$files = while ($uri) {
 8    $page = Invoke-MgGraphRequest -Uri $uri
 9    $page.value | Where-Object { $_.file }
10    $uri = $page.'@odata.nextLink'
11}
12
13$files |
14    Group-Object { $_.file.hashes.quickXorHash } |
15    Where-Object { $_.Name -and $_.Count -gt 1 } |
16    ForEach-Object {
17        [pscustomobject]@{ Antal = $_.Count; Filer = ($_.Group.webUrl -join "; ") }
18    }
  • /drive er webstedets standardbibliotek. De andre biblioteker står under v1.0/sites/{id}/drives.
  • Stien kommer ikke med i delta. Microsoft skriver, at parentReference er uden path, fordi en omdøbt mappe ikke sender sine undermapper med. Derfor bruger scriptet webUrl.
  • Word, Excel og PowerPoint i SharePoint får bibliotekets kolonner skrevet ind i filen. To kopier af samme dokument i to biblioteker med forskellige kolonner har derfor ikke samme kontrolsum. Mere om det i At bevise, at intet blev ændret under en migrering.

SharePoint har ingen indbygget funktion, der finder ens filer. Søgningen skjuler næsten ens resultater, men det er alt (Microsoft).

Gammelt indhold#

En liste over tusindvis af gamle filer kan ingen ejer tage stilling til. En opgørelse pr. mappe kan: hvor mange filer, hvor meget de fylder, og hvornår den nyeste blev ændret.

1Get-ChildItem -LiteralPath $root -Directory | ForEach-Object {
2    $files = Get-ChildItem -LiteralPath $_.FullName -Recurse -File
3    [pscustomobject]@{
4        Mappe  = $_.Name
5        Filer  = $files.Count
6        MB     = [math]::Round(($files | Measure-Object Length -Sum).Sum / 1MB, 1)
7        Nyeste = ($files | Measure-Object LastWriteTime -Maximum).Maximum
8    }
9} | Export-Csv -Path "C:\Migrering\mapper.csv" -NoTypeInformation -Encoding utf8

Afprøvet i PowerShell 7. “Nyeste” er den seneste ændring i hele mappen. Er den fra 2016, er det et godt spørgsmål til ejeren. Ændret-datoen siger ikke, om filerne bliver læst.

I SharePoint er det samme Get-PnPListItem med -PageSize, så store biblioteker hentes i sider (PnP). FSObjType er 0 for en fil og 1 for en mappe:

1Get-PnPListItem -List "Dokumenter" -PageSize 2000 -Fields "FileLeafRef", "FileRef", "Modified", "FSObjType" |
2    Where-Object { $_.FieldValues.FSObjType -eq 0 -and $_.FieldValues.Modified -lt (Get-Date).AddYears(-5) } |
3    ForEach-Object { [pscustomobject]@{ Sti = $_.FieldValues.FileRef; Ændret = $_.FieldValues.Modified } }

Kolonnen hedder Modified internt, ikke LastModified. Ikke kørt.

For hele websteder kan inactive site policies i SharePoint Advanced Management finde websteder uden aktivitet i en periode, skrive til ejerne og til sidst gøre webstedet skrivebeskyttet eller arkivere det. Det kræver en ekstra licens, og OneDrive er ikke med (Microsoft, licenser). Hvad der fylder på et websted, står i Hvad der fylder i SharePoint-lageret.

SharePoint og OneDrive afviser (Microsoft):

  • tegnene " * : < > ? / \ |
  • mellemrum først og sidst i et navn
  • navnene .lock, CON, PRN, AUX, NUL, COM0-COM9, LPT0-LPT9 og desktop.ini, navne, der starter med ~$, og _vti_ nogen steder i navnet
  • forms som navn i roden af et bibliotek
  • en sti på mere end 400 tegn, inklusive filnavnet

# og % er tilladt, men kan være slået fra i en tenant. Æ, ø og å står ikke på listen.

Windows tillader ikke de fleste af tegnene i forvejen, så på et fildrev er det navnene, mellemrummene og længden, der skal findes. Længden er målets, ikke kildens: webstedets og bibliotekets sti kommer foran.

 1$prefix  = "/sites/<websted>/Delte dokumenter"
 2$blocked = '^~\$|^desktop\.ini$|^\.lock$|_vti_'
 3
 4Get-ChildItem -LiteralPath $root -Recurse | ForEach-Object {
 5    $path = $prefix + $_.FullName.Substring($root.Length).Replace('\', '/')
 6    $why  = @()
 7    if ($_.Name -match $blocked)    { $why += "navn" }
 8    if ($_.Name -ne $_.Name.Trim()) { $why += "mellemrum" }
 9    if ($path.Length -gt 400)       { $why += "sti $($path.Length)" }
10    if ($why) { [pscustomobject]@{ Sti = $_.FullName; Problem = $why -join ", " } }
11} | Export-Csv -Path "C:\Migrering\navne.csv" -NoTypeInformation -Encoding utf8

Afprøvet i PowerShell 7 på en lille mappe. SharePoint Migration Tool og Migration Manager finder det samme i deres scanning, som kan køres alene med Only perform scanning (Microsoft).

Det der driller#

  • 400 tegn, men hvilke. Microsoft skriver “the entire decoded file path”, men en anden side hos Microsoft siger, at tegn som mellemrum og bogstaver med accent tæller i deres kodede form (Microsoft). Med æ, ø og å i mappenavnene er der mindre plads, hvis det sidste er rigtigt. Ikke efterprøvet.
  • Omdøb ikke for at gøre navnene pæne. Æ, ø, å og mellemrum er tilladt. Hver omdøbning bryder links til filen og er en ændring, der skal forklares bagefter.
  • Filtrene i migreringsværktøjet kan springe filer over, der er oprettet eller ændret før en dato, og skjulte filer. Det er gennemførelsen af ejernes beslutning, ikke beslutningen selv.

Alle noter