To give you a bit of background, a REST API is an interface based on the HTTP protocol. You use one of four operations—Get, Post, Put, or Delete—with a string parameter in HTTP format. The strings look like URIs, but they don't refer to a web page. Instead, they provide the data for one of the four operations.

I didn't know how to call REST APIs in Windows PowerShell, so I asked Doug for help. Before we started, I asked Doug how to determine which websites have web services with REST interfaces. It turns out that this isn't a very straightforward task. You have to search online for the name of your favorite website or service and "REST API." Doug found YouTube and StackOverflow, and he pointed me to the ProgrammableWeb API search.

Doug suggested that we start with the Invoke-RestMethod cmdlet, which was introduced in Windows PowerShell 3.0, and YouTube, which has a well-documented REST API. I started here: YouTube API v2.0 – API Query Parameters. This page lists the parameters that you can include in a Get or query operation.

The syntax of the query string is:

https://gdata.youtube.com/feeds/api/videos?

…followed by a parameter and parameter value in key=value format.

For example, the instructions recommend that you include the v (version) parameter with a value of 2 to use the latest version of the REST API:

https://gdata.youtube.com/feeds/api/videos?v=2

To specify the query string (the text you are searching for), use a parameter of q (lower-case) and the search text. This query string searches for PowerShell:

https://gdata.youtube.com/feeds/api/videos?q=PowerShell

To search for multiple words, concatenate the words with a plus sign (+).

https://gdata.youtube.com/feeds/api/videos?q=Windows+PowerShell

To use multiple parameters, separate them with an ampersand (&). The following query string specifies v 2 and searches for PowerShell:

https://gdata.youtube.com/feeds/api/videos?v=2&q=Powershell

Now, to run the query in Windows PowerShell, use the Invoke-RestMethod cmdlet. The following command searches YouTube videos with PowerShell in the title.

That's much better! There's lots of other useful information, including the publication date and last updated date, comments, statistics, and ratings.

But before I turn you over to Doug to hear why this works, let me share one more tidbit. One of the parameters in the YouTube REST API is Max-Results. Its default value is 25, and its maximum value is 50.

It doesn't seem to work in Windows PowerShell 3.0. By default, it returns the first 13 hits. When we specified values of 5, 10, 30, and 50, we got only half of what we requested: 3, 5, 15, and 25.

No Tools No Problem Building a PowerShell Botnet Christopher @obscuresec Campbell

Creating HTML Reports with PowerShell

PowerShell Scripting Basics

PowerShell for common Office 365 Operations

Windows Powershell - What are The Top 10 Cmdlets to Start Using Immediately

Take note of how the ­title information is retrieved:

(Invoke-RestMethod $url).title.'#text'

The title data is stored in the #textproperty, but if you don’t enclose "#text" in quotation marks, Windows PowerShell interprets it as a comment because it begins with a # sign, and you will receive an error message.

Before Windows PowerShell delivered Invoke-RestMethod, we could reach into the .NET Framework and use the System.Net.WebClient class to grab this data ourselves:

Invoke-RestMethod does a lot for us. It connects and downloads the data from the target URL, converts the returned string into XML, and extracts the feed.entry information so we can use less .NET notation to get at what we want faster. A feed is a data format for providing frequently updated content. Invoke-RestMethod leverages this standard to make our lives easier.

But wait! There’s more…

Earthquake data and JSON

Invoke-RestMethod also automatically detects the type of data the URL returns. While REST is the predominate way to interact with data on the web, JavaScript Object Notation (JSON), a text-based standard for data interchange, is often used too.

Great news! The designers of Invoke-RestMethod also made it easy to interact with JSON REST feeds. Here's an Invoke-RestMethod command that gets earthquake data from Seismi.org. It returns JSON, but you don't need to know that. Windows PowerShell returns custom objects (PSCustomObject) that you can use in your commands.

