PowerShell调用Confluence REST API上传附件遇权限及空文件问题求助
PowerShell调用Confluence API上传Excel附件权限及空文件问题解决
问题场景
我正在编写PowerShell脚本,通过Token认证调用Atlassian Confluence REST API将Excel文档上传至指定页面作为附件。脚本代码如下:
Write-Host "Start of script" $userToken = "TOKEN" $pageId = "PAGE-ID" $fileName = "All_Employee_List.xlsx" $rootFolder = "C:\moonfall\Powershell\Server Side\General Server Scripts" $subFolder = "All_Employee_list\All_Employee_List_SRV_2" $filePath = Join-Path $rootFolder $subFolder $wpURL = "https://DOMAIN/rest/api/content/" $Headers = @{ 'Authorization' = "Bearer $userToken" 'X-Atlassian-Token' = 'nocheck' } # Get the attachment ID if it exists $uri = $wpURL + $pageId + "/child/attachment?filename=$fileName&expand=body.storage,version,space,ancestors" $attachment = Invoke-RestMethod -Method GET -Headers $Headers -Uri $uri $attachmentId = $attachment.results.id # If the attachment doesn't exist, create it if (!$attachmentId) { $uri = $wpURL + $pageId + "/child/attachment" #after this file path check it won't upload to confluence anymore, it just says access to the path is denied if (-not (Test-Path $filePath)) { Write-Error "File does not exist at $filePath" return } try { $fileBytes = [System.IO.File]::ReadAllBytes(${filePath}) } catch { Write-Error "Failed to read file at ${filePath}: $_" return } $fileEncoded = [System.Convert]::ToBase64String($fileBytes) $delimiter = [System.Guid]::NewGuid().ToString() $LF = "`r`n" $bodyData = ( "--$delimiter", "Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"", "Content-Type: application/octet-stream$LF", $fileEncoded, "--$delimiter--$LF" ) -join $LF Invoke-RestMethod -Uri $uri -Method POST -ContentType "multipart/form-data; boundary=$delimiter" -Headers $Headers -Body $bodyData Write-Output "Attachment created successfully." } else { Write-Output "Attachment already exists. Skipping creation." } # Set the attachment as the primary viewable attachment $uri = $wpURL + $attachmentId + "/?minorEdit=true" $bodyData = @{ "id" = $attachmentId "version" = @{ "number" = $attachment.version.number + 1 } "type" = "attachment" "title" = $fileName "container" = @{ "id" = $pageId "type" = "page" } "metadata" = @{ "comment" = @{ "value" = "Automatically uploaded from PowerShell script." } "labels" = @() "properties" = @{ "download" = @{ "value" = @{ "downloadAll" = "true" } } } } "extensions" = @{ "mediaType" = @{ "value" = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" "macroEnabled" = "true" } } "status" = "current" } | ConvertTo-Json # Make the request $response = Invoke-RestMethod -Uri $uri -Method POST -Headers $Headers -ContentType "multipart/form-data; boundary=$delimiter" -Body $bodyData # Print the response $response
错误1:管理员权限运行时的权限拒绝
以管理员权限运行脚本时,出现错误:
Failed to read file at 'FILE-PATH': Exception calling "ReadAllBytes" with "1" argument(s): "Access to the path 'FILE-PATH' is denied.
错误2:移除文件检查后的空文件与415错误
移除文件读取检查后,出现以下错误,且附件上传后为0KB空文件:
Exception calling "ReadAllBytes" with "1" argument(s): "Access to the path 'C:\moonfall\Powershell\Server Side\General Server Scripts\All_Employee_list\All_Employee_List_SRV_2' is denied." At line:29 char:5 + $fileBytes = [System.IO.File]::ReadAllBytes($filePath) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : UnauthorizedAccessException Exception calling "ToBase64String" with "1" argument(s): "Value cannot be null. Parameter name: inArray" At line:30 char:5 + $fileEncoded = [System.Convert]::ToBase64String($fileBytes) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ArgumentNullException results size _links ------- ---- ------ {@{id=123455572; type=attachment; status=current; title=All_Employee_List.xlsx; version=; container=; metadata=; extensions=; _links=; _expandable=}} 1 @{base=https://DOMAIN; context=} Attachment created successfully. Invoke-RestMethod : The remote server returned an error: (415). At line:84 char:13 + $response = Invoke-RestMethod -Uri $uri -Method POST -Headers $Header ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
解决步骤
1. 修复文件路径错误
核心问题:$filePath仅拼接了文件夹路径,未包含文件名,导致尝试读取文件夹而非文件,触发权限拒绝。修改路径拼接:
# 正确拼接完整文件路径 $filePath = Join-Path $rootFolder $subFolder $fileName
2. 简化Multipart文件上传
手动处理Base64编码和Multipart格式容易出错,直接用Invoke-RestMethod的-InFile参数更可靠。替换原文件读取及上传代码段:
# 替换原有的文件读取、Base64编码及POST请求部分 if (-not (Test-Path $filePath -PathType Leaf)) { Write-Error "File does not exist at $filePath" return } Invoke-RestMethod -Uri $uri -Method POST -Headers $Headers -ContentType "multipart/form-data" -InFile $filePath
3. 修正附件更新请求的方法与ContentType
更新附件属性需用PUT方法,且发送JSON数据时ContentType应为application/json,而非multipart/form-data,这是415错误的根源:
# 修改更新请求的方法和ContentType $response = Invoke-RestMethod -Uri $uri -Method PUT -Headers $Headers -ContentType "application/json" -Body $bodyData
4. 完善附件存在性检查逻辑
原代码中$attachment.results.id在多个匹配附件时会返回数组,需调整为取第一个匹配项:
$attachmentId = $attachment.results | Where-Object { $_.title -eq $fileName } | Select-Object -ExpandProperty id -First 1
完整修正后的脚本
Write-Host "Start of script" $userToken = "TOKEN" $pageId = "PAGE-ID" $fileName = "All_Employee_List.xlsx" $rootFolder = "C:\moonfall\Powershell\Server Side\General Server Scripts" $subFolder = "All_Employee_list\All_Employee_List_SRV_2" # 正确拼接完整文件路径 $filePath = Join-Path $rootFolder $subFolder $fileName $wpURL = "https://DOMAIN/rest/api/content/" $Headers = @{ 'Authorization' = "Bearer $userToken" 'X-Atlassian-Token' = 'nocheck' } # Get the attachment ID if it exists $uri = "$wpURL$pageId/child/attachment?filename=$fileName&expand=version" $attachment = Invoke-RestMethod -Method GET -Headers $Headers -Uri $uri $existingAttachment = $attachment.results | Where-Object { $_.title -eq $fileName } | Select-Object -First 1 $attachmentId = $existingAttachment.id # If the attachment doesn't exist, create it if (!$attachmentId) { $uri = "$wpURL$pageId/child/attachment" if (-not (Test-Path $filePath -PathType Leaf)) { Write-Error "File does not exist at $filePath" return } try { Invoke-RestMethod -Uri $uri -Method POST -Headers $Headers -ContentType "multipart/form-data" -InFile $filePath Write-Output "Attachment created successfully." # 重新获取新创建的附件ID用于后续更新 $attachment = Invoke-RestMethod -Method GET -Headers $Headers -Uri "$wpURL$pageId/child/attachment?filename=$fileName&expand=version" $existingAttachment = $attachment.results | Where-Object { $_.title -eq $fileName } | Select-Object -First 1 $attachmentId = $existingAttachment.id } catch { Write-Error "Failed to upload attachment: $_" return } } else { Write-Output "Attachment already exists. Preparing to update." } # Set the attachment as the primary viewable attachment $uri = "$wpURL$attachmentId/?minorEdit=true" $bodyData = @{ "id" = $attachmentId "version" = @{ "number" = $existingAttachment.version.number + 1 } "type" = "attachment" "title" = $fileName "container" = @{ "id" = $pageId "type" = "page" } "metadata" = @{ "comment" = @{ "value" = "Automatically uploaded from PowerShell script." } "labels" = @() "properties" = @{ "download" = @{ "value" = @{ "downloadAll" = "true" } } } } "extensions" = @{ "mediaType" = @{ "value" = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" "macroEnabled" = "true" } } "status" = "current" } | ConvertTo-Json -Depth 10 # Make the request with correct method and ContentType try { $response = Invoke-RestMethod -Uri $uri -Method PUT -Headers $Headers -ContentType "application/json" -Body $bodyData # Print the response $response Write-Output "Attachment updated successfully." } catch { Write-Error "Failed to update attachment: $_" }
内容的提问来源于stack exchange,提问作者r4ymaster
相关产品推荐
相关产品推荐

