使用PowerShell操作SharePoint大列表报错:内存不足(0x8007000e)
问题根源
你的代码有两个致命问题导致内存溢出:
- 一次性加载全量数据:
$SiteWebObjectList.Items会直接把40万条列表项全部加载到内存中,哪怕64GB内存也扛不住——SharePoint的SPListItem对象包含大量元数据,内存占用远超想象。 - 分批逻辑无效:你虽然用
SPQuery做了分批获取,但foreach循环遍历的是全量的$SiteWebObjectListItems,完全没用到分批返回的$listItems,等于白做了分批处理。
修正后的代码
$siteUrl = 'http://sharepointserver' $listName = "List" $batchSize = 500 # 建议批次大小:500-2000,根据服务器性能调整 # 获取Web和列表对象 $siteWeb = Get-SPWeb $siteUrl $targetList = $siteWeb.Lists[$listName] # 禁用事件接收器和版本控制(提升处理速度,可选) $originalEventState = $targetList.EventReceivers.Enabled $targetList.EventReceivers.Enabled = $false $originalVersionState = $targetList.EnableVersioning $targetList.EnableVersioning = $false $targetList.Update() # 初始化SPQuery,设置批次大小 $spQuery = New-Object Microsoft.SharePoint.SPQuery $spQuery.RowLimit = $batchSize # 只加载需要修改的字段,减少内存占用(比如只加载Title和ID) $spQuery.ViewFields = "<FieldRef Name='ID'/><FieldRef Name='Title'/>" $spQuery.ViewFieldsOnly = $true do { # 获取当前批次的列表项 $batchItems = $targetList.GetItems($spQuery) $spQuery.ListItemCollectionPosition = $batchItems.ListItemCollectionPosition Write-Host "正在处理第 $($batchItems.ListItemCollectionPosition.PagingInfo) 批次,共 $($batchItems.Count) 条数据" # 遍历当前批次的项 foreach ($item in $batchItems) { try { # 这里写你的修改逻辑,比如: # $item["Title"] = "修改后的标题" # $item.Update() } catch { Write-Error "处理ID为 $($item.ID) 的项时出错:$_" } finally { # 释放当前项的资源 $item.Dispose() } } # 手动触发垃圾回收,释放内存 [GC]::Collect() [GC]::WaitForPendingFinalizers() } while ($spQuery.ListItemCollectionPosition -ne $null) # 恢复列表的原始设置 $targetList.EventReceivers.Enabled = $originalEventState $targetList.EnableVersioning = $originalVersionState $targetList.Update() # 释放Web对象资源 $siteWeb.Dispose() Write-Host "所有数据处理完成"
关键优化点
- 设置合理批次大小:500-2000条是SharePoint推荐的安全范围,平衡内存占用和请求次数。
- 只加载必要字段:通过
ViewFields和ViewFieldsOnly指定需要修改的字段,避免加载无关元数据,大幅降低内存消耗。 - 禁用事件和版本:处理期间关闭列表事件接收器和版本控制,避免不必要的性能开销,处理完成后恢复。
- 及时释放资源:每个
SPListItem处理完后调用Dispose(),循环间隙触发垃圾回收,防止内存泄漏。 - 错误捕获:加入
try-catch避免单个项处理失败导致整个脚本中断。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