You can use the WebClient class to build a command like this on your own. Prior to Windows PowerShell 3.0, you’d need to use a third-party .NET JSON parser or build your own. Windows PowerShell 3.0 introduced the ConvertFrom-Json cmdlet:

The results are much noisier than the out-of-the-box experience of Invoke-RestMethod. Plus, Invoke-RestMethod automatically detects whether XML or JSON is being returned, and it does the right thing—it returns Windows PowerShell objects for you to easily work on.

Invoke-RestMethod under the covers

Invoke-RestMethod is one of the Windows PowerShell 3.0 core cmdlets. It is written in C# and delivered in the Microsoft.PowerShell.Commands.Utility.dll. To examine it, I used a free tool from JetBrains, called DotPeek. This tool can look into the compiled DLL and decompile it to source code so you can browse it.

After reading the Invoke-RestMethod code, I asked the Windows PowerShell team to confirm my assumptions. Lee Holmes, author of the great book, Windows PowerShell Cookbook, 3rd Edition, replied, “If it looks like an RSS or ATOM feed, we process and return the elements in the feed. If the response says it returns some form of JSON (there are many), we will first try to convert it to JSON. If that fails, we will convert it to XML. If that fails, we return it as text.”

Here is a simplified Windows PowerShell version I came up with that I sent along with the question:

$url = "http://www.seismi.org/api/eqs"

$request = [System.Net.WebRequest]::Create($url)

$request.Method="Get"

$response = $request.GetResponse()

$requestStream = $response.GetResponseStream()

$readStream = New-Object System.IO.StreamReader $requestStream

$data=$readStream.ReadToEnd()

if($response.ContentType -match "application/xml") {

$results = $data

} elseif($response.ContentType -match "application/json") {

$results = $data | ConvertFrom-Json

} else {

try {

$results = $data

} catch {

$results = $data | ConvertFrom-Json

}

}

$results

These 23 lines of code give the same results for the earthquake data as the one-line that used Invoke-RestMethod. Thank you, Windows PowerShell team!

That’s a very simple overview of how YouTube and Seismi.org serve this information. The better news is that this is a web standard and many sources of data are available to you this way. Even better, Windows PowerShell makes working with this information a breeze.

Folks – while I like the examples, the part that consistently stimies me with this method is how to capture and pass the session information. I’m working with an API that causes a session to be created in step 1, and I need to capture this session and pass it back in step 2. I’ve tried these two lines unsuccessfully:

however, the command invariably fails with an ‘invalid session’ message or somesuch. I can use curl and the command prompt to capture and pass the session ID, but I thought the above approach would work. Please clue me in as to what I’m doing wrong – and thank you!

-SessionVariable
Creates a web request session and saves it in the value of the specified variable. Enter a variable name without
the dollar sign ($) symbol.

When you specify a session variable, Invoke-RestMethod creates a web request session object and assigns it to a
variable with the specified name in your Windows PowerShell session. You can use the variable in your session as
soon as the command completes.

Unlike a remote session, the web request session is not a persistent connection. It is an object that contains
information about the connection and the request, including cookies, credentials, the maximum redirection value,
and the user agent string. You can use it to share state and data among web requests.

To use the web request session in subsequent web requests, specify the session variable in the value of the
WebSession parameter. Windows PowerShell uses the data in the web request session object when establishing the new
connection. To override a value in the web request session, use a cmdlet parameter, such as UserAgent or
Credential. Parameter values take precedence over values in the web request session.

You cannot use the SessionVariable and WebSession parameters in the same command.

It makes sense to read it, but I can’t an example working. Do you know where there is a sample script using this functionality I could look at? I don’t seem to actually ever store a cookie when setting the session variable.

I have the smae issue as anonymous! I am trying to access Nessus data from our corporate scanning infrastructure via powershell. I can make a single login REST connection via the login page successfully. But none of the other REST pages will work for me.
Is ther an example somewhere online of a non public interface that shows how to authenticate, generate a cookie, and then perform additional requests on the same connection?