The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Deserialize an API response | Invoke-RestMethod -Uri $Uri -Method Get | View examples |
| Inspect an HTTP response | $Response = Invoke-WebRequest -Uri $Uri -Method Get | View examples |
| Encode GET query values | Invoke-RestMethod -Uri $Uri -Method Get -Body @{ q = `
'blue widget'; page = 2 } | View examples |
| Serialize JSON deliberately | $Json = @{ name = 'widget'; enabled = $true } |
ConvertTo-Json -Depth 10 -Compress | View examples |
| Post UTF-8 JSON | Invoke-RestMethod -Uri $Uri -Method Post -Body $Json `
-ContentType 'application/json; charset=utf-8' | View examples |
| Request a response media type | Invoke-RestMethod -Uri $Uri -Headers @{ Accept = `
'application/json' } | View examples |
| Prompt for a bearer token | Invoke-RestMethod -Uri $Uri -Authentication Bearer `
-Token (Read-Host -AsSecureString) | View examples |
| Capture a web session | Invoke-WebRequest -Uri $Uri -SessionVariable ApiSession | View examples |
| Reuse cookies and session state | Invoke-RestMethod -Uri $Uri -WebSession $ApiSession | View examples |
| Use a client certificate | Invoke-RestMethod -Uri $Uri -Certificate (Get-Item `
"Cert:\CurrentUser\My\$Thumbprint") | View examples |
| Constrain the TLS protocol | Invoke-RestMethod -Uri $Uri -SslProtocol Tls12 | View examples |
| Use an explicit proxy | Invoke-RestMethod -Uri $Uri -Proxy `
'https://proxy.example.com:8443' | View examples |
| Follow bounded relation links | Invoke-RestMethod -Uri $Uri -FollowRelLink `
-MaximumFollowRelLink 5 | View examples |
| Capture status and headers | Invoke-RestMethod -Uri $Uri -StatusCodeVariable Status `
-ResponseHeadersVariable Headers | View examples |
| Retry a bounded request | Invoke-RestMethod -Uri $Uri -MaximumRetryCount 3 `
-RetryIntervalSec 2 | View examples |
| Bound connection and idle reads | Invoke-RestMethod -Uri $Uri -ConnectionTimeoutSeconds 10 `
-OperationTimeoutSeconds 30 | View examples |
| Cancel a request job | Stop-Job -Job $RequestJob | View examples |
| Download to an exact path | Invoke-WebRequest -Uri $Uri -OutFile '.\artifact.zip' | View examples |
| Resume a partial download | Invoke-WebRequest -Uri $Uri -OutFile `
'.\artifact.zip.part' -Resume | View examples |
| Calculate a SHA-256 digest | (Get-FileHash -LiteralPath '.\artifact.zip' -Algorithm `
SHA256).Hash | View examples |
| Process HTTP error bodies | Invoke-RestMethod -Uri $Uri -SkipHttpErrorCheck `
-StatusCodeVariable Status | View examples |
| Catch request failures | try { Invoke-RestMethod -Uri $Uri -ErrorAction Stop } `
catch { Write-Error $_ } | View examples |
| Use safe Windows PowerShell parsing | Invoke-WebRequest -UseBasicParsing -Uri $Uri | View examples |
| Invoke native curl explicitly | curl.exe --fail --output artifact.zip `
https://example.com/artifact.zip | View examples |
PowerShell's web cmdlets cover both object-oriented REST calls and lower-level response inspection. Reliable automation makes the HTTP contract explicit: encode inputs, set the intended media type, keep credentials out of source and logs, validate TLS, bound pagination and waits, retry only operations that can be repeated safely, and treat downloaded bytes as untrusted until their identity is verified.
Step by step
Detailed examples
Choose objects or response control
Invoke-RestMethod is the natural default for JSON and XML APIs because it deserializes supported response bodies. Invoke-WebRequest returns a response wrapper whose StatusCode, Headers, Content, RawContent, and download options are useful when the wire response matters. In PowerShell 7, HTML handling is basic rather than a browser DOM. One subtle pipeline rule remains important: when Invoke-RestMethod receives a JSON array, it can write that array as one pipeline object; use parentheses or Write-Output when downstream commands must enumerate every member.
$ApiUri = 'https://api.example.com/v1/widgets'
$Items = Invoke-RestMethod -Uri $ApiUri -Method Get
$Items | Write-Output | Select-Object -Property id, name
$Response = Invoke-WebRequest -Uri $ApiUri -Method Head
[pscustomobject]@{
Status = $Response.StatusCode
ContentType = $Response.Headers['Content-Type']
} Encode the request contract explicitly
For a GET request, a dictionary supplied to Body is URL-encoded and added to the URI as query parameters. This avoids hand-concatenating spaces, ampersands, and other reserved characters, although array and nested-value conventions still depend on the API. For JSON, serialize the object yourself, choose enough ConvertTo-Json depth for the model, and set ContentType rather than relying on method-dependent defaults. PowerShell 7.4 changed the default request encoding to UTF-8 and makes ContentType take precedence if Headers also contains Content-Type, so specifying a charset produces clearer cross-version behavior.
$BaseUri = 'https://api.example.com/v1/widgets'
$Query = @{
q = 'blue widget'
page = 2
}
$Matches = Invoke-RestMethod -Uri $BaseUri -Method Get -Body $Query
$Payload = @{
name = 'blue widget'
tags = @('new', 'fragile')
} | ConvertTo-Json -Depth 10
$Created = Invoke-RestMethod -Uri $BaseUri -Method Post `
-Body $Payload -ContentType 'application/json; charset=utf-8' Keep credentials out of source, history, and diagnostics
Use Headers for ordinary negotiation metadata and a supported authentication parameter for secrets. In PowerShell 7, Authentication Bearer with Token accepts a SecureString, allowing an interactive prompt or secret provider to supply the token without a literal in the script. Do not print splatted parameters, sessions, headers, verbose traces, or exception bodies until they have been reviewed for tokens and personal data. Authentication and Token are unavailable in Windows PowerShell 5.1; if compatibility requires an Authorization header, retrieve its value at runtime from an approved secret store and keep it out of command-line arguments and logs. Credentials are rejected over plain HTTP by default in PowerShell 7.
$Token = Read-Host 'API token' -AsSecureString
$Headers = @{
Accept = 'application/json'
}
try {
Invoke-RestMethod -Uri 'https://api.example.com/v1/profile' `
-Authentication Bearer -Token $Token -Headers $Headers
}
finally {
$Token.Dispose()
Remove-Variable -Name Token
} Note: For unattended automation, replace the prompt with an approved secret provider that returns a SecureString.
Scope cookies to a deliberate session
SessionVariable creates a WebRequestSession in a variable whose name is supplied without a dollar sign. WebSession reuses that object on subsequent calls; the two parameters cannot be used together on one request. Sessions can contain authentication cookies, credentials, headers, proxy settings, and a user agent, so keep them in memory only as long as needed and never serialize them into diagnostics. Verify the destination before reusing a session, especially when an API returns an absolute next-page or redirect URI.
$BaseUri = 'https://api.example.com'
Invoke-WebRequest -Uri "$BaseUri/session" -SessionVariable ApiSession | Out-Null
try {
Invoke-RestMethod -Uri "$BaseUri/v1/profile" -WebSession $ApiSession
}
finally {
Remove-Variable -Name ApiSession -ErrorAction SilentlyContinue
} Preserve server identity through TLS and proxies
HTTPS protects credentials only when certificate validation remains enabled. Do not normalize SkipCertificateCheck: it disables expiration, revocation, trust-chain, and hostname protections. Install the correct internal CA instead. Certificate accepts an X.509 object for mutual TLS; CertificateThumbprint is Windows-only. PowerShell 7 can use proxy environment variables or explicit Proxy and NoProxy parameters, while Windows PowerShell 5.1 behavior differs. Treat proxy credentials as secrets. Authorization is stripped on redirects by default in PowerShell 7; preserve it only after proving the redirect target is in the same trust boundary.
$Thumbprint = 'REPLACE_WITH_REVIEWED_THUMBPRINT'
$Certificate = Get-Item -LiteralPath "Cert:\CurrentUser\My\$Thumbprint"
Invoke-RestMethod -Uri 'https://api.example.com/v1/secure' `
-Certificate $Certificate -SslProtocol Tls12 Bound pagination and validate every next link
FollowRelLink understands Link response headers and MaximumFollowRelLink caps how many additional relation links are followed. APIs that return cursors or next URLs in the body need an explicit loop. Bound both the page count and collected data, detect repeated cursors, and reject a next URL whose scheme or authority (host and effective port) crosses the intended trust boundary before reusing credentials. ResponseHeadersVariable and StatusCodeVariable accept bare variable names and make rate-limit and pagination metadata available without replacing the body result.
$Origin = [uri]'https://api.example.com/'
$Next = [uri]'https://api.example.com/v1/widgets?limit=100'
$Seen = [System.Collections.Generic.HashSet[string]]::new()
for ($Page = 1; $Next -and $Page -le 20; $Page++) {
if ($Next.Scheme -ne $Origin.Scheme -or $Next.Authority -ne $Origin.Authority) {
throw "Rejected pagination target: $Next"
}
if (-not $Seen.Add($Next.AbsoluteUri)) { throw 'Pagination cycle detected' }
$Result = Invoke-RestMethod -Uri $Next -Method Get
$Result.items
$Next = if ($Result.next) { [uri]::new($Origin, [string]$Result.next) } else { $null }
}
if ($Next) { throw 'Pagination exceeded 20 pages' } Bound waits, retries, and cancellation
MaximumRetryCount retries HTTP status codes from 400 through 599, plus 304, so it is broader than a transient-error-only policy. Use it primarily for idempotent reads or writes protected by a server-supported idempotency key; a retry can duplicate a POST after an ambiguous failure. For 429 responses with Retry-After, the cmdlet honors the server delay over RetryIntervalSec. In PowerShell 7.4+, ConnectionTimeoutSeconds bounds how long the request can remain pending, although DNS resolution can still take about 15 seconds, and OperationTimeoutSeconds bounds idle gaps between stream reads rather than total transfer duration. Earlier versions expose TimeoutSec without the separate operation timeout. The web cmdlets expose no CancellationToken parameter; Ctrl+C handles interactive cancellation, while automation can isolate a synchronous request in a job and stop it under an outer deadline.
$Uri = 'https://api.example.com/v1/health'
$RequestJob = Start-Job -ScriptBlock {
Invoke-RestMethod -Uri $using:Uri -Method Get `
-ConnectionTimeoutSeconds 10 -OperationTimeoutSeconds 30 `
-MaximumRetryCount 3 -RetryIntervalSec 2
}
try {
Wait-Job -Job $RequestJob -Timeout 120 | Out-Null
if ($RequestJob.State -notin @('Completed', 'Failed')) {
Stop-Job -Job $RequestJob
throw 'Request exceeded the 120-second workflow deadline'
}
Receive-Job -Job $RequestJob -ErrorAction Stop
}
finally {
Remove-Job -Job $RequestJob -Force -ErrorAction SilentlyContinue
} Stage downloads and verify identity before use
OutFile writes bytes directly to a literal path and does not also return them unless PassThru is present. Download into a staging name, then compare SHA-256 with a value obtained through the publisher's trusted release channel before moving the file into place. Resume, available since PowerShell 6.1, is only a best-effort size comparison; it does not prove the local prefix belongs to the current remote object. A successful HTTPS transfer authenticates the connection, not the artifact's release identity.
$Uri = 'https://example.com/releases/artifact.zip'
$Staging = Join-Path $env:TEMP 'artifact.zip.part'
$Destination = Join-Path $PWD 'artifact.zip'
$ExpectedSha256 = 'REPLACE_WITH_PUBLISHER_SHA256'
Invoke-WebRequest -Uri $Uri -OutFile $Staging
$ActualSha256 = (Get-FileHash -LiteralPath $Staging -Algorithm SHA256).Hash
if ($ActualSha256 -ne $ExpectedSha256) {
Remove-Item -LiteralPath $Staging -Force
throw "Artifact digest mismatch: $ActualSha256"
}
Move-Item -LiteralPath $Staging -Destination $Destination Note: Obtain the expected digest independently from the publisher; do not trust a hash downloaded from the same unverified location.
Separate HTTP status from transport failure
By default, non-success HTTP responses become terminating errors. PowerShell 7's SkipHttpErrorCheck instead writes the error response to the pipeline, and StatusCodeVariable makes an explicit status branch possible; it does not suppress DNS, TLS, timeout, or deserialization failures. For code that must also run on Windows PowerShell 5.1, use try/catch and inspect ErrorRecord. Exception response types differ between 5.1 and 7, and a connection failure may have no Response at all. Treat error bodies as untrusted and potentially sensitive before logging them.
$Body = Invoke-RestMethod -Uri 'https://api.example.com/v1/widgets/42' `
-SkipHttpErrorCheck -StatusCodeVariable Status `
-ResponseHeadersVariable ResponseHeaders
if ($Status -ge 400) {
$RequestId = $ResponseHeaders['Request-Id']
throw "API request failed with HTTP $Status; request ID $RequestId"
}
$Body try {
Invoke-RestMethod -Uri 'https://api.example.com/v1/widgets/42' -ErrorAction Stop
}
catch {
$Status = if ($_.Exception.Response) {
[int]$_.Exception.Response.StatusCode
} else {
$null
}
Write-Error "Request failed; HTTP status: $Status; category: $($_.CategoryInfo.Category)"
} Feature-test Windows PowerShell 5.1 and PowerShell 7
Windows PowerShell 5.1 uses legacy .NET web request types and Internet Explorer-based HTML parsing. After Microsoft's December 2025 security update, Invoke-WebRequest can prompt about script execution unless UseBasicParsing is supplied; use that switch for untrusted content. PowerShell 7 always uses basic HTML parsing, treats UseBasicParsing as a no-op, uses HttpClient response types, and has no ParsedHtml or Forms properties. Features such as Authentication, Token, SkipHttpErrorCheck, StatusCodeVariable, ResponseHeadersVariable, FollowRelLink, retries, Resume, and SslProtocol arrived after 5.1; the separate ConnectionTimeoutSeconds and OperationTimeoutSeconds parameters arrived in 7.4, with TimeoutSec retained as an alias for the former. Feature-test parameters when supporting multiple versions. Also, curl is an Invoke-WebRequest alias in 5.1 but not PowerShell 7; spell curl.exe when the native tool is intended.
$Command = Get-Command Invoke-RestMethod
$Parameters = @{
Uri = 'https://api.example.com/v1/health'
Method = 'Get'
}
if ($Command.Parameters.ContainsKey('StatusCodeVariable')) {
$Parameters.StatusCodeVariable = 'Status'
}
Invoke-RestMethod @Parameters Get-Command curl -ErrorAction SilentlyContinue | Select-Object Name, CommandType
curl.exe --fail --output artifact.zip https://example.com/artifact.zip Note: In Windows PowerShell 5.1, plain curl resolves to Invoke-WebRequest; PowerShell 7 does not define that alias.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- Microsoft LearnInvoke-RestMethodlearn.microsoft.com
- Microsoft LearnInvoke-WebRequestlearn.microsoft.com
- Microsoft LearnDifferences between Windows PowerShell 5.1 and PowerShell 7.xlearn.microsoft.com
- Microsoft LearnInvoke-WebRequest for Windows PowerShell 5.1learn.microsoft.com
- Microsoft Learncurl on Windowslearn.microsoft.com
- Microsoft LearnGet-FileHashlearn.microsoft.com
- Microsoft Learnabout_Splattinglearn.microsoft.com
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



