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

SharePoint Online列表附件下载后损坏无法打开,求排查PnP PowerShell脚本问题

SharePoint Online列表附件下载脚本导致文件损坏的问题

我有一个SharePoint Online列表,里面的项目带有附件。我想用PnP PowerShell下载所有列表项的附件,写了如下脚本:

$ApprovalListItems = Get-PnPListItem -List "tickets" -PageSize 1000 -ScriptBlock { Param($items) $items.Context.ExecuteQuery()} | ForEach-Object {
     
  $ctx = Get-PnPContext
  $spSourceWeb= Get-PnPWeb
    
  $ItemAttachmentURLPrefix = 'https://****.sharepoint.com/Lists/tickets/Attachments/'+$_['ID']+'/'
  $attachmentCollection = ForEach-Object{Get-PnPProperty -ClientObject $_ -Property "AttachmentFiles"}
    
  $AttachmentSeq = 0
  ForEach($Attachment in $attachmentCollection)
            {
            Write-Host "`tDownloading Attachement: " $attachment $ItemAttachmentURLPrefix
            
            $AttachmentSeq++
    
            $AttachmentDataObj = "" | Select "Attachment Seq", "JDE Company", "Vendor Number", "Vendor Invoice Number", "Attachment Name", "Attachment System Name", "Job-run Date/Time Stamp"
    Write-Host $Attachment.FileName
            $file = Get-PnPFile -Url ($ItemAttachmentURLPrefix + $Attachment.FileName)
            $bytes = (Get-PnPFile -Url ($ItemAttachmentURLPrefix + $Attachment.FileName)).OpenBinaryStream()
            $name = "C:\Attachments\"+$Attachment.FileName
             $fs = New-Object System.IO.StreamWriter($name, "OpenOrCreate") 
            $fs.Write($bytes, 0 , $bytes.Length)    
            $fs.Close() 
            $stream = $streamResult.Value
            Write-Host $file.Name
            Write-Host $stream.Name
            }
   }

但保存后的文件无法打开,Excel文件报错,PDF显示损坏。请问脚本哪里有问题?


脚本存在的核心问题

  • 二进制文件处理错误:使用StreamWriter写入二进制数据,StreamWriter是专门处理文本的工具,会将二进制字节按文本编码转换,直接破坏文件结构。
  • OpenBinaryStream调用错误:该方法返回的是ClientResult<Stream>对象,不是直接可用的字节数组或流,你没有正确提取其中的流数据。
  • 冗余的API调用:重复调用Get-PnPFile获取同一个文件,既浪费资源也容易引发错误。
  • 附件集合赋值错误:ForEach-Object{Get-PnPProperty...}语法错误,不需要嵌套ForEach-Object,直接调用Get-PnPProperty即可获取附件集合。

修正后的脚本

# 确保下载目录存在
$downloadPath = "C:\Attachments"
if (-not (Test-Path $downloadPath)) {
    New-Item -ItemType Directory -Path $downloadPath | Out-Null
}

# 获取列表项并遍历处理附件
Get-PnPListItem -List "tickets" -PageSize 1000 -ScriptBlock { Param($items) $items.Context.ExecuteQuery()} | ForEach-Object {
    $listItem = $_
    # 获取当前列表项的附件集合
    $attachmentCollection = Get-PnPProperty -ClientObject $listItem -Property "AttachmentFiles"
    
    if ($attachmentCollection.Count -gt 0) {
        Write-Host "处理列表项ID: $($listItem['ID']) 的附件"
        $AttachmentSeq = 0
        foreach ($attachment in $attachmentCollection) {
            $AttachmentSeq++
            Write-Host "`t下载附件: $($attachment.FileName)"
            
            # 获取附件的文件流
            $fileStream = Get-PnPFile -Url $attachment.ServerRelativeUrl -AsFileStream
            $savePath = Join-Path -Path $downloadPath -ChildPath $attachment.FileName
            
            # 安全写入二进制文件
            using ($localStream = [System.IO.File]::Create($savePath)) {
                $fileStream.CopyTo($localStream)
            }
            
            Write-Host "`t已保存到: $savePath"
        }
    }
}

关键修复点说明

  1. 使用-AsFileStream参数:直接获取文件流,避免手动处理二进制数据的编码错误。
  2. 二进制安全写入:用File::Create创建文件流,通过CopyTo方法复制二进制数据,确保文件结构完整。
  3. 简化URL处理:直接使用附件的ServerRelativeUrl属性,避免手动拼接URL的潜在错误。
  4. 自动管理流资源:using语句会自动关闭并释放流资源,避免内存泄漏或文件占用问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 10:40:37