PowerShell: Invoke-RestMethod

Scenario

I want to write a function that will query an image site and download a picture so I can insert it into a blog post. After watching a local PowerShell User Group presentation on using Invoke-RestMethod, I decided to give it a try.

API Parameters

Invoke-RestMethod is a PowerShell utility specifically for quering web sites that use Representational State Transfer (REST) web services. It was introduced in PS 3.0 and is present through subsequent versions, including PS 7.0. In order to use this cmdlet, I needed a web site that provded a RESTful API. I chose Pixabay because it has an easy to understand API and provides free and royalty free stock photos and videos. Let us take a look at the API parameters.

ParameterTypeDescription
key (required)StringAPI Key, provided after you create an account
qStringA URL encoded search term. If omitted, all images are returned. This value may not exceed 100 characters.
langStringLanguage code of the language to be searched in.
idStringRetrieve individual images by ID.
image_typeStringFilter results by image type: “all”, “photo”, “illustration”, or “vector”.
orientationStringImage orientation. Can be : “all”, “horizontal”, or “vertical”.
categoryStringFilter results by category: backgrounds, fashion, nature, science, education, feelings, health, people, religion, places, animals, industry, computer, food, sports, transportation, travel, buildings, business, or music
min_widthIntegerMinimum image width.
min_heightIntegerMinimum image height.
colorStringFilter by color: “grayscale”, “transparent”, “red”, “orange”, “yellow”, “green”, “turquoise”, “blue”, “lilac”, “pink”, “white”, “gray”, “black”, “brown”
editors_choiceBooleanSelect images that have received an Editor’s Choice award. “true” or “false”
safesearchBooleanA flag indicating that only images suitable for all ages should be returned. “true” or “false”
orderStringHow the results should be ordered. “popular” or “latest”
pageIntegerReturned search results are paginated. This parameter selects the page number.
per_pageIntegerNumber of results per page. Range 3 – 200
callbackStringJSONP callback function name
prettyBooleanIndent JSON output. This option should not be used in production. “true” or “false”

Function Parameters

Now that I know the API parameters, I can decide what parameters to pass to my function. I need to pass a query for the type of images. I would also like to pick the category, a color (optional), and the API Key that I got when I created an account. Here is my function Param block:

param (
        [parameter(Position = 0, Mandatory = $True )]   
        [ValidateNotNullOrEmpty()]
        [string]$query,

        [Parameter(Mandatory = $true)]
        [ValidateSet("backgrounds", "fashion", "nature", "science", "education", "feelings", "health", "people", "religion", "places", "animals", "industry", "computer", "food", "sports", "transportation", "travel", "buildings", "business", "music")]
        $category,

        [Parameter(Mandatory = $false)]
        [ValidateSet("grayscale", "transparent", "red", "orange", "yellow", "green", "turquoise", "blue", "lilac", "pink", "white", "gray", "black", "brown")]
        $color,

        #Pixabay apikey
        [parameter(Mandatory = $true)]
        [string]$apikey
    )

I made the $query$category, and $apikey parameters mandatory and the $color optional (the API supports sending colors as a comma separated list if you wanted more than one color in your image, but we’ll keep it to one for this function). Since Pixabay listed the accepted values for categories and colors, we can make these parameters use a ValidateSet. A ValidateSet forces the parameter to come from a specific set of values. If the parameter does not match, then the function will fail.

Example

 function get-color {
    param (
        [parameter()]
        [ValidateSet("blue","red")]
        $color
    )
    write-host $color -BackgroundColor $color
}

PS > get-color -color blue
blue

PS > get-color -color red
red

PS > get-color -color black
get-color : Cannot validate argument on parameter 'color'. The argument "black" does not belong 
to the set "blue,red" specified by the ValidateSet attribute. Supply an argument that is in the 
set and then try the command again.
At line:1 char:18
+ get-color -color black
+                  ~~~~~
    + CategoryInfo          : InvalidData: (:) [get-color], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,get-color

Splat Attack

Available since PowerShell 2.0, splating is a great way to simplify your scripts. The next part of our function will create splats to send all these variables to the invoke-restmethod cmdlet.

if ($null -ne $color) {
    $Body = @{
        key         = $apikey
        q           = $URLSearch
        category    = $category
        lang        = "en"
        image_type  = "photo"
        orientation = "horizontal"
        safesearch  = $true
    }
} else {
    $Body = @{
        key         = $apikey
        q           = $URLSearch
        category    = $category
        lang        = "en"
        image_type  = "photo"
        orientation = "horizontal"
        safesearch  = $true
        color       = $color
    }
}

$splat = @{
    URI    = "https://pixabay.com/api/"
    Method = "Get"
    Body   = $Body
}

