SharePoint Online:使用 PowerShell 上传大文件
要求:使用 PowerShell 将大文件上传到 SharePoint Online。
PowerShell 将大文件上传到 SharePoint Online
假设您尝试使用 CSOM Files.Add 方法或 PnP PowerShell Add-PnPFile 方法将文件大小 > 250 MB 的文件上传到 SharePoint Online,您最终会遇到错误:
- “远程服务器返回错误:(503) 服务器不可用。”
- “Add-PnPFile:请求消息太大。服务器不允许消息大于 262144000 字节”
- Add-PnPFile:基础连接已关闭:发送时发生意外错误
- Add-PnPFile :远程服务器返回错误:(404) 未找到
缓解错误的方法 以下是如何使用 PowerShell 将较大的文件上传到 SharePoint Online:
#Load SharePoint CSOM Assemblies
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
#Parameters
$SiteURL = "https://crescent.sharepoint.com/sites/marketing"
$TargetFolderURL = "/sites/marketing/Shared Documents"
$FilePath = "C:\Users\Thomas\Downloads\WFx64.zip"
#Get Credentials to connect
$Cred = Get-Credential
Try {
#Setup the context
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($SiteURL)
$Ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Cred.UserName,$Cred.Password)
#Get the file from disk
$FileStream = ([System.IO.FileInfo] (Get-Item $FilePath)).OpenRead()
#Calculate Target URL
$SourceFileName = Split-path $FilePath -leaf
$TargetFileURL = $TargetFolderURL+"/"+$SourceFileName
#Upload Large File to SharePoint Online
$Ctx.RequestTimeout = [System.Threading.Timeout]::Infinite
[Microsoft.SharePoint.Client.File]::SaveBinaryDirect($Ctx, $TargetFileURL, $FileStream,$True)
Write-host "File uploaded Successfully!" -f Green
}
Catch {
write-host "Error Uploading File: $($_.Exception.Message)" -foregroundcolor Red
}
但是,当您从慢速网络上传较大文件时,如果上传操作时间超过 30 分钟,则会超时。
SharePoint Online 文件大小限制
- 250 GB - 文件上传限制。适用于每个单独的文件
- 250 MB - 附加到列表项的文件。
PowerShell 将大文件分块上传到 SharePoint Online:
我们可以将其拆分为较小的块并上传,而不是一次性上传较大的文件。
#Function to Upload Large File to SharePoint Online Library
Function Upload-LargeFile($FilePath, $LibraryName, $FileChunkSize=10)
{
Try {
#Get File Name
$FileName = [System.IO.Path]::GetFileName($FilePath)
$UploadId = [GUID]::NewGuid()
#Get the folder to upload
$Library = $Ctx.Web.Lists.GetByTitle($LibraryName)
$Ctx.Load($Library)
$Ctx.Load($Library.RootFolder)
$Ctx.ExecuteQuery()
$BlockSize = $FileChunkSize * 1024 * 1024
$FileSize = (Get-Item $FilePath).length
If($FileSize -le $BlockSize)
{
#Regular upload
$FileStream = New-Object IO.FileStream($FilePath,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $FileName
$Upload = $Docs.RootFolder.Files.Add($FileCreationInfo)
$ctx.Load($Upload)
$ctx.ExecuteQuery()
}
Else
{
#Large File Upload in Chunks
$ServerRelativeUrlOfRootFolder = $Library.RootFolder.ServerRelativeUrl
[Microsoft.SharePoint.Client.File]$Upload
$BytesUploaded = $null
$Filestream = $null
$Filestream = [System.IO.File]::Open($FilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$BinaryReader = New-Object System.IO.BinaryReader($Filestream)
$Buffer = New-Object System.Byte[]($BlockSize)
$LastBuffer = $null
$Fileoffset = 0
$TotalBytesRead = 0
$BytesRead
$First = $True
$Last = $False
#Read data from the file in blocks
While(($BytesRead = $BinaryReader.Read($Buffer, 0, $Buffer.Length)) -gt 0)
{
$TotalBytesRead = $TotalBytesRead + $BytesRead
If ($TotalBytesRead -eq $FileSize)
{
$Last = $True
$LastBuffer = New-Object System.Byte[]($BytesRead)
[Array]::Copy($Buffer, 0, $LastBuffer, 0, $BytesRead)
}
If($First)
{
#Create the File in Target
$ContentStream = New-Object System.IO.MemoryStream
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.ContentStream = $ContentStream
$FileCreationInfo.Url = $FileName
$FileCreationInfo.Overwrite = $true
$Upload = $Library.RootFolder.Files.Add($FileCreationInfo)
$Ctx.Load($Upload)
#Start FIle upload by uploading the first slice
$s = new-object System.IO.MemoryStream(, $Buffer)
$BytesUploaded = $Upload.StartUpload($UploadId, $s)
$Ctx.ExecuteQuery()
$fileoffset = $BytesUploaded.Value
$First = $False
}
Else
{
#Get the File Reference
$Upload = $ctx.Web.GetFileByServerRelativeUrl($Library.RootFolder.ServerRelativeUrl + [System.IO.Path]::AltDirectorySeparatorChar + $FileName);
If($Last)
{
$s = [System.IO.MemoryStream]::new($LastBuffer)
$Upload = $Upload.FinishUpload($UploadId, $fileoffset, $s)
$Ctx.ExecuteQuery()
Write-Host "File Upload completed!" -f Green
}
Else
{
#Update fileoffset for the next slice
$s = [System.IO.MemoryStream]::new($buffer)
$BytesUploaded = $Upload.ContinueUpload($UploadId, $fileoffset, $s)
$Ctx.ExecuteQuery()
$fileoffset = $BytesUploaded.Value
}
}
}
}
}
Catch {
Write-Host $_.Exception.Message -ForegroundColor Red
}
Finally {
If($Filestream -ne $null)
{
$Filestream.Dispose()
}
}
}
#Connect to SharePoint Online site
Connect-PnPOnline "https://crescent.sharepoint.com/sites/marketing" -Interactive
$Ctx = Get-PnPContext
#Call the function to Upload File
Upload-LargeFile -FilePath "C:\Users\Thomas\Downloads\235021WFx64.rar" -LibraryName "Documents"
顺便说一句,我已将该方法转换为 PowerShell,如 https://docs.microsoft.com/en-us/sharepoint/dev/solution-guidance/upload-large-files-sample-app-for-sharepoint 中所述