How to Leverage Invoke-RestMethod for More Powerful Scripting – Part 2

In our last post, we began to explore the Invoke-RestMethod cmdlet in PowerShell. We covered some of the basics, such as the components of the command, and how to build your REST API calls in PowerShell. Now it is time to start exploring a few of the next level topics related to REST API calls and PowerShell.

The two main topics of this post will be around pagination of results and creating functions to simplify calls you might make repeatedly. We will also look at a practical example of each so that it makes sense what we are talking about. I hope you are enjoying this series as much as I am. If not, then thanks for checking it out anyways. Let’s get started.

DISCLAIMER

Please understand that the content herein is for informational purposes only. This existence and contents shall not create an obligation, liability or suggest a consultancy relationship. In further, such shall be considered as is without any express or implied warranties including, but not limited to express and implied warranties of merchantability, fitness for a particular purpose and non-infringement. There is no commitment about the content within the services that the specific functions of the services or its reliability, applicability or ability to meet your needs, whether unique or standard. Please be sure to test this process fully before deploying in ANY production capacity, and ensure you understand that you are doing so at your own risk.

Table of Contents

How Do Functions Help with REST?
How to Paginate Results in PowerShell
Conclusion


How Do Functions Help with REST?

Function Basics

If you are not familiar with using functions in PowerShell, then you can think of them as a method for creating your own PowerShell cmdlets. A function is essentially a script-writer defined PowerShell object that is configured to carry out a specific task or set of tasks.

Just like Connect-Graph is a cmdlet written by Microsoft as a part of a specific module, functions are cmdlets written by the script writer to allow for a specific task to be repeated with the use of that cmdlet instead of the full amount of code each time. Let’s look at some examples:

In this example, we have a standard Invoke-RestMethod call that will return the specific results we are requesting.

Invoke-RestMethod -uri https://graph.microsoft.com/v1.0/sites/ -Headers @{Authorization = "Bearer $($Token.access_token)"} -Method Get

This line is simple enough, and if we only wanted to use it once in a script, it may be just fine on its own. However, what if we had a larger command that looked something like this:

$apiUrl = "https://api.dropboxapi.com/2/team/members/list_v2"
$headers = @{
            "Authorization" = "Bearer $accessToken"
            "Content-Type" = "application/json"
        }
$Data = @{
            "include_removed" = $false
            "limit" = 200
        }
$json = $data | ConvertTo-JSON
Invoke-RestMethod -Uri $apiURL -Headers $headers -Method POST -body $json

Now for the Function…

If we needed to use this multiple times, that would be a lot of redundant code that would take extra lines in the file, and also be more difficult to update at a later date. It leaves greater room for error and requires more maintenance and upkeep. Instead, with a function, we could have this as the call, and reuse a single line each time.

function Get-DropboxUsers {
    #gets all dropbox users as list
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory)]
        [string]$accessToken
    )
    begin {
        $headers = @{
            "Authorization" = "Bearer $accessToken"
            "Content-Type" = "application/json"
        }
        $Data = @{
            "include_removed" = $false
            "limit" = 200
        }
        $apiUrl = "https://api.dropboxapi.com/2/team/members/list_v2"
    }
    process {
        $json = $data | ConvertTo-Json
        $SheetData = Invoke-RestMethod -Uri $apiURL -Headers $headers -Method POST -Body $json
    }
    end {
        return $SheetData
    }
}

########################### TO Call this function we need the below line
Get-DropboxUsers $accessToken
So functions allow us to do a few things:
  • Simplify code that is reused by having it all located in a single location
  • Reuse code without having multiple instances of duplicate code
  • Keep our code neater, cleaner and easier to read

Often times you need to create a loop to paginate through all the results your REST API call. Or your script may contain a wider range of information and processes, and yet a single part needs to perform a REST call for specific information. Functions allow you to simplify your code, and we will be using some of them with pretty regularly with Invoke-RestMethod.


How to Paginate Results in PowerShell

