0

I am trying to change the course code via the canvas api. I can get it to work in bash with the example the give

curl -X PUT -H 'Authorization: Bearer w3KhVblthisisnottoken5LmhlnUorFM8NJMh0' \
https://school.test.instructure.com/api/v1/courses/9066 \
-d 'course[course_code]=holla!' \
-v

I try to reproduce this in powershell. The call goes through, but it does not do anything!

function Update-CanvasCourseName(
[Parameter(Mandatory = $true)][string] $CourseId, 
[Parameter(Mandatory = $true)][object] $header, 
[Parameter(Mandatory = $true)][string] $url,
[Parameter(Mandatory = $true)][string] $name
){
    $uri = "$url$CourseId"
    $body = @{"course[course_code]" = $name}
    Invoke-WebRequest -Headers $header -Body $body -Method put  -Uri $uri

}
$header  = @{"Authorization"="Bearer $(C:\PowerShells\decryptText.ps1 -FilePath C:\Credentials\canvasapi.txt)"}
$course = 9066
$url = "https://holyfamily.test.instructure.com/api/v1/courses/"
Update-CanvasCourseName -CourseId $course -header $header -url $url -name "please work"

has anyone have this issue before? IS there something in my code that I am doing wrong? I cannot reproduce what I can do in curl.


Solved!

The problem was that I was using the wrong content type. For Canvas LMS, multipart/form-data must be selected when doing a PUT call.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Franco Pettigrosso
  • 4,056
  • 2
  • 20
  • 32
  • You have different URLs between your curl and PS examples, and you have a hard coded token in the curl command, but not in the PS example. Does it work if you hard code the token in the PS script? How about if you use the same URL? – TheMadTechnician Oct 12 '18 at 19:36
  • tried both of those ways – Franco Pettigrosso Oct 12 '18 at 21:03
  • When you say the "call goes through" do you mean you're getting the same response from the webserver? Have you tried capturing both requests and comparing to ensure they're identical? – so cal cheesehead Oct 12 '18 at 21:24
  • are you using self signed certs? and or powershell version 3-5 if so you may want to look at this article: https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error – Thom Schumacher Oct 12 '18 at 22:21
  • @socalcheesehead what I mean by "call goes through" is that the server accepts the call and gives back a response. The responses are not identical since the changes requested to be made are not being made. I didn't check the responses. – Franco Pettigrosso Oct 13 '18 at 02:15
  • @FrancoPettigrosso if you're still stuck on this it might be worth while to verify you're getting the same response code and response body using both methods – so cal cheesehead Oct 15 '18 at 16:40
  • @socalcheesehead I have check the responses, The format comes back the same is just that the Curl response shows the changes and the Invoke-webrequest does not. Would it be possible to check the request? – Franco Pettigrosso Oct 16 '18 at 11:15
  • 1
    You can use something like Fiddler to capture both the request and the response – so cal cheesehead Oct 16 '18 at 14:50
  • @socalcheesehead, turns out the content type needs to be 'multipart/form-data'. – Franco Pettigrosso Oct 16 '18 at 17:39

3 Answers3

1

The problem was that I was using the wrong content type. For Canvas LMS, multipart/form-data must be selected when doing a PUT call.

Franco Pettigrosso
  • 4,056
  • 2
  • 20
  • 32
0

Assuming Canvas has a REST interface, the Invoke-RestMethod cmdlet may be more appropriate for this than Invoke-WebRequest.

As I remember, Invoke-WebRequest is intended for web pages, and includes features for dealing with HTML responses, it returns an object that is sort of slanted that way, while Invoke-RestMethod is intended for Web APIs, and processes the response differently. This alternative processing of the response may be useful in figuring out what's going on for you.

For further detail, see for example https://www.systemcenterautomation.com/2018/05/invoke-restmethod-vs-invoke-webrequest/

Burt_Harris
  • 6,415
  • 2
  • 29
  • 64
0

One thing I noticed is that, yes - you have to use the "-ContentType 'multipart/form-data'" switch, but I also found that the BODY should not contain a JSON object. Instead, you pass a Powershell HashTable in the BODY field, as follows:

$token   = "<YOUR_TOKEN>" 
$headers = @{"Authorization"="Bearer "+$token}
$uri     = "https://<YOUR_HOST_NAME>:443/api/v1/courses/<COURSE_ID>"
$body = @{
    'course[sis_course_id]'='NEW_ID'
}

$response = Invoke-RestMethod `
    -URI $URI `
    -Headers $headers `
    -Method PUT `
    -Body $body `
    -ContentType 'multipart/form-data'

Write-host $response
BenjaminSelby
  • 59
  • 1
  • 6