14

I'm trying to use the PowerShell commandlet Invoke-RestMethod to post a picture to a url. Here's my commands:

$usercreds = Get-Credential
$pic = Get-Content \\server\share\pic.jpg
$uri = http://website/sub/destination

Invoke-RestMethod -uri $uri -Method Put -Body $pic -ContentType 'image/jpg' -Credential $usercreds

I get an error: "the file is not a valid image file." I tried using Invoke-WebRequest too, with the same result. The web server isn't ours, and the tech on their side said to use curl, but we don't know how and don't have a Linux box either. Is there something I'm missing? I can open the jpg without issue so it's not corrupt or anything.

I tried this, but the server yelled at me: Using PowerShell Invoke-RestMethod to POST large binary multipart/form-data

Error code:

PS C:\Windows\system32> Invoke-WebRequest -uri $uri -Method Put -Body $pic -ContentType 'image/jpg' -Credential $usercreds
Invoke-WebRequest : {"error":{"message":"the file is not a valid image file"},"data":[],"meta":"error"}
At line:1 char:1
+ Invoke-WebRequest -uri $uri -Method Put -Body $pic -ContentType 'imag ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Carson
  • 6,105
  • 2
  • 37
  • 45
user3494277
  • 167
  • 1
  • 1
  • 7
  • What does _yelled at me_ mean. How did that not work? $pic is a newline delimited string array and not what is expected for a picture. – Matt Feb 22 '17 at 15:29
  • It told me: The remote server returned an error: (405) Method Not Allowed. I passed it the direct path to the picture, and that gave me the same error. – user3494277 Feb 22 '17 at 15:30
  • Can you show us _exactly_ what you tried that generated that error? I know what the code you have here does not work. I don't know what to tell you about code we cannot see. – Matt Feb 22 '17 at 15:31
  • PS C:\Windows\system32> Invoke-RestMethod -uri $uri -Method Put -Body $pic -ContentType 'image/jpg' -Credential $usercreds Invoke-RestMethod : {"error":{"message":"the file is not a valid image file"},"data":[],"meta":"error"} At line:1 char:1 + Invoke-RestMethod -uri $uri -Method Put -Body $pic -ContentType 'imag ... + + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand – user3494277 Feb 22 '17 at 15:35
  • Thanks for that. Please [edit] those details into your question. Code in comments is horrid. – Matt Feb 22 '17 at 15:36

2 Answers2

33

Try using the -Infile Parameter. Get-Content interprets your file an array of strings and just messes things up.

$usercreds = Get-Credential
$picPath = "\\server\share\pic.jpg"
$uri = http://website/sub/destination

Invoke-WebRequest -uri $uri -Method Put -Infile $picPath -ContentType 'image/jpg' -Credential $usercreds
TToni
  • 9,145
  • 1
  • 28
  • 42
  • If that is true and does work this should be a dupe. Would be nice to know what the error was the OP was getting. – Matt Feb 22 '17 at 15:30
  • He said "the file is not a valid image file." Totally logical with the use of `Get-Content` – TToni Feb 22 '17 at 15:32
  • He also said that he tried the method you are showing and got an error. – Matt Feb 22 '17 at 15:32
  • He probably used "Post" instead of "Put" which explains the second errormsg. – TToni Feb 22 '17 at 15:34
  • @TToni that seems to have worked. At least I'm on to a different error now. haha. Thanks for the help! I was using Post the when I had tried it before. Thanks again! – user3494277 Feb 22 '17 at 15:39
  • @TToni Does that mean the linked answer is wrong? Or just not what the OP needed in the case. – Matt Feb 22 '17 at 15:44
1

I've been trying for a day to get this working. My setup was a powershell script that was pushing a screenshot into a nodejs express api endpoint that was saving to the server. The above code almost worked, that is, the endpoint was hit and the file was saved, but the whatever was being saved wasn't the right encoding. I searched high and low for a solution, used multiple frameworks like multer, formidable, busboy etc. Tried various methods that involved building up the body for a multipart form, but with the same results.

What worked in the end for me (in case anyone else is reading) was to send it as base64 data and convert it on the other end because something wasn't going right with the encoding and I couldn't work it out.

Powershell script ($path and $uri are as above, nothing different)

$base64Image = [convert]::ToBase64String((get-content $path -encoding byte))
Invoke-WebRequest -uri $uri -Method Post -Body $base64Image -ContentType "application/base64"

Nodejs Express


app.post("/api/screenshot/", (req,res) => {
    let body = '';
    req.on('data', chunk => {
        body += chunk.toString();
    });
    req.on('end', () => {
      fs.writeFile(__dirname + '/public/images/a.jpg', body,'base64',function(err) {
        if( err ) {
          res.end('not okay');
        } else {
          res.end('ok');
        }
      });
    });
});

Probably more inefficient, but I needed to get something working.

Jarrod McGuire
  • 523
  • 5
  • 11
  • Just to note: Once I got the above working, I would assume that it would also work again alongside whatever middleware is in place. I think the issue was not with the request parsing, but somehow with the journey between powershell and http, but the knowledge escapes me. My journey to this point was circuitous, and I can't really be bothered updating unless I have to. – Jarrod McGuire Feb 18 '19 at 09:52
  • 1
    Thanks for your solution, (get-content $path -encoding byte) is very slow. Instead I used ([System.IO.File]::ReadAllBytes($ImagePath)). – Emir Husic May 29 '19 at 08:04