The reason I want to use splatting is that both invoke-restmethod and the Pixabay API have a lot of parameters. It also makes code easier to read and modify in the future. I am going to first create a $body Hash Table. The $body may have the additional $color parameter if one is present. We assign the values to the keys in the hash table using the API parameters for the Keys and the function parameters for the Values. Some of the Values are preset based on the API. I am presetting langimage_typeorientation, and safesearch. Once the values of the $body are set, I create a $splat hash table that consists of the URI (API URL), the Method (the method used for the web request, the most common ones being get and post), and the Body which comes from the $body hash table.

Getting Results

Now we can use the the splats to query the Pixabay API. We use a Try/Catch command to have an error check on the Invoke-RestMethod.

try {
    $pixabay_query = Invoke-RestMethod @splat
} catch {
    Write-Warning "Failed to query Pixabay"
    break
}

The rest of the function takes the results, randomly picks from the results (Pixabay returns 20 images as a default) and uses an Invoke-WebRequest to download the image.

if ($pixabay_query.totalHits -eq 0) {
    Write-Warning "No query results"
    Break
} else {
    $picPath = Split-Path -parent $PSCommandPath
    Write-Verbose "Filepath: [$PSScriptRoot]"
    # Default items per page from pixabay is 20
    $randomHit = Get-Random -Minimum 1 -Maximum 20
    $img = $pixabay_query.hits[$randomHit]
    Invoke-WebRequest -Uri $img.webformatUrl -OutFile $picPath\$picFilename
}   

The entire function…

function get-pixabayImage {
    [CmdletBinding()]
    param (
        [parameter(Position = 0, Mandatory = $True )] 	
        [ValidateNotNullOrEmpty()]
        [string]$query,

        [Parameter(Mandatory = $true)]
        [ValidateSet("backgrounds", "fashion", "nature", "science", "education", "feelings", "health", "people", "religion", "places", "animals", "industry", "computer", "food", "sports", "transportation", "travel", "buildings", "business", "music")]
        $category,

        [Parameter(Mandatory = $false)]
        [ValidateSet("grayscale", "transparent", "red", "orange", "yellow", "green", "turquoise", "blue", "lilac", "pink", "white", "gray", "black", "brown")]
        $color,

        #Pixabay apikey - https://pixabay.com/api/docs/
        [parameter(Mandatory = $true)]
        [string]$apikey
    )
    
    $picFilename = (Get-Date).tostring("dd-MM-yyyy-hh-mm-ss")
    $picFilename = $picFilename + ".jpg"

    #Reform query to URL encoded search term
    $URLSearch = $query.Replace(" ", "+")

    if ($null -ne $color) {
        $Body = @{
            key         = $apikey
            q           = $URLSearch
            category    = $category
            lang        = "en"
            image_type  = "photo"
            orientation = "horizontal"
            safesearch  = $true
        }
    }
    else {
        $Body = @{
            key         = $apikey
            q           = $URLSearch
            category    = $category
            lang        = "en"
            image_type  = "photo"
            orientation = "horizontal"
            safesearch  = $true
            color       = $color
        }
    }

    $splat = @{
        URI    = "https://pixabay.com/api/"
        Method = "Get"
        Body   = $Body
    }

    try {
        $pixabay_query = Invoke-RestMethod @splat
    }
    catch {
        Write-Warning "Failed to query Pixabay"
        break
    }
     
    if ($pixabay_query.totalHits -eq 0) {
        Write-Warning "No query results"
        Break
    }
    else {
        $picPath = Split-Path -parent $PSCommandPath
        Write-Verbose "Filepath: [$PSScriptRoot]"
        # Default items per page from pixabay is 20
        $randomHit = Get-Random -Minimum 1 -Maximum 20
        $img = $pixabay_query.hits[$randomHit]
        Invoke-WebRequest -Uri $img.webformatUrl -OutFile $picPath\$picFilename
    }   
}

Conclusion

This function worked exactly as I wanted. I used it to retrieve the picture at the top of this post. I hope you have seen something you can use in the future. Please leave a comment if you have any questions.

Learning More

Value for Value

If you received any value from reading this post, please help by becoming a supporter.

Thanks for Reading,
Alain Assaf

About the Author:

Alain Assaf is a technology professional who’s worked in IT for over 20 years. For much of that time, he’s focused on virtualization platforms from Citrix, VMware, and Microsoft and several related technologies to automate, monitor, and manage the end-user experience. He’s a Citrix Certified Expert in Virtualization. Since 2017, he’s been a participant in the Citrix Technology Advocates Program and he’s also a leader of the Raleigh-Durham Citrix User Group. You can view his LinkedIn Profile for more information and follow him on Twitter. He also maintains several PowerShell repositories on GitHub.

Reference:

Assaf, A. (2020). PowerShell: Invoke-RestMethod. Available at: https://alainassaf.github.io/2020-04-22-Powershell-Invoke-RestMethod/ [Accessed: 19th February 2021].

Share this on...

Rate this Post:

Share: