如何在PnP PowerShell 7中从CSV批量/并行上传文件到SharePoint
问题描述
我正在寻求一种使用PnP PowerShell批量上传文件到SharePoint的解决方案。目前我编写了如下代码,通过逐行读取CSV文件来上传文件,但上传速度较慢,一小时仅能上传3000个文件。我希望通过批处理实现一小时至少上传7000-8000个文件,以下是我的代码:
Get-ChildItem -Path $CSVPath -Filter '*.csv' | Foreach-Object { #Import CSV $CSVData = import-csv $_ # Built Url & Connect to PnP Connect-PnPOnline -Url $sharePointUrl $CSVData | Foreach-Object { $Row = $_ Add-PnPFile -Path $Row.SourcePath -Folder $InsertorUpdateAt -Values $MetadataValue } }
核心优化方案
1. 消除重复连接开销
原代码在每个CSV文件循环内重复调用Connect-PnPOnline,连接握手过程会消耗大量时间。将连接逻辑移到所有循环外部,仅建立一次连接。
2. 启用并行处理
单线程逐行上传是速度瓶颈核心,通过多线程并行处理可成倍提升效率。根据PowerShell版本选择方案:
- PowerShell 7+:使用
ForEach-Object -Parallel原生并行特性,性能更优 - PowerShell 5.x:使用
Start-Job实现多作业并行
3. 预加载所有CSV数据
提前读取所有CSV文件内容到内存,避免循环中重复执行文件IO操作,减少磁盘读取开销。
4. 关闭冗余功能
在Connect-PnPOnline中添加-NoTelemetry参数,禁用遥测数据上报,减少额外网络请求。
优化后代码示例
PowerShell 7+ 推荐版本
# 仅建立一次SharePoint连接 Connect-PnPOnline -Url $sharePointUrl -NoTelemetry # 一次性读取所有CSV文件数据到内存 $allUploadTasks = Get-ChildItem -Path $CSVPath -Filter '*.csv' | ForEach-Object { Import-Csv $_.FullName } # 并行上传文件,ThrottleLimit控制并发数(建议10-20,根据服务器负载调整) $allUploadTasks | ForEach-Object -Parallel { # 在并行线程中获取共享连接上下文 $context = Get-PnPContext $context.Load($context.Web) $context.ExecuteQuery() # 执行文件上传 Add-PnPFile -Path $_.SourcePath -Folder $using:InsertorUpdateAt -Values $using:MetadataValue -Connection $context } -ThrottleLimit 15
PowerShell 5.x 兼容版本
# 建立主连接(可选,作业内会独立建立连接) Connect-PnPOnline -Url $sharePointUrl -NoTelemetry # 预加载所有CSV上传任务 $allUploadTasks = Get-ChildItem -Path $CSVPath -Filter '*.csv' | ForEach-Object { Import-Csv $_.FullName } # 定义上传作业脚本块 $uploadJobScript = { param($sourcePath, $targetFolder, $metadata, $siteUrl) # 每个作业独立建立连接 Connect-PnPOnline -Url $siteUrl -NoTelemetry Add-PnPFile -Path $sourcePath -Folder $targetFolder -Values $metadata } # 控制并发作业数量,避免触发SharePoint限流 $maxConcurrentJobs = 15 $currentRunningJobs = 0 foreach ($task in $allUploadTasks) { # 等待有作业完成后再启动新作业 while ($currentRunningJobs -ge $maxConcurrentJobs) { $completedJobs = Get-Job -State Completed if ($completedJobs) { Receive-Job $completedJobs Remove-Job $completedJobs $currentRunningJobs -= $completedJobs.Count } Start-Sleep -Milliseconds 500 } # 启动新上传作业 Start-Job -ScriptBlock $uploadJobScript -ArgumentList $task.SourcePath, $InsertorUpdateAt, $MetadataValue, $sharePointUrl | Out-Null $currentRunningJobs++ } # 等待所有剩余作业完成 while ($currentRunningJobs -gt 0) { $completedJobs = Get-Job -State Completed if ($completedJobs) { Receive-Job $completedJobs Remove-Job $completedJobs $currentRunningJobs -= $completedJobs.Count } Start-Sleep -Milliseconds 500 }
注意事项
- 并发数需根据SharePoint服务器性能和带宽调整,过高可能触发请求限流(建议从10开始测试,逐步提升)
- 确保源文件路径在所有并行线程/作业中可访问(本地文件无问题,网络共享需确认权限)
- 上传大文件时,适当降低并发数,避免带宽饱和影响上传效率
内容的提问来源于stack exchange,提问作者Mukesh
相关产品推荐
相关产品推荐

