In part 2 we looked at Invoke-WebRequest. Today we focus on Invoke-RestMethod: this cmdlet performs the same tasks but focuses on the data: it recognizes the format and automatically returns appropriate objects.
For example, lets assume you want to find out where an obscure IP address is registered that you found in your logs. When you enter the URL below into your browser, you get back the registration information in a human-readable format:
Accessing Web Service
The same web server can also act as a web service; it simply changes the data type from HTML to a machine-readable format. Try this in your browser:
https://ipinfo.io/8.8.8.8/json
This time, you receive the information in JSON format:
{
"ip": "8.8.8.8",
"hostname": "dns.google",
"city": "Mountain View",
"region": "California",
"country": "US",
"loc": "37.4056,-122.0775",
"org": "AS15169 Google LLC",
"postal": "94043",
"timezone": "America/Los_Angeles",
"readme": "https://ipinfo.io/missingauth",
"anycast": true
}
Invoke-WebRequest
Invoke-WebRequest can retrieve any web data for you, so it can work with web services as well. However, you always receive the raw data:
$ip = '8.8.8.8'
$url = "https://ipinfo.io/$ip/json"
$result = Invoke-WebRequest -UseBasicParsing -Uri $url
The result looks exactly like in the browser before:
$ip = '8.8.8.8'
$url = "https://ipinfo.io/$ip/json"
$result = Invoke-RestMethod -UseBasicParsing -Uri $url
You would need to determine the content type yourself and then apply the appropriate conversion:
PS C:\> $result.Headers['Content-Type']
application/json; charset=utf-8
PS C:\> $formatted = $result.Content | ConvertFrom-Json
PS C:\> $formatted
ip : 8.8.8.8
hostname : dns.google
city : Mountain View
region : California
country : US
loc : 37.4056,-122.0775
org : AS15169 Google LLC
postal : 94043
timezone : America/Los_Angeles
readme : https://ipinfo.io/missingauth
anycast : True
PS C:\> $formatted.hostname
dns.google
PS C:\> $formatted.org
AS15169 Google LLC
PS C:\> $formatted | Select-Object -Property HostName, Org, Country
hostname org country
-------- --- -------
dns.google AS15169 Google LLC US
Invoke-RestMethod
Invoke-RestMethod detects the content type and then applies the appropriate conversion automatically. If you are after the data returned by a web service, it is the much more convenient option. You simply exchange the cmdlet name:
$ip = '8.8.8.8'
$url = "https://ipinfo.io/$ip/json"
$result = Invoke-RestMethod -UseBasicParsing -Uri $url
Now, you can directly work with the data and dont have to worry about content types or conversions:
PS C:\> $result
ip : 8.8.8.8
hostname : dns.google
city : Mountain View
region : California
country : US
loc : 37.4056,-122.0775
org : AS15169 Google LLC
postal : 94043
timezone : America/Los_Angeles
readme : https://ipinfo.io/missingauth
anycast : True
PS C:\> $result.hostname
dns.google
PS C:\> $result | Select-Object -Property HostName, Org, Country
hostname org country
-------- --- -------
dns.google AS15169 Google LLC US
Caveats and Tricks
The insight you just gained can be very helpful because the magic does not always work. For example, an administrator responsible for Lenovo servers wanted to make her life easier by automatically downloading the BIOS updates for her servers from Lenovo. They are publicly available right here:
https://download.lenovo.com/cdrt/td/catalogv2.xml
When you enter this URL into your browser, you see a huge XML data set. This is no different from the previous example: it is a machine-readable web service.
The admin selected Invoke-RestMethod to retrieve the information:
$Uri = 'https://download.lenovo.com/cdrt/td/catalogv2.xml'
$data = Invoke-RestMethod -Uri $Uri -UseBasicParsing
While this worked, unfortunately, the magic auto-conversion did not occur: the result was the same huge XML data set. Why?
Invoke-RestMethod tried to auto-convert the data but failed, and so would you. The conversion to XML would yield nothing.
PS C:\> $data -as [xml]
Invoke-RestMethod is only as good and capable as the data you receive. Upon closer examination, it turns out that Lenovo returns text with a few garbled bytes at the beginning:
PS C:\> $data.Substring(0,40)

Issues like this may occasionally occur and are caused by different types of text encoding. While Invoke-RestMethod cannot fix this, you can: once you remove the first five bytes, the XML conversion works as expected:
PS C:\> $xml = $data.Substring(5) -as [xml]
PS C:\> $xml.ModelList.Model
name Types BIOS SCCM
---- ----- ---- ----
ThinkCentre M715Q Types BIOS SCCM
ThinkCentre M715Q 2nd Gen Types BIOS {SCCM, SCCM, SCCM}
ThinkCentre M810Z Types BIOS {SCCM, SCCM}
ThinkCentre M625Q Types BIOS {SCCM, SCCM, SCCM}
ThinkCentre M630E Types BIOS {SCCM, SCCM}
ThinkCentre M710Q Types BIOS {SCCM, SCCM, SCCM}
...
In the end, the admin was able to automate the task with a remarkably short PowerShell script, selecting a Lenovo server, retrieving the download URL for the latest BIOS version, and downloading the binaries:
# web service url
$Uri = 'https://download.lenovo.com/cdrt/td/catalogv2.xml'
# get data and convert into correct format
$data = Invoke-RestMethod -Uri $Uri -UseBasicParsing
# fix the text encoding issue
[xml]$realData = $data.Substring(5)
# let the user select the server model
$selection = $realData.ModelList.Model |
# we care only about these two properties
Select-Object -Property Name, BIOS |
# retrieve the download URL from the nested property "#text" and move it up
ForEach-Object {
$_.BIOS = $_.BIOS.'#text'
$_
} |
Sort-Object -Property Name |
# let the user select one server type
Out-GridView -Title 'Select Server Type' -OutputMode Single
# this is what we got back
$url = $selection.BIOS
$modelname = $selection.Model -replace '\s','_'
# construct the local file name
$filename = Split-Path -Path $url -Leaf
$timestamp = Get-Date -Format 'yyyy-MM-dd'
$destinationPath = Join-Path -Path $env:temp -ChildPath "$timestamp-$modelname-$filename"
# use Invoke-WebRequest to perform the actual download
Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $destinationPath
# show the selected downloaded file in File Explorer
explorer /select,$destinationPath
Your ultimate PowerShell Cheat Sheet
Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets. The poster is available for download and in paper form.
Related links
- ScriptRunner ActionPacks provide ready-to-use PowerShell scripts.
- Try out ScriptRunner here
- ScriptRunner: Book a demo with our product experts