GitLab流水线中PowerShell脚本转Docx为PDF时执行异常求助
Docx转PDF脚本在GitLab流水线执行失败问题
我编写了一段PowerShell脚本,手动执行可正常将Docx文件转换为PDF,但在GitLab流水线中调用时出现异常,脚本无法正常结束,Word进程还会持续占用内存,只能手动终止。
脚本内容
param( [string]$File, # Path to document [string]$DestinationFolder, # Path of folder [string]$NewName # New name for converted file ) # ======== check if parameter are valid ======== if (-not $File) { Write-Error "Parameter '-File' must not be empty" exit 1 } if (-not $DestinationFolder) { $DestinationFolder = Split-Path -Path $File } if (-not $NewName) { $NewName = [System.IO.Path]::GetFileNameWithoutExtension($File) + ".pdf" } # ======== create destination folder if not exists ======== if (-not (Test-Path -Path $DestinationFolder)) { $null = New-Item -Path $DestinationFolder -ItemType Directory -Force Write-Output "Path did not exist. Created folder: $DestinationFolder" } # ======== export pdf ======== Write-Output "Export pdf" $Word = New-Object -ComObject 'Word.Application' $Document = $Word.Documents.Open($File) $NewFilePath = [string](Join-Path $DestinationFolder $NewName) $Document.SaveAs($NewFilePath, 17) $Document.Close() $Word.Quit() Write-Output "Stored to $NewFilePath"
报错信息
At D:\GitLab-Runner\builds\yxFfC2Egu\0\SPS_Entwicklung\test\ci-dev-test\ci\release\docx_to_pdf.ps1 :44 char:5 + $Document.SaveAs($NewFilePath, 17) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull You cannot call a method on a null-valued expression. At D:\GitLab-Runner\builds\yxFfC2Egu\0\SPS_Entwicklung\test\ci-dev-test\ci\release\docx_to_pdf.ps1 :45 char:5 + $Document.Close() + ~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
已排查情况
- GitLab Runner服务以管理员用户启动
- 使用该管理员用户手动执行脚本可正常运行
- 尝试用Python实现同类功能时,出现类似
ValueError('NULL COM pointer access',)错误,参考相关方案后未解决
解决办法
1. 给GitLab Runner服务开启桌面交互权限
Windows服务默认没有桌面会话,而Office COM组件依赖桌面环境才能正常工作:
- 打开「服务」管理器,找到GitLab Runner服务
- 右键选择「属性」,切换到「登录」选项卡
- 勾选「允许服务与桌面交互」,点击确定后重启服务
2. 修改脚本,增加异常处理与COM对象释放
原脚本未处理异常,且未正确释放COM对象,容易导致进程残留。修改后的导出部分代码如下:
# ======== export pdf ======== Write-Output "Export pdf" $Word = $null $Document = $null try { $Word = New-Object -ComObject 'Word.Application' $Word.Visible = $false $Word.DisplayAlerts = 0 # 禁用所有Office提示弹窗,避免阻塞 $Document = $Word.Documents.Open($File) $NewFilePath = [string](Join-Path $DestinationFolder $NewName) $Document.SaveAs($NewFilePath, 17) Write-Output "Stored to $NewFilePath" } catch { Write-Error "转换失败: $_" exit 1 } finally { # 强制释放文档对象 if ($Document) { $Document.Close() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Document) | Out-Null } # 强制退出Word并释放对象 if ($Word) { $Word.Quit() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word) | Out-Null [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() } }
原因说明
GitLab Runner作为Windows服务运行时,默认处于无桌面的会话环境,Microsoft Office的COM组件(如Word)需要桌面交互才能正确初始化文档对象,这就是为什么手动执行正常,但流水线中$Document会返回null的核心原因。同时,原脚本未处理异常和释放COM对象,导致Word进程无法正常退出,持续占用内存。
内容的提问来源于stack exchange,提问作者Pukinn
相关产品推荐
相关产品推荐

