0

I use the following powershell and REST-API to upload attachment

class TfsHelper{
#...
  [string]UploadPng([string]$TfsProject, [string]$PngFileName) {
    $uri = "http://$organization/$TfsProject/_apis/wit/attachments?fileName=image.png&api-version=5.1"
    $strPngBase64 = [convert]::ToBase64String((Get-Content $PngFileName -Encoding byte))  
    $rtn = Invoke-RestMethod -Uri $uri -Method POST -Headers $this.Header `
      -Body $strPngBase64 `
      -ContentType 'application/octet-stream'
    return $rtn.url
  }
}

The function UploadPng executed successfully and I can also get the response which contains the uploaded PNG url and uuid

But when I opened response url in browser to check the uploaded PNG, I found the uploaded image was not shown as expected and not same as the original one.

The uploaded image shown in browser The original png in local

So, what`s wrong with the function UploadPng?

zhong
  • 35
  • 3

1 Answers1

1

I can reproduce the same issue when using the same Powershell script.

To solve this issue, you can use the powershell command: [IO.File]::ReadAllBytes("$PngFileName") to read the file and no need to convert it to base64. Then you can change the content type to application/json.

class TfsHelper{
#...
  [string]UploadPng([string]$TfsProject, [string]$PngFileName) {
    $uri = "http://$organization/$TfsProject/_apis/wit/attachments?fileName=image.png&api-version=5.1"
    $file = [IO.File]::ReadAllBytes("$PngFileName") 
    $rtn = Invoke-RestMethod -Uri $uri -Method POST -Headers $this.Header `
      -Body $file  `
      -ContentType 'application/json'
    return $rtn.url
  }
}

Or you can use the -InFile to create the attachment.

Here is PowerShell example:

class TfsHelper{
#...
  [string]UploadPng([string]$TfsProject, [string]$PngFileName) {
    $uri = "http://$organization/$TfsProject/_apis/wit/attachments?fileName=image.png&api-version=5.1"
    $file = Get-ChildItem -Path "filepath" 
    $rtn = Invoke-RestMethod -Uri $uri -Method POST -Headers $this.Header `
      -InFile $file `
      -ContentType 'application/octet-stream'
    return $rtn.url
  }
}

Update:

class TfsHelper{
  [string]UploadPng([string]$TfsProject, [string]$PngFileName) {
    $uri = "https://dev.azure.com/orgname/$TfsProject/_apis/wit/attachments?fileName=image.png&api-version=5.1"
    $file = Get-ChildItem -Path "$PngFileName" 
    $token = "PAT"
    $token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($token)"))
    $rtn = Invoke-RestMethod -Uri $uri -Method POST -Headers @{Authorization = "Basic $token"} `
      -InFile $file `
      -ContentType 'application/octet-stream'

    return $rtn.url
  }
}


$uploadpng = [TfsHelper]::new()

echo $uploadpng.UploadPng("projectname","pngpath")
Kevin Lu-MSFT
  • 20,786
  • 3
  • 19
  • 28
  • Both solutions raise error `Content-Type 'application/x-www- form-urlencoded' is unsupported for method 'POST'` – zhong Dec 07 '22 at 07:11
  • @zhong Can you try to run the script in my update of the answer? Check if it can work for you. – Kevin Lu-MSFT Dec 07 '22 at 07:25
  • The cause of the issue could be that the Invoke-RestMethod ignore the Content type argument. you can set the all parameters at the same line, for example: `$rtn = Invoke-RestMethod -Uri $uri -Method POST -Headers @{Authorization = "Basic $token"} -InFile $file -ContentType 'application/octet-stream'` – Kevin Lu-MSFT Dec 07 '22 at 07:57
  • 1
    It is worked and appreciate for your guidance. The exception('application/x-www- form-urlencoded') memtioned in my previous reply, was caused by the comments between line-break ```. Sorry for my confused reply. – zhong Dec 07 '22 at 08:32