Skip to content

/compare/powershell/invoke-webrequest-vs-invoke-restmethod

Invoke-WebRequest vs Invoke-RestMethod: which one to use in PowerShell

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated
tool
PowerShell
compares
Invoke-WebRequest vs Invoke-RestMethod

Use Invoke-RestMethod for REST APIs: it parses a JSON (or XML) response into PowerShell objects, so $r.name works directly. Use Invoke-WebRequest when you need the HTTP details: it returns a response object with StatusCode, Headers and the raw Content string, and is the usual choice for HTML pages and downloads with -OutFile. Both send the same requests and accept the same main parameters (-Method, -Headers, -Body, -ContentType).

Same request, both cmdlets

A local Node.js server returns a small JSON document on 127.0.0.1:4500:

powershell
@'
require("http").createServer((req, res) => {
  res.setHeader("Content-Type", "application/json");
  res.end(JSON.stringify({ id: 7, name: "widget", tags: ["a", "b"] }));
}).listen(4500, "127.0.0.1");
setTimeout(() => process.exit(0), 6000);
'@ | Set-Content server.js
$server = Start-Process node -ArgumentList server.js -NoNewWindow -PassThru
Start-Sleep -Milliseconds 1000
$url = 'http://127.0.0.1:4500/item'
$web = Invoke-WebRequest -Uri $url -UseBasicParsing
"Invoke-WebRequest -> $($web.GetType().Name), StatusCode $($web.StatusCode), Content-Type $($web.Headers['Content-Type'])"
"Content: $($web.Content)"
$rest = Invoke-RestMethod -Uri $url
"Invoke-RestMethod -> $($rest.GetType().Name), name=$($rest.name), tags=$($rest.tags -join ',')"
"Same thing by hand: $(($web.Content | ConvertFrom-Json).name)"
$server.WaitForExit()

Output

Invoke-WebRequest -> BasicHtmlWebResponseObject, StatusCode 200, Content-Type application/json
Content: {"id":7,"name":"widget","tags":["a","b"]}
Invoke-RestMethod -> PSCustomObject, name=widget, tags=a,b
Same thing by hand: widget

Criterion by criterion

CriterionInvoke-WebRequestInvoke-RestMethod
Returnsresponse object (Content, StatusCode, Headers, RawContent)the parsed body: objects for JSON, XmlDocument for XML, string otherwise
JSONstring in .Content; pipe to ConvertFrom-Jsonalready converted
Status code and headers.StatusCode, .HeadersPowerShell 7: -StatusCodeVariable, -ResponseHeadersVariable; 5.1: not available
HTML pages.Links, .Images, .Forms (5.1 full parsing; limited in 7)raw HTML string
Download a file-OutFile file-OutFile file
Non-2xx statusthrows; PowerShell 7 has -SkipHttpErrorCheckthrows; PowerShell 7 has -SkipHttpErrorCheck
Paging (RSS, Atom, Link headers)noPowerShell 7: -FollowRelLink

Windows PowerShell 5.1: use -UseBasicParsing

In Windows PowerShell 5.1, Invoke-WebRequest without -UseBasicParsing parses the page with the Internet Explorer engine. On current Windows builds it also asks for confirmation before doing so, and in a non-interactive session (scheduled task, CI, powershell -NonInteractive) that prompt fails. This was observed on Windows 11 with Windows PowerShell 5.1.26100:

powershell
@'
require("http").createServer((req, res) => res.end("<html><body>ok</body></html>")).listen(4501, "127.0.0.1");
setTimeout(() => process.exit(0), 5000);
'@ | Set-Content server.js
$server = Start-Process node -ArgumentList server.js -NoNewWindow -PassThru
Start-Sleep -Milliseconds 1000
try { Invoke-WebRequest -Uri 'http://127.0.0.1:4501/' | Out-Null; 'no prompt' } catch { $_.Exception.Message }
(Invoke-WebRequest -Uri 'http://127.0.0.1:4501/' -UseBasicParsing).StatusCode
$server.WaitForExit()

Output

Windows PowerShell is in NonInteractive mode. Read and Prompt functionality is not available.
200

Add -UseBasicParsing to every Invoke-WebRequest in 5.1 scripts. In PowerShell 7 the parameter is accepted but has no effect: basic parsing is the only mode.

Sources