Azure PowerShell Runbook中iText7修改PDF后无法保存至SharePoint
方案一:修复iText7修改后的PDF保存流程
你当前的问题大概率是修改后未重置MemoryStream的位置,导致写入SPO时流为空。以下是完整的可行流程:
关键操作点
- 修改PDF后,必须将输出MemoryStream的
Position重置为0,否则写入会从流的末尾开始,生成空白文件。 - 使用PnP PowerShell的
Add-PnPFile命令完成流到SPO的写入,这是Azure Runbook中操作SPO文件最稳定的方式。
完整代码示例
# 安装/导入PnP模块(Runbook首次运行需执行,可重复执行) if (-not (Get-Module -Name PnP.PowerShell -ListAvailable)) { Install-Module -Name PnP.PowerShell -Force -AllowClobber -Scope CurrentUser } Import-Module PnP.PowerShell # 连接SharePoint Online(示例用应用身份验证,也可替换为托管身份) $siteUrl = "https://yourtenant.sharepoint.com/sites/yoursite" $clientId = "你的应用客户端ID" $clientSecret = ConvertTo-SecureString "你的应用客户端密钥" -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret) Connect-PnPOnline -Url $siteUrl -Credentials $cred # 读取源PDF到MemoryStream $sourceFilePath = "/sites/yoursite/Shared Documents/SourceFolder/原始文件.pdf" $sourceFile = Get-PnPFile -Url $sourceFilePath -AsFileObject $sourceStream = New-Object System.IO.MemoryStream $sourceFile.OpenBinaryStream().Result.CopyTo($sourceStream) # 用iText7修改PDF(替换为你的现有修改逻辑) Add-Type -Path "$env:TEMP/itext.kernel.dll" Add-Type -Path "$env:TEMP/itext.layout.dll" $reader = New-Object iText.Kernel.Pdf.PdfReader($sourceStream) $outputStream = New-Object System.IO.MemoryStream $writer = New-Object iText.Kernel.Pdf.PdfWriter($outputStream) $pdfDoc = New-Object iText.Kernel.Pdf.PdfDocument($reader, $writer) # 示例:添加空白页(替换成你的修改代码) $pdfDoc.AddNewPage() # 关闭文档,确保内容写入输出流 $pdfDoc.Close() $reader.Close() $writer.Close() # 重置输出流位置到开头(核心步骤!) $outputStream.Position = 0 # 保存到目标SPO文件夹 $targetFolderPath = "/sites/yoursite/Shared Documents/TargetFolder" Add-PnPFile -FileName "修改后的文件.pdf" -Folder $targetFolderPath -Stream $outputStream # 清理资源 $sourceStream.Dispose() $outputStream.Dispose() Disconnect-PnPOnline
注意事项
- 将iText7的DLL文件(
itext.kernel.dll、itext.layout.dll)上传至Azure Automation资产库,或在Runbook中下载到临时目录$env:TEMP。 - 若使用托管身份连接SPO,只需将连接命令改为
Connect-PnPOnline -Url $siteUrl -ManagedIdentity,并确保托管身份拥有SPO站点的编辑权限。
方案二:纯PowerShell替代方案(使用PdfSharp)
如果不想依赖iText7,可使用开源.NET库PdfSharp,直接在PowerShell中实现PDF修改:
代码示例
# 安装/导入PnP模块(同方案一) if (-not (Get-Module -Name PnP.PowerShell -ListAvailable)) { Install-Module -Name PnP.PowerShell -Force -AllowClobber -Scope CurrentUser } Import-Module PnP.PowerShell # 连接SPO $siteUrl = "https://yourtenant.sharepoint.com/sites/yoursite" $clientId = "你的应用客户端ID" $clientSecret = ConvertTo-SecureString "你的应用客户端密钥" -AsPlainText -Force $cred = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret) Connect-PnPOnline -Url $siteUrl -Credentials $cred # 读取源PDF到MemoryStream $sourceFilePath = "/sites/yoursite/Shared Documents/SourceFolder/原始文件.pdf" $sourceFile = Get-PnPFile -Url $sourceFilePath -AsFileObject $sourceStream = New-Object System.IO.MemoryStream $sourceFile.OpenBinaryStream().Result.CopyTo($sourceStream) $sourceStream.Position = 0 # 引用PdfSharp DLL(需提前上传到Runbook资产库) Add-Type -Path "$env:TEMP/PdfSharp.dll" Add-Type -Path "$env:TEMP/PdfSharp.Drawing.dll" # 修改PDF(示例添加空白页) $pdfDoc = PdfSharp.Pdf.IO.PdfReader.Open($sourceStream, PdfSharp.Pdf.IO.PdfDocumentOpenMode.Modify) $pdfDoc.AddPage() # 写入输出流 $outputStream = New-Object System.IO.MemoryStream $pdfDoc.Save($outputStream) $pdfDoc.Close() # 重置流位置并保存到SPO $outputStream.Position = 0 $targetFolderPath = "/sites/yoursite/Shared Documents/TargetFolder" Add-PnPFile -FileName "修改后的文件_ps.pdf" -Folder $targetFolderPath -Stream $outputStream # 清理资源 $sourceStream.Dispose() $outputStream.Dispose() Disconnect-PnPOnline
注意事项
- PdfSharp对复杂PDF的支持不如iText7,适合简单的页面添加、合并等操作;若需高级编辑(如文本替换、表单处理),建议优先用方案一。
内容的提问来源于stack exchange,提问作者Marc Codere Dussault
相关产品推荐
相关产品推荐

