You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过PowerShell上传文件至Wasabi S3时遇410及请求体终止错误

问题

使用PowerShell脚本将SharePoint文件下载后上传至Wasabi S3指定存储桶及文件夹,下载功能正常,但上传进度到100%后终止,报错The request body terminated unexpectedly。联系Wasabi支持后,对方反馈日志中存在410错误,且已拥有S3完全权限,当前使用的脚本如下:

$SiteUrl = "sharepoint site"    
$LibraryName = "Documents"
$FolderName = "Archive"
$S3BucketName = "Bucket"    
$S3Region = "eu-central-2" 
$AccessKey = "Access_Key" 
$SecretKey = "Secret_Key" 

$LocalTempFolder = "Folderpath"  
$WasabiEndpoint = "https://s3.eu-central-2.wasabisys.com"

Import-Module PnP.PowerShell
Import-Module AWSPowerShell.NetCore


function Convert-HexStringToByteArray {
    param (
        [string]$HexString
    )
    
    
    if ($HexString.Length % 2 -ne 0) {
        throw "Hex string length must be even."
    }

    
    $ByteArray = for ($i = 0; $i -lt $HexString.Length; $i += 2) {
        [Convert]::ToByte($HexString.Substring($i, 2), 16)
    }
    
    return $ByteArray
}

function Upload-ToWasabi {
    param (
        [string]$FilePath,
        [string]$S3Key,
        [int]$RetryCount = 3
    )

    for ($Attempt = 1; $Attempt -le $RetryCount; $Attempt++) {
        try {
            Write-Host "Uploading item to Wasabi S3: $S3Key (Attempt $Attempt of $RetryCount)"

            
            Write-S3Object -BucketName $S3BucketName `
               -Key $S3Key `
               -File $FilePath `
               -Region $S3Region `
               -ProfileName WasabiProfile `
               -Endpoint $WasabiEndpoint `
               -StorageClass STANDARD `
               -PartSize 5MB `
               -Verbose

            Write-Host "Upload successful for $S3Key."
            return $true
        } catch {
            Write-Host "Error during upload: $($_.Exception.Message)"
            Write-Host "Full error details: $($_.Exception)"
            if ($Attempt -lt $RetryCount) {
                Write-Host "Retrying upload in 5 seconds..."
                Start-Sleep -Seconds 5
            } else {
                Write-Error "Failed to upload $S3Key after $RetryCount attempts."
                return $false
            }
        }
    }
}


Write-Host "Connecting to SharePoint..."
Connect-PnPOnline -Url $SiteUrl -UseWebLogin


if (-not (Test-Path -Path $LocalTempFolder)) {
    Write-Host "Creating temporary folder at $LocalTempFolder"
    New-Item -Path $LocalTempFolder -ItemType Directory
}

$SiteName = ($SiteUrl.Split('/'))[-1]  
Write-Host "Using SharePoint site name: $SiteName"

try {
    
    Write-Host "Fetching the SharePoint library and folder..."
    $FolderRelativeUrl = "Shared Documents/$FolderName"
    
    Write-Host "Getting files from SharePoint folder: $FolderRelativeUrl"
    $Files = Get-PnPFolderItem -FolderSiteRelativeUrl $FolderRelativeUrl

    
    Write-Host "Items found in SharePoint folder: $($Files.Count)"
    foreach ($Item in $Files) {
        Write-Host "Processing item: $($Item.Name) - Type: $($Item.FileSystemObjectType)"
        
        
        $LocalFilePath = Join-Path -Path $LocalTempFolder -ChildPath $Item.Name

        try {
            
            Write-Host "Downloading item: $($Item.Name) to $LocalFilePath"
            Get-PnPFile -Url $Item.ServerRelativeUrl -Path $LocalTempFolder -FileName $Item.Name -AsFile -Force

            
            if (Test-Path $LocalFilePath) {
                $FileSize = (Get-Item $LocalFilePath).Length
                Write-Host "Item downloaded successfully: $LocalFilePath"
                Write-Host "Item size: $FileSize bytes"

                
                $S3Key = "$SiteName/$FolderName/$($Item.Name)"

                
                $UploadSuccess = Upload-ToWasabi -FilePath $LocalFilePath -S3Key $S3Key

                if (-not $UploadSuccess) {
                    Write-Error "Failed to upload item to Wasabi: $S3Key"
                }
            } else {
                Write-Host "Error: Item was not downloaded properly: $LocalFilePath"
            }
        } catch {
            Write-Host "Error processing item: $($Item.Name)"
            Write-Error $_
        }
    }
} catch {
    Write-Error "An error occurred: $_"
} finally {
    Write-Host "Disconnecting from SharePoint..."
    Disconnect-PnPOnline
}

Write-Host "Script completed successfully."

解决建议

  • 修复凭证配置问题:脚本中指定了-ProfileName WasabiProfile但未初始化该配置文件,添加凭证初始化步骤:
    # 在Import-Module后添加
    Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs WasabiProfile
    
    或者直接在Write-S3Object中传入凭证,避免依赖本地配置:
    Write-S3Object -BucketName $S3BucketName `
       -Key $S3Key `
       -File $FilePath `
       -Region $S3Region `
       -Credential (New-Object Amazon.Runtime.BasicAWSCredentials($AccessKey, $SecretKey)) `
       -Endpoint $WasabiEndpoint `
       -StorageClass STANDARD `
       -PartSize 10MB `
       -ForcePathStyle `
       -Verbose
    
  • 调整分片上传参数:将-PartSize从5MB调整为10MB或更大,Wasabi对小分片的处理可能存在兼容性问题;同时添加-ForcePathStyle参数,强制使用路径样式访问,避免虚拟主机样式的潜在问题。
  • 替换为AWS.Tools.S3模块:AWSPowerShell.NetCore是旧版模块,AWS.Tools.S3是官方推荐的模块化工具,对第三方S3兼容更好:
    # 卸载旧模块(可选)
    Uninstall-Module AWSPowerShell.NetCore -Force
    # 安装新模块
    Install-Module AWS.Tools.S3 -Force
    # 导入模块
    Import-Module AWS.Tools.S3
    
  • 验证文件完整性:上传前对比SharePoint文件大小与本地文件大小,确保下载过程中未出现文件损坏:
    # 在Get-PnPFile后添加
    $spFile = Get-PnPFile -Url $Item.ServerRelativeUrl -AsFile -Force -Path $LocalTempFolder -FileName $Item.Name
    $spFileSize = $spFile.Length
    $localFileSize = (Get-Item $LocalFilePath).Length
    if ($spFileSize -ne $localFileSize) {
        Write-Error "File size mismatch for $($Item.Name): SharePoint size $spFileSize, local size $localFileSize"
        continue
    }
    
  • 排查410错误原因:410表示目标资源不存在,确认存储桶是否存在、$S3Key中的路径是否合法(避免特殊字符),可以手动在Wasabi控制台创建对应路径后再测试上传。

内容的提问来源于stack exchange,提问作者insil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 16:10:53