r4ymaster
r4ymaster

Reputation: 1

Upload xlsx to confluence page as attachment via REST API and token authentication

I am writing a Powershell script which will upload an Excel document to Atlassian Confluence page via REST API, using token authentication.

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

When I run the script in Powershell terminal with admin privileges I get the error:

Failed to read file at 'FILE-PATH': Exception calling "ReadAllBytes" with "1" argument(s): "Access to the path 'FILE-PATH' is denied.

But when I remove the file path check of $filebytes it writes a slightly different error:

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

And uploads the file as attachment to the page but the file has 0.0 kb and is nothing inside when opened. So as I see it I have two problems with this script. Please if anyone could help, this is all very much new to me and been trying to solve this for 3 weeks now and also with the help of ChatGPT.

Upvotes: 0

Views: 831

Answers (1)

Cpt.Whale
Cpt.Whale

Reputation: 5351

You missed adding the file name to the file path:

$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 ## File name missing?

So ReadAllBytes(${filePath}) tries to read the folder and chokes. The error message is not really accurate

Upvotes: 0

Related Questions