What is Pagination?

So for starters, you may be wondering what pagination is. With REST, API providers may want to limit the number of results that are returned with a single query, to manage demand on resources. For example, if you were trying to return the members of a group in Microsoft Graph, the default is 100 results per query unless you indicate a specific number or indicate that you would like ALL in the same query.

However, many REST API’s will not allow you to exceed the maximum number no matter what. Instead, they will indicate in the results, that there is a page two where you can retrieve more information.

Pagination then is looping a REST API query to multiple pages to pull all of the information of a given query. Depending on the REST API, it may require a second API call that includes an additional set of data in the body, or the URI itself may change. Each API is different, so you must read the documentation. (I’ll say it until I’m blue in the face!).

What about Invoke-RestMethod -FollowRelLink?

If you look at the documentation, for Invoke-RestMethod, it includes a parameter (-FollowRelLink) to allow for automatic pagination of results. This parameter only works with some REST APIs, and isn’t an immediate standard. Even MS Graph doesn’t follow this standard. They require the use of ‘@odata.nextlink’ to continue returning results. (Detailed HERE).

Because of this, it is useful to do some testing. Using some basic API calls, see if you can return results beyond the first page. If it works, great, you save yourself some extra scripting to get all the information. However, it is important to have an understanding of pagination for the times it doesn’t work.

Basic Script for Pagination in MS Graph

MS Graph is a good example because it is so widely used, and many admins may already work in a Microsoft environment and have existing PowerShell skills. After retrieving the access token, I can run this snippet and get these results:

function Get-GroupList {
    [CmdletBinding()]
    Param (
        
    )
    begin {
        $headers = @{
            Authorization = "$($connection.token_type) $($connection.access_token)"
            ContentType  = "application/json"
        }
        $apiUrl = "https://graph.microsoft.com/v1.0/groups"
    }
    process {
        $SheetData = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Get
    }
    end {
        return $SheetData
    }
}

$groups = Get-GroupList 
$values = $groups.value

Write-Host "Collection Complete"
Write-Host $values.Count "Records Returned"

This results in 100 results.

number of records returned without proper pagination durign invoke-restmethod

Now if I add a small section for Pagination, we can see we will get different results:

$more = $groups.'@odata.nextLink'

while ($null -ne $more) {
    $headers = @{
        Authorization = "$($connection.token_type) $($connection.access_token)"
        ContentType  = "application/json"
    }
    $groups2 = Invoke-RestMethod $more -Headers $headers
    $more = $groups2.'@odata.nextLink'
    $values2 = $groups2.value
    $values = $values + $values2
}

This results in 1568 results.

number of records returned with proper pagination durign invoke-restmethod

In case you are looking for the entire script, you can find it here on my GitHub: Powershell/Graph-PaginatedResultsExample.ps1


Conclusion

There you have it! We have covered the second part of this Invoke-RestMethod series. Pagination and Functions can both add additional capability to your scripts and allow for cleaner code. So far, I’ve focused primarily on GET methods, so the repeatability can be harder to imagine. However, as we continue along on this journey, we will start to get into more complicated scripting, which is where these ideas will begin to shine.

Learning new things is one of my favorite hobbies, and I am really digging spending time learning this stuff. I hope you enjoy it too and that you stick around as we continue this journey.

Leveraging RESTful API’s will help tremendously as the world becomes more connected and cloud based. You’ll be able to pull in more data, and make more intelligent scripts do the work that might otherwise take you significantly longer.

I love receiving feedback and look forward to hearing from you about this one. Be sure to come back for the next part as we continue to leverage Invoke-RestMethod for more powerful scripting! As always, hit me up on Twitter @SeeSmittyIT to let me know what you thought of this post. Thanks for reading!

Smitty

Curtis Smith works in IT with a primary focus on Mobile Device Management, M365 Apps, and Azure AD. He has certifications from CompTIA and Microsoft, and writes as a hobby.

View all posts by Smitty →