Public/Invoke-XKCD.ps1

using namespace System.IO
using namespace System.Net.Http
using namespace System.Net.Http.Headers

function Invoke-XKCD {
    [Alias("xkcd")]
    [OutputType([XKCD])]
    [CmdletBinding(DefaultParameterSetName = "Last", SupportsShouldProcess, ConfirmImpact = "Low")]
    param(
        [Parameter(Mandatory, ParameterSetName = "All")]
        [switch] $All,

        [Parameter(Mandatory, ParameterSetName = "Number")]
        [int[]] $Number,

        [Parameter(Mandatory, ParameterSetName = "Random")]
        [switch] $Random,

        [Parameter(Mandatory, ParameterSetName = "Range")]
        [ValidateRange(1, [int]::MaxValue)]
        [int] $From,

        [Parameter(Mandatory, ParameterSetName = "Range")]
        [ValidateScript({
            if ($_ -le $From) {
                Write-Error "The value of -To must be greater than -From" -Category InvalidArgument -ErrorAction Stop
            }

            return $true
        })]
        [int] $To,

        [Parameter(ParameterSetName = "Last")]
        [int] $Last = 1,

        [string] $Path = $PWD.Path,

        [switch] $Download,

        [switch] $Force
    )

    begin {
        # The Info response contains the following data:
        #
        # ======================================================================
        # KEY TYPE NULLABLE REMARKS
        # ======================================================================
        # year int year of publication
        # month int month of publication
        # day int day of publication
        # num int running number of comic
        # title string title of website
        # safe_title string ASCII-friendly title
        # alt string alt text on image
        # link string X ?
        # img string DDL to comic
        # news string X ?
        # transcript string X ?
        # ======================================================================
        $Info = if (!$MyInvocation.BoundParameters.ContainsKey("Number") -or $null -eq $Number) {
            Invoke-RestMethod -Uri "https://xkcd.com/info.0.json"
        }

        [int[]] $Ids = switch ($PSCmdlet.ParameterSetName) {
            "All" {
                @(1..$Info.Num)
            }
            "Number" {
                $Number
            }
            "Random" {
                @([System.Random]::Shared.Next(1, $Info.Num))
            }
            "Range" {
                @($From..$To)
            }
            "Last" {
                @(($Info.Num - $Last + 1)..$Info.Num)
            }
            default {
                1
            }
        }
    }
    process {
        for ([int] $i = 0; $i -lt $Ids.Count; $i++) {
            $Id = $Ids[$i]

            try {
                $Response = Invoke-RestMethod -Uri "https://xkcd.com/$Id/info.0.json"
                $FileExtension = $Response.Img.Split("/")[-1].Split(".")[1]
                $FilePath = [Path]::Combine($Path, "${Id}.${FileExtension}")
                Write-Host "test $id"

                if ($Download.IsPresent -and $PSCmdlet.ShouldProcess($Response.img, "Download $($FilePath)")) {
                    [int] $PercentComplete = [Math]::Round($i / $Ids.Count * 100, 0)

                    Write-Progress -Activity "Download XKCD ${Id}" `
                        -Status "${PercentComplete}%" `
                        -PercentComplete $PercentComplete

                    Write-Verbose "Downloading $Id to $Path"
                    Invoke-WebRequest -Uri $Response.img -OutFile $FilePath
                }

                Write-Output $([XKCD]::new(
                    $Id,
                    $Response.title,
                    $Response.alt,
                    $Response.year,
                    $Response.month,
                    $Response.day,
                    $Response.link
                ))
            } catch {
                Write-Error "A comic with ID = $ID does not exist." -Category InvalidArgument -ErrorAction Stop
            }
        }
    }
    clean {

    }
}