A SharePoint duplikált mappáinak egyesítése a PowerShell-lel
A blog egyik olvasója megkeresett, ha tudom, hogyan egyesíthetem az ismétlődő mappákat a SharePoint Online-ban. A felhasználók már dolgoztak a duplikált mappákban, így nem csak egyesíteni kellett a mappákat, hanem meg kell őriznünk az utoljára módosított fájlt is.
Minden duplikált fájl vagy mappa fájlnevében ugyanaz a minta, (1). Így nagyon egyszerűvé vált a fájlok és mappák megtalálása, valamint az eredeti hellyel való egyesítése.
Ha kíváncsi, mi történt; Egy felhasználó helyileg törölte a fájlokat anélkül, hogy először leállította volna a szinkronizálást. A törölt fájlok nagy száma miatt (több mint 750 000) megkérték a Microsoftot, hogy állítsa vissza őket, amit meg is tettek.
Csak egy kommunikációs hiba miatt a visszaállítási munka két részből állt, ami duplikált fájlokat eredményezett. A Microsoft nem tudott segíteni a tisztításban, ezért közbeléptem.
Ez azon helyzetek egyike, amikor egy harmadik féltől származó biztonsági mentési megoldás valóban életmentő lehet. Korábban írtam róla; Szüksége van-e biztonsági mentési megoldásra a Microsoft 365-höz. Mint látható ebben az esetben, a fájlok visszaállíthatók, de a biztonsági mentési megoldás sokkal egyszerűbbé tenné a visszaállítást.
Az ismétlődő elemek megkeresése
Az ismétlődő mappák és fájlok egyesítése néhány lépést vesz igénybe. A duplikált mappák nem csak a dokumentumtár gyökér szintjén találhatók, hanem egy almappa 3 szint mélységében is lehetnek. Tehát rekurzívan át kell dolgoznunk az összes mappán, és meg kell keresnünk azokat az elemeket, amelyek nevében (1) szerepel.
A szkriptet néhány lépésre bontottam, mindegyik saját funkcióra fordítva:
- Ismétlődő fájlok és mappák keresése
- A cél útvonal létrehozása (az eredeti hely)
- A mappa tartalmának áthelyezése
- Hasonlítsa össze a fájlok dátumait
- Egyetlen elem mozgatása
Csatlakozzon a SharePoint webhelyhez
Mielőtt bármit is tehetünk, csatlakoznunk kell a SharePoint webhelyhez. Ezt egyszerűen megtehetjük a PnPOnline-nal, én pedig a webes bejelentkezési kapcsolót használom, így itt használhatjuk a normál bejelentkezésünket az MFA-val.
A cikk végén megmutatom a teljes forgatókönyvet.
# SharePoint url
$sharepointUrl = 'https://lazyadmin.sharepoint.com/'
# Site
$site = 'sites/lab01'
# Library name
$libraryName = 'Duplicates'
# Login
$url = $sharepointUrl+ '/' + $site
Connect-PnPOnline -Url $url -UseWebLoginAz ismétlődő fájlok megkeresése
Mivel az almappákat is fel kell dolgoznunk, itt az a trükk, hogy rekurzívan menjünk végig a mappákon. Itt a Get-PnPFolderItem függvényt használjuk, de akkor rekurzív módon. A funkció Josh Einstein forgatókönyvén alapul, amelyet itt találhat meg.
# Recursively calls Get-PnpFolderItem for a given Document Library
# Based on: https://gist.github.com/josheinstein/3ace0c9f8e25d07583ceb57d13f71b2e
Function Get-PnpFolderItemRecursively($FolderSiteRelativeUrl) {
# Get all items
$items = @(Get-PnPFolderItem -FolderSiteRelativeUrl $FolderSiteRelativeUrl)
Foreach ($item in $items) {
# Strip the Site URL of the item path because Get-PnpFolderItem wants it
# to be relative to the site, not an absolute path.
$itemPath = $item.ServerRelativeUrl -replace "^$(([Uri]$item.Context.Url).AbsolutePath)/",''
# Check if the item is a folder
If ($item -is [Microsoft.SharePoint.Client.Folder])
{
# Check if the folder name contains (1) on the end
# If - if the folder name contains a (1) on the end, then it's a duplicate folder that we need to move or merge
# Else - if the folder doesn't contain (1), then we open the folder and search through the next level
if ($item.name -like "*(1)")
{
# Duplicate folder found
Write-Host " - Duplicatie folder found: " $itemPath -ForegroundColor Yellow
# Move the content of the folder to the original location
Move-FolderItemsRecursively($itemPath)
}
else
{
# Is doesn't contain (1), but it's a folder, search through the next level by recursing into this function.
Get-PnpFolderItemRecursively $itemPath
}
}
else
{
# Item is a file
# Check if items name contains a (1), if true, move the file
if ($item.name -like "*(1)")
{
$targetPath = Create-TargetPath -itemPath $itemPath -targetPath $item["FileRef"].trim("*(1)") -relativePath $relativePath
Write-Host $newTargetPath;
Move-CustomItem -SiteRelativeUrl $itemPath -targetPath $targetPath -item $item
}
# Else skip to next
}
}
}Tehát minden elemnél ellenőrizzük, hogy mappa-e. Ha ez egy mappa, akkor ellenőrizzük a mappa nevét, ha az (1) tartalmazza. Ha igen, akkor áthelyezzük a mappa tartalmát, ha nem, akkor „nyitjuk” a mappát, és végignézzük a tartalmat.
Ha nem mappa, hanem fájl, akkor ismét ellenőrizzük a nevet. Ha az (1) értéket tartalmazza, akkor áthelyezzük a fájlt, különben nem csinálunk semmit.
A cél útvonal létrehozása
Ha ismétlődő elemet találunk, létre kell hoznunk az eredeti elérési utat az elem elérési útjából. Azt is ellenőriznünk kell, hogy létezik-e az eredeti mappa, és ha nem, akkor létre kell hozni újra az eredeti mappát.
Function Create-TargetPath {
[CmdletBinding()]
param(
[parameter (Mandatory=$true)]
$itemPath,
[parameter (Mandatory=$true)]
$item,
[parameter (Mandatory=$false)]
$relativePath
)
process
{
# Build new path
$path = $itemPath.replace($item.name,'')
$targetPath = "/" + $site + "/" + $path + $item.name
if ($whatIf -ne $true)
{
# Check if target folder exists, create if necessary
Write-host ' - Check if target folder exists' $path.replace('(1)', '') -BackgroundColor DarkMagenta;
$result = Resolve-PnPFolder -SiteRelativePath $path.replace('(1)', '') -ErrorAction SilentlyContinue
}
else{
Write-host ' - Create target folder if it does not exists' $path.replace('(1)', '') -BackgroundColor DarkMagenta;
}
Write-Output $targetPath.replace('(1)', '')
}
}Amit az egyes függvényekben látni fog, az az, hogy a $whatIf változót használom. A szkript elején deklaráltam ezt a változót. Ez lehetővé teszi a szkript tesztelését anélkül, hogy ténylegesen áthelyeznék vagy létrehoznék fájlokat vagy mappákat.
A legtöbb PnP funkció támogatja a WhatIf kapcsolót, de például a Resolve-PnPFolder nem támogatja azt. Így egyszerűen tesztelhetem úgy, hogy felírom a konzolra, hogy mit csinálna a szkript.
A create-targetPath funkció újra létrehozza az elérési utat, ellenőrzi, hogy létezik-e a mappa, és ha nem, akkor újra létrehozza a Resolve-PnPfolder funkcióval.
Mappa és almappák áthelyezése a PowerShell segítségével
Ha ismétlődő mappát találtunk, a mappát és az összes tartalmat (beleértve az almappákat is) az eredeti helyére szeretnénk helyezni. Minden almappához létre kell hoznunk egy cél elérési utat is.
Function Move-FolderItemsRecursively($FolderSiteRelativeUrl) {
# Get all items in this sub folder
$items = @(Get-PnPFolderItem -FolderSiteRelativeUrl $FolderSiteRelativeUrl)
foreach ($item in $items) {
# Strip the Site URL off the item path, because Get-PnpFolderItem wants it
# to be relative to the site, not an absolute path.
$itemPath = $item.ServerRelativeUrl -replace "^$(([Uri]$item.Context.Url).AbsolutePath)/",''
# If this is a directory, recurse into this function.
# Otherwise, build target path and move file
if ($item -is [Microsoft.SharePoint.Client.Folder])
{
Move-FolderItemsRecursively $itemPath
}
else
{
$targetPath = Create-TargetPath -itemPath $itemPath -item $item
Move-CustomItem -SiteRelativeUrl $itemPath -targetPath $targetPath -item $item
}
}
}A fájlok dátumának összehasonlítása a SharePoint Online-ban és a fájlok áthelyezése
Tehát most elérkeztünk ahhoz a részhez, amelyről szó van, a tényleges fájlok áthelyezésére. Mielőtt áthelyezhetnénk a fájlt, ellenőriznünk kell, hogy a fájl létezik-e az eredeti helyen. Ha igen, akkor össze kell hasonlítanunk a fájldátumokat, ebben az esetben az utoljára módosított fájlt szeretnénk megtartani.
# Move file to original folder
Function Move-CustomItem {
[CmdletBinding()]
param(
[parameter (Mandatory=$true)]
$siteRelativeUrl,
[parameter (Mandatory=$true)]
$targetPath,
[parameter (Mandatory=$true)]
$item
)
process
{
$moveFile = Compare-FileDates -sourceFilePath $siteRelativeUrl -targetFilePath $targetPath;
$global:moveLimitCounter++
if ($moveFile -eq $true)
{
if ($moveLimitCounter -eq $moveLimit)
{
Write-Warning 'Move limit reached'
exit;
}
if ($whatIf -ne $true)
{
# Move the file
Write-host ' - Move item to' $targetPath -BackgroundColor DarkYellow;
Move-PnPFile -SiteRelativeUrl $siteRelativeUrl -TargetUrl $targetPath -OverwriteIfAlreadyExists -Force:$force
Write-Host "`r`n"
}
else
{
Write-host ' - Move file from' $siteRelativeUrl -BackgroundColor DarkCyan
Write-host ' to' $targetPath -BackgroundColor DarkCyan
Write-Host "`r`n"
}
}
}
}Itt hozzáadtam egy számlálót, amely számolja az áthelyezett fájlok számát. Amikor egy ilyen szkriptet tesztel, először csak néhány fájlt szeretne áthelyezni, majd ellenőrizni az eredményeket, mielőtt folytatná.
# Check if the file already exists in the target location
# If the file exists, we need to compare the dates to keep the latest files
Function Compare-FileDates ()
{
[CmdletBinding()]
param(
[parameter (Mandatory=$true)]
$targetFilePath,
[parameter (Mandatory=$true)]
$sourceFilePath
)
$targetFileExists = Get-PnPFile -Url $targetFilePath -ErrorAction SilentlyContinue
If($targetFileExists)
{
$sourceFile = Get-PnPFile -Url $sourceFilePath -AsListItem
$targetFile = Get-PnPFile -Url $targetFilePath -AsListItem
$sourceFileDate = Get-date $sourceFile['Modified']
$targetFileDate = Get-date $targetFile['Modified']
write-host ' - Comparing files dates: duplicate file: '$sourceFileDate 'original file: '$targetFileDate
# Check if the source file is newer then the target file
If ($sourceFile['Modified'] -gt $targetFile['Modified'])
{
write-host ' - Duplicate file is newer, move the file' -BackgroundColor DarkGreen
write-output $true
}
else
{
# Remove file
if ($whatIf -ne $true)
{
Write-host ' - Target file is newer. Removing duplicate file' -BackgroundColor DarkRed
Write-Host "`r`n"
Remove-PnPFile -SiteRelativeUrl $sourceFilePath -Recycle -Force:$force
}
else
{
Write-Host 'Remove file' $sourceFilePath -ForegroundColor Red
Write-Host "`r`n"
}
write-output $false
}
}
else
{
# Target file doesn't exists
Write-host ' - Target file does not exist' -BackgroundColor DarkGreen
Write-Output $true
}
}Tehát összehasonlítjuk a dátumokat, és ha az eredeti fájl újabb, akkor eltávolítjuk a duplikált fájlt. A fájl eltávolítása funkcióban hozzáadtam a -Recycle kapcsolót, így a fájl a lomtárba kerül. Eltávolíthatja ezt a kapcsolót, ha véglegesen törölni szeretné a fájlokat.
Becsomagolás
Jó tudni, hogy előfordulhat, hogy néhány üres mappa marad a könyvtárában. Külön szkriptet használtam, amelyet futtathat az üres mappák megtisztításához. A teljes szkriptet itt találod a GitHubon.
Mindig tesztelje az ilyen típusú szkripteket egy teszt SharePoint webhelyen néhány tesztfájllal. Győződjön meg róla, hogy a whatif értéket $true értékre, a force változót pedig $false értékre állítja az induláskor.
Ha bármilyen kérdése van, csak írjon megjegyzést alább.