Invoke-WebRequest or Invoke-RestMethod?

So, you want to play with that shiny new ReST API you’ve discovered but in doing research on consuming ReST APIs with PowerShell you’ve discovered two different cmdlets.

Which one do I use? Which one is best? These are the same questions I had about 8 months ago.

Invoke-WebRequest

The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web service. It parses the response and returns collections of forms, links, images, and other significant HTML elements.

From Microsoft Documentation

Invoke-WebRequest is the multi-purpose cmdlet to use for web requests, it can talk to API’s, static pages, RSS feeds, etc. It doesn’t do any translation or conversion to the response it receives from the server.

$response = Invoke-WebRequest -Uri "https://www.binarymethod.com"
$response

StatusCode        : 200
StatusDescription : OK
Content           : <!DOCTYPE html>
                    ...
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    Strict-Transport-Security: max-age=31536000
                    Accept-Ranges: bytes
                    Content-Length: 21148
                    Content-Type: text/html
                    Date: Wed, 29 Jul 2020 14:28:22 GMT
                    ETag: "...
Forms             : {}
Headers           : {[Connection, keep-alive], [Strict-Transport-Security, max-age=31536000], [Accept-Ranges, bytes], [Content-Length, 21148]...}
Images            : {@{innerHTML=; innerText=; outerHTML=<img title="Home" alt="avatar" src="/images/avatar.png">; outerText=; tagName=IMG; title=Home; alt=avatar; src=/images/avatar.png}}
InputFields       : {}
Links             : {@{innerHTML=...}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 21148

This response contains the information you would expect during an HTTPs request/response exchange. You have the Status Code, Content, Header information and some other items that may prove useful. The content in this response is the raw HTML for the page, so you could potentially parse the html to pick out information.

Can I access a ReST API with Invoke-WebRequest

Yes! I actually prefer to use Invoke-WebRequest as it gives you the actual Response object which contains all the details you need. For example, some ReST APIs return ETags, or Pages in the Response Header. The below example access a very quick ReST API I wrote in Python using FastAPI.

$response = Invoke-WebRequest -Uri "http://127.0.0.1:8000/users/"
$response

StatusCode        : 200
StatusDescription : OK
Content           : [{"id":1,"name":"User Alpha","username":"usera"},{"id":2,"name":"User Omega","username":"usero"}]
RawContent        : HTTP/1.1 200 OK
                    Content-Length: 97
                    Content-Type: application/json
                    Date: Wed, 29 Jul 2020 14:35:28 GMT
                    Server: uvicorn
                    
                    [{"id":1,"name":"User Alpha","username":"usera"},{"id":2,"name":"User Omega...
Forms             : {}
Headers           : {[Content-Length, 97], [Content-Type, application/json], [Date, Wed, 29 Jul 2020 14:35:28 GMT], [Server, uvicorn]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 97

The information we want from the API is within the Content property

$response.Content
[{"id":1,"name":"User Alpha","username":"usera"},{"id":2,"name":"User Omega","username":"usero"}]

Great we have the response content but how do we use it. Most ReST API’s return data in JSON, luckily PowerShell supports JSON and we can get the actual data object by converting from JSON like so

$data = $response.Content | ConvertFrom-Json
$data

id name       username
-- ----       --------
 1 User Alpha usera   
 2 User Omega usero

Invoke-RestMethod

The Invoke-RestMethod cmdlet sends HTTP and HTTPS requests to Representational State Transfer (REST) web services that returns richly structured data.

From Microsoft Documentation

Invoke-RestMethod is basicly a wrapper cmdlet around Invoke-WebRequest. Invoke-RestMethod does some automatic conversion for you. If the API you are consuming returns JSON then Invoke-RestMethod will return a PowerShell Object which is a result of JSON conversion.

$response = Invoke-RestMethod -Uri "http://127.0.0.1:8000/users/"
$response

id name       username
-- ----       --------
 1 User Alpha usera   
 2 User Omega usero

As you can see the $response variable is a PSObject you can start using right away, no need for a manual conversion.

Unfortunately the Status Code and Headers are missing, most times this is ok. It’s a standard that 200 is Ok, 201 is Created, 400 causes an error etc. It’s almost safe to assume when your command works and returns an object that all is ok. I only say almost because not everyone adheres to standards and there may be some off the wall edge cases. Headers are important because some APIs provide ETags to help with caching, a Pages header to tell how many pages of objects there are, or a more common one is API versioning/obsolete flags.

Can I access an HTML page with Invoke-RestMethod

Actually…you can! Invoke-RestMethod doesn’t do any conversion for the HTML content, just returns a string but this could still be useful depending on your use case.

$response = Invoke-RestMethod -Uri "https://www.binarymethod.com"
$response

<!DOCTYPE html>
<html lang="en">
    <head>
	<meta name="generator" content="Hugo 0.70.0" />
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title>Binarymethod</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
...

When to use Invoke-RestMethod over Invoke-WebRequest

My personal opinion is never, but I’m a control freak. I like having all the information Invoke-WebRequest provides, but telling you it’s the best way would not be honest. The best way is the way that fits the requirements of your script.

For example, my colleague Jordan Benzing recently pointed me at the API provided by ICanHazDadJoke. This is a perfect use case for Invoke-RestMethod!

Looking at the API Documentation you can see it’s a very straight forward API, no response headers to worry about, no odd ball status codes to take in to account. I would use Invoke-RestMethod for this like so

Invoke-RestMethod -Uri "https://icanhazdadjoke.com/" -Headers @{Accept = 'application/json'}

id     : FdN7wcxAskb
joke   : They're making a movie about clocks. It's about time
status : 200

Easy peasy, no fuss! This is the type of API Invoke-RestMethod is great for.

The API provided for Eve Online however, is not something I would use Invoke-RestMethod for. I would use Invoke-WebRequest for any endpoint I consume.

I hope this helps clear up some of the confusion about when to use Invoke-WebRequest or Invoke-RestMethod. Invoke-RestMethod is perfect for quick APIs that have no special response information such as Headers or Status Codes, whereas Invoke-WebRequest gives you full access to the Response object and all the details it provides.


By Tim Davis

I spent my career before Truesec ensuring small financial institutions could meet the demands of todays security standards. I realized that exposure was just the tip of the iceberg and the world of IT security had much more to teach me. I love troubleshooting, finding problems, and being able to bring them to a resolution.

My true passion is programming. I spend my free time writing software for Eve Online and supporting existing deployments. I love learning new programming languages and seeing how I can use it at Truesec.