PowerShell: Working with JSON & APIs Using Invoke-RestMethod
PowerShell's Invoke-RestMethod cmdlet is a powerful tool for interacting with RESTful APIs, enabling you to send HTTP/HTTPS requests, handle JSON responses, and manage authentication. This blog post explores how to use Invoke-RestMethod to work with APIs, parse JSON efficiently, and handle various authentication mechanisms, complete with practical examples.
Why Invoke-RestMethod?
Invoke-RestMethod simplifies API interactions by:
Sending HTTP methods (GET, POST, PUT, DELETE, etc.).
Automatically parsing JSON or XML responses into PowerShell objects.
Supporting headers, body payloads, and authentication.
Handling errors and response codes.
Let’s dive into the key aspects of working with APIs and JSON in PowerShell.
1. Making API Requests with Invoke-RestMethod
Invoke-RestMethod supports common HTTP methods via the -Method parameter. The basic syntax is:
Invoke-RestMethod -Uri <API-Endpoint> -Method <Get|Post|Put|Delete> [-Headers <Hashtable>] [-Body <Object>] [-Credential <PSCredential>]
Example: Fetching Data with a GET Request
Let’s query the public JSONPlaceholder API to retrieve a list of users:
$uri = "https://jsonplaceholder.typicode.com/users"
$response = Invoke-RestMethod -Uri $uri -Method Get
$response | Format-Table Name, Email -AutoSize
Output (truncated):
Name Email
---- -----
Leanne Graham Sincere@april.biz
Ervin Howell Shanna@melissa.tv
...
The API returns JSON, which Invoke-RestMethod automatically converts into a PowerShell object array, making it easy to access properties like $response[0].name.
2. Parsing JSON Efficiently
Since Invoke-RestMethod deserializes JSON into PowerShell objects, you can access data using dot notation or filter it with Where-Object, Select-Object, etc.
Example: Filtering and Selecting Data
Suppose you want only users from a specific city:
$uri = "https://jsonplaceholder.typicode.com/users"
$users = Invoke-RestMethod -Uri $uri -Method Get
$filteredUsers = $users | Where-Object { $_.address.city -eq "Gwenborough" } | Select-Object Name, Email, @{Name="City";Expression={$_.address.city}}
$filteredUsers | Format-Table -AutoSize
Output:
Name Email City
---- ----- ----
Leanne Graham Sincere@april.biz Gwenborough
Here, we:
Access nested JSON properties (address.city).
Create a custom property (City) using a calculated expression.
Filter and format the output.
Tip: Handling Large JSON Responses
For large JSON payloads, use Select-Object to extract only needed properties to reduce memory usage:
$users = Invoke-RestMethod -Uri $uri -Method Get | Select-Object Id, Name, Email
If the API returns raw JSON (e.g., when using Invoke-WebRequest), parse it manually with ConvertFrom-Json:
$rawJson = Invoke-WebRequest -Uri $uri | Select-Object -ExpandProperty Content
$parsed = $rawJson | ConvertFrom-Json
3. Sending Data with POST Requests
To send data to an API, use the -Body parameter with a hashtable or JSON string. Set the -ContentType to application/json for JSON payloads.
Example: Creating a New Post
Let’s create a post on JSONPlaceholder:
$uri = "https://jsonplaceholder.typicode.com/posts"
$body = @{
title = "My New Post"
body = "This is the content of my post."
userId = 1
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri $uri -Method Post -Body $body -ContentType "application/json"
$response
Output:
id title body userId
-- ----- ---- ------
101 My New Post This is the content... 1
Here, we:
Create a hashtable and convert it to JSON with ConvertTo-Json.
Send the POST request with the correct content type.
Receive the API’s response, including the assigned id.
4. Handling Authentication
APIs often require authentication, such as API keys, OAuth tokens, or basic credentials. Invoke-RestMethod supports several authentication methods.
Example: API Key Authentication
Many APIs require an API key in the query string or headers. Here’s how to use an API key with the OpenWeatherMap API (replace YOUR_API_KEY with a real key):
powershell
$apiKey = "YOUR_API_KEY"
$city = "London"
$uri = "https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey"
$response = Invoke-RestMethod -Uri $uri -Method Get
"Current temperature in $city: $($response.main.temp - 273.15)°C"
Output (example):
Current temperature in London: 15.32°C
Example: Basic Authentication
For APIs using basic auth, use the -Credential parameter:
$uri = "https://api.example.com/protected"
$credential = Get-Credential # Prompts for username/password
$response = Invoke-RestMethod -Uri $uri -Method Get -Credential $credential
Example: Bearer Token (OAuth)
For OAuth 2.0 APIs, include a Bearer token in the headers:
$token = "YOUR_ACCESS_TOKEN"
$uri = "https://api.github.com/user"
$headers = @{
Authorization = "Bearer $token"
}
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
"Logged in as: $($response.login)"
Output (example):
Logged in as: octocat
Tip: Storing Credentials Securely
Avoid hardcoding sensitive data. Use Get-Credential or store tokens in encrypted files:
# Save token securely
$token | ConvertTo-SecureString -AsPlainText -Force | Export-Clixml -Path "token.xml"
# Retrieve token
$secureToken = Import-Clixml -Path "token.xml" | ConvertFrom-SecureString -AsPlainText
5. Error Handling
APIs may return errors (e.g., 404, 401). Use try/catch to handle exceptions gracefully.
Example: Handling API Errors
$uri = "https://jsonplaceholder.typicode.com/invalid"
try {
$response = Invoke-RestMethod -Uri $uri -Method Get -ErrorAction Stop
}
catch {
$errorDetails = $_.Exception.Response | Select-Object -ExpandProperty StatusCode
Write-Error "API request failed with status code: $errorDetails"
}
Output:
API request failed with status code: NotFound
Check the response status code for more control:
$response = Invoke-WebRequest -Uri $uri -Method Get -SkipHttpErrorCheck
if ($response.StatusCode -eq 200) {
$data = $response.Content | ConvertFrom-Json
} else {
Write-Warning "Request failed with status: $($response.StatusCode)"
}
6. Advanced: Paginated APIs
Many APIs use pagination. You can handle this by looping through pages.
Example: Fetching Paginated Data
Suppose an API returns 10 items per page:
$baseUri = "https://api.example.com/items"
$page = 1
$allItems = @()
do {
$uri = "$baseUri?page=$page"
$response = Invoke-RestMethod -Uri $uri -Method Get
$allItems += $response.items
$page++
} while ($response.hasMore) # Assumes API indicates more pages
$allItems | Format-Table -AutoSize
Best Practices
Respect Rate Limits: Check API documentation for rate limits and implement delays if needed (Start-Sleep).
Validate Input: Sanitize inputs to prevent injection or malformed requests.
Log Errors: Save error details to a file for debugging (Write-Output | Out-File).
Use Splatting: For readability, use splatting for complex Invoke-RestMethod calls:
$params = @{
Uri = "https://api.example.com/data"
Method = "Get"
Headers = @{ "Authorization" = "Bearer $token" }
ContentType = "application/json"
}
$response = Invoke-RestMethod @params
Cache Responses: Store API responses locally to reduce redundant calls (Export-Clixml).
TLDR
Invoke-RestMethod makes working with APIs and JSON in PowerShell straightforward and efficient. By leveraging its ability to handle HTTP methods, parse JSON, and support various authentication mechanisms, you can build robust scripts for automation, data retrieval, and integration. Whether you’re fetching data, posting updates, or managing pagination, PowerShell’s flexibility empowers you to tackle API challenges with ease.
Try these examples with your favorite APIs, and let PowerShell simplify your API workflows! For more details, check the official PowerShell documentation.