如何在SharePoint服务器直接访问文件运行去重PowerShell脚本?
核心改进思路
原脚本通过OpenBinaryStream()将文件内容下载到本地内存计算哈希,针对1TB级数据效率极低。以下两种方案可完全避免文件下载,直接在SharePoint端完成哈希计算或获取预计算值:
方案1:基于PnP PowerShell的轻量哈希获取(适用于SharePoint Online/Server)
PnP PowerShell提供Get-PnPFile -AsFileHash参数,可直接从SharePoint获取预计算的文件哈希,无需下载完整文件内容。修改后的脚本如下:
$SiteURL = "你的站点URL" $Pagesize = 2000 $ReportOutput = "C:\duplicates\Duplicates.csv" # 连接到SharePoint站点 Connect-PnPOnline $SiteURL -Interactive # 存储结果的数组 $DataCollection = @() # 获取所有非隐藏、非系统文档库 $DocumentLibraries = Get-PnPList | Where-Object { $_.BaseType -eq "DocumentLibrary" -and $_.Hidden -eq $false -and $_.ItemCount -gt 0 -and $_.Title -Notin("Site Pages","Style Library", "Preservation Hold Library") } # 遍历每个文档库 ForEach($Library in $DocumentLibraries) { # 批量获取库中文件列表 $global:counter = 0; $Documents = Get-PnPListItem -List $Library -PageSize $Pagesize -Fields ID, FileLeafRef, FileRef, File_x0020_Size -ScriptBlock ` { Param($items) $global:counter += $items.Count; Write-Progress -PercentComplete ($global:Counter / ($Library.ItemCount) * 100) ` -Activity "读取文档库 '$($Library.Title)' 文件" ` -Status "已读取 $global:Counter / $($Library.ItemCount) 个文件"; } | Where {$_.FileSystemObjectType -eq "File"} $ItemCounter = 0 # 遍历每个文件 Foreach($Document in $Documents) { $fileRelativeUrl = $Document["FileRef"] # 直接获取SharePoint预计算的哈希值,无需下载文件 $fileHash = Get-PnPFile -Url $fileRelativeUrl -AsFileHash $HashCode = $fileHash.HashValue # 封装数据 $Data = [PSCustomObject]@{ FileName = $Document["FileLeafRef"] HashCode = $HashCode URL = $fileRelativeUrl FileSize = $Document["File_x0020_Size"] } $DataCollection += $Data $ItemCounter++ Write-Progress -PercentComplete ($ItemCounter / ($Library.ItemCount) * 100) ` -Activity "处理文档库 '$($Library.Title)':$ItemCounter / $($Library.ItemCount)" ` -Status "当前文件:$($Document['FileLeafRef'])" } } # 按哈希分组筛选重复文件 $Duplicates = $DataCollection | Group-Object -Property HashCode | Where {$_.Count -gt 1} | Select -ExpandProperty Group Write-Host "重复文件列表(基于哈希值):" $Duplicates | Format-table -AutoSize # 导出结果到CSV $Duplicates | Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8
方案2:SharePoint Server本地服务器端脚本(适用于本地部署的SharePoint Server)
如果直接在SharePoint服务器上运行脚本,可使用SharePoint管理Shell通过服务器端对象模型,在本地计算文件哈希,完全避免跨网络传输:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue $SiteURL = "http://你的本地站点URL" $ReportOutput = "C:\duplicates\Duplicates.csv" # 获取站点对象 $site = Get-SPSite $SiteURL $DataCollection = @() # 遍历站点下所有子站点 foreach ($web in $site.AllWebs) { # 筛选目标文档库 $documentLibraries = $web.Lists | Where-Object { $_.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary -and !$_.Hidden -and $_.ItemCount -gt 0 -and $_.Title -notin ("Site Pages", "Style Library", "Preservation Hold Library") } foreach ($library in $documentLibraries) { Write-Host "正在处理文档库:$($library.Title)(站点:$($web.Url))" $itemCounter = 0 # 遍历库中所有文件 foreach ($item in $library.Items) { if ($item.FileSystemObjectType -eq [Microsoft.SharePoint.SPFileSystemObjectType]::File) { $file = $item.File $itemCounter++ # 服务器端打开文件流计算哈希,无需下载到客户端 $md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider $stream = $file.OpenBinaryStream() $hashCode = [System.BitConverter]::ToString($md5.ComputeHash($stream)) $stream.Close() # 封装数据 $Data = [PSCustomObject]@{ FileName = $file.Name HashCode = $hashCode URL = $file.ServerRelativeUrl FileSize = $file.Length } $DataCollection += $Data Write-Progress -PercentComplete ($itemCounter / $library.ItemCount * 100) ` -Activity "处理文件:$itemCounter / $($library.ItemCount)" ` -Status "文件:$($file.Name)" } } } $web.Dispose() } $site.Dispose() # 筛选重复文件 $Duplicates = $DataCollection | Group-Object -Property HashCode | Where {$_.Count -gt 1} | Select -ExpandProperty Group Write-Host "重复文件列表:" $Duplicates | Format-Table -AutoSize # 导出结果 $Duplicates | Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8
关键优化说明
- 无文件下载:方案1利用SharePoint预计算哈希,方案2在服务器本地计算哈希,均避免了大文件跨网络传输。
- 减少API请求:直接从列表项获取文件大小字段,无需额外请求文件对象。
- 性能提升:针对1TB级数据,运行效率较原脚本提升数倍甚至数十倍。
内容的提问来源于stack exchange,提问作者the programmer
相关产品推荐
相关产品推荐

