PoshGram.psm1

$script:assetPath = "$PSScriptRoot\asset\emoji.json"

<#
.Synopsis
    Evaluates if the provided URL is reachable
.DESCRIPTION
    Evaluates if the provided URL is reachable and returns a boolean based on results
.EXAMPLE
    Confirm-URL -Uri http://gph.is/2y3AWRU
 
    Determines if the provided URL is accessible and returns a boolean based on results
.PARAMETER Uri
    Uri you wish to resolve
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Confirm-URL {
    [CmdletBinding()]
    param (
        ## The URI to resolve
        [Parameter(Mandatory = $true,
            HelpMessage = 'Uri you wish to resolve')]
        [string]$Uri
    )
    $result = $true #assume the best
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    Write-Verbose -Message "Attempting to confirm $Uri"
    try {
        Invoke-WebRequest -Uri $uri -UseBasicParsing -DisableKeepAlive -ErrorAction Stop | Out-Null
        Write-Verbose -Message 'Confirmed.'
    } #try_Invoke-WebRequest
    catch {
        Write-Verbose -Message 'Catch on Invoke-WebRequest. This is not necessarily a bad thing. Checking status code.'
        if ([int]$_.Exception.Response.StatusCode -eq 0) {
            Write-Warning -Message "$Uri"
            Write-Warning -Message 'The URL provided does not appear to be valid'
            $result = $false
        }
        #we will proceed with any other exit code
    } #catch_Invoke-WebRequest
    return $result
} #Confirm-URL


<#
.Synopsis
    Resolve a URI to the URIs it redirects to
.DESCRIPTION
    Resolves a URI provided to the URI it redirects to. If no redirect is in place, null is returned. This is useful for resolving shortlinks to try url file paths.
.EXAMPLE
    Resolve-ShortLink -Uri http://gph.is/2y3AWRU
 
    Resolve shortlink to full URI
.PARAMETER Uri
    Uri you wish to resolve
.OUTPUTS
    System.String
    -or-
    Null
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Resolve-ShortLink {
    [CmdletBinding()]
    param (
        ## The URI to resolve
        [Parameter(Mandatory = $true,
            HelpMessage = 'Uri you wish to resolve')]
        [string]$Uri
    )
    $result = $null
    $a = $null
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    try {
        $a = Invoke-WebRequest -Uri $uri -MaximumRedirection 0 -ErrorAction Stop
    } #try_Invoke-WebRequest
    catch {
        #if($_.ErrorDetails.Message -like "*maximum redirection*"){
        if ($_.Exception.Message -like "*Moved*") {
            $a = $_
            Write-Verbose -Message 'Moved detected.'
            #$result = $a.Headers.Location
            $result = $a.Exception.Response.Headers.Location.AbsoluteUri
        } #if_Error_Moved
        else {
            Write-Warning -Message 'An Error was encountered resolving a potential shortlink:'
            Write-Error $_
        } #else_Error_Moved
    } #catch_Invoke-WebRequest
    return $result
} #Resolve-ShortLink


<#
.Synopsis
    Verifies that provided quiz explanation matches Telegram requirements.
.DESCRIPTION
    Evaluates if the provided quiz explanation meets the Telegram explanation requirements.
.EXAMPLE
    Test-Explanation -Explanation $explanation
 
    Verifies if the provided options meet the poll requirements.
.PARAMETER Explanation
    Quiz explanation text
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
    Telegram currently supports 0-200 characters with at most 2 line feeds after entities parsing
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-Explanation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'Quiz explanation text')]
        [string]$Explanation
    )
    $results = $true #assume the best
    Write-Verbose -Message 'Evaluating provided explanation...'

    $splitTest = $Explanation -split '\n'
    $carriageCount = $splitTest | Measure-Object | Select-Object -ExpandProperty Count

    if ($carriageCount -gt 2) {
        Write-Warning -Message 'Explanation can contain at most 2 line feeds.'
        $results = $false
    }

    if ($Explanation.Length -gt 200) {
        Write-Warning -Message 'Explanation can contain at most 200 characters.'
        $results = $false
    }

    return $results
} #function_Test-Explanation


<#
.Synopsis
    Verifies that specified file is a supported Telegram extension type
.DESCRIPTION
    Evaluates the specified file path to determine if the file is a supported extension type
.EXAMPLE
    Test-FileExtension -FilePath C:\photos\aphoto.jpg -Type Photo
 
    Verifies if the path specified is a supported photo extension type
.EXAMPLE
    Test-FileExtension -FilePath $PhotoPath -Type Photo -Verbose
 
    Verifies if the path specified in $PhotoPath is a supported photo extension type with verbose output
.EXAMPLE
    $fileTypeEval = Test-FileExtension -FilePath $AnimationPath -Type Animation
 
    Verifies if the path specified is a supported Animation extension type
.EXAMPLE
    $fileTypeEval = Test-FileExtension -FilePath $Audio -Type Audio
 
    Verifies if the path specified is a supported Audio extension type
.EXAMPLE
    $fileTypeEval = Test-FileExtension -FilePath $PhotoPath -Type Photo
 
    Verifies if the path specified is a supported photo extension type
.EXAMPLE
    $fileTypeEval = Test-FileExtension -FilePath $Video -Type Video
 
    Verifies if the path specified is a supported Video extension type
.EXAMPLE
    $fileTypeEval = Test-FileExtension -FilePath $Sticker -Type Sticker
 
    Verifies if the path specified is a supported Sticker extension type
.PARAMETER FilePath
    Path to file that will be evaluated
.PARAMETER Type
    Telegram message type
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-FileExtension {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'Path to file that will be evaluated')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$FilePath,
        [Parameter(Mandatory = $true,
            HelpMessage = 'Telegram message type')]
        [ValidateSet('Photo', 'Video', 'Audio', 'Animation', 'Sticker')]
        [string]$Type
    )
    #------------------------------------------------------------
    $supportedPhotoExtensions = @(
        'JPG',
        'JPEG',
        'PNG',
        'GIF',
        'BMP',
        'WEBP',
        'SVG',
        'TIFF'
    )
    $supportedVideoExtensions = @(
        'MP4'
    )
    $supportedAudioExtensions = @(
        'MP3',
        'M4A'
    )
    $supportedAnimationExtensions = @(
        'GIF'
    )
    $supportedStickerExtensions = @(
        'WEBP',
        'TGS'
    )
    switch ($Type) {
        Photo {
            $extType = $supportedPhotoExtensions
        } #photo
        Video {
            $extType = $supportedVideoExtensions
        } #video
        Audio {
            $extType = $supportedAudioExtensions
        } #audio
        Animation {
            $extType = $supportedAnimationExtensions
        } #animation
        Sticker {
            $extType = $supportedStickerExtensions
        }
    } #switch_Type
    Write-Verbose -Message "Validating type: $Type"
    #------------------------------------------------------------
    [bool]$results = $true #assume the best.
    #------------------------------------------------------------
    Write-Verbose -Message "Processing $FilePath ..."
    $divide = $FilePath.Split('.')
    $rawExtension = $divide[$divide.Length - 1]
    $extension = $rawExtension.ToUpper()
    Write-Verbose -Message "Verifying discovered extension: $extension"
    switch ($extension) {
        { $extType -contains $_ } {
            Write-Verbose -Message 'Extension verified.'
        }
        default {
            Write-Warning -Message "The specified file is not a supported $Type extension."
            $results = $false
        } #default
    } #switch_extension
    return $results
} #function_Test-FileExtension


<#
.Synopsis
    Verifies that file size is supported by Telegram
.DESCRIPTION
    Evaluates if the file is at or below the supported Telegram file size
.EXAMPLE
    Test-FileSize -Path C:\videos\video.mp4
 
    Verifies if the path specified is a supported video extension type
.EXAMPLE
    Test-FileSize -Path $Path -Verbose
 
    Verifies if the path specified in $VideoPath is a supported video extension type with verbose output
.PARAMETER Path
    Path to file
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
    Telegram currently supports a 50MB file size for bots
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-FileSize {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'Path to file')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$Path
    )
    $results = $true #assume the best
    $supportedSize = 50
    try {
        $size = Get-ChildItem -Path $Path -ErrorAction Stop
        if (($size.Length / 1MB) -gt $supportedSize) {
            Write-Warning -Message "The file is over $supportedSize (MB)"
            $results = $false
        }
    }
    catch {
        Write-Warning -Message 'An error was encountered evaluating the file size'
        $results = $false
    }
    return $results
} #function_Test-FileSize


<#
.Synopsis
    Verifies that MediaGroup requirements are met.
.DESCRIPTION
    Evaluates the provided files to determine if they met all MediaGroup requirements.
.EXAMPLE
    Test-MediaGroupRequirements -MediaType Photo -FilePaths $files
 
    Verifies if the provided files adhere to the Telegram MediaGroup requirements.
.PARAMETER MediaType
    Type of media to send
.PARAMETER FilePaths
    List of filepaths for media you want to send
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
    Telegram currently supports a 50MB file size for bots
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-MediaGroupRequirements {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'Type of media to send')]
        [ValidateSet('Photo', 'Video', 'Document', 'Audio')]
        [string]$MediaType,
        [Parameter(Mandatory = $false,
            HelpMessage = 'List of filepaths for media you want to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string[]]$FilePaths
    )

    Write-Verbose -Message 'Evaluating the group of files for MediaGroup requirements...'
    $results = $true #assume the best

    Write-Verbose -Message 'Evaluating file count...'
    if ($FilePaths.Count -le 1 -or $FilePaths.Count -gt 10) {
        Write-Warning -Message 'Send-TelegramMediaGroup requires a minimum of 2 and a maximum of 10 media files to be provided.'
        $results = $false
        return $results
    } #file_Count
    else {
        Write-Verbose -Message "File count is: $($FilePaths.Count)"
    } #else_FileCount

    foreach ($file in $FilePaths) {
        $fileTypeEval = $null
        $fileSizeEval = $null
        Write-Verbose -Message 'Verifying presence of media...'
        if (-not(Test-Path -Path $file)) {
            Write-Warning -Message "The specified media path: $file was not found."
            $results = $false
            return $results
        } #if_testPath
        if ($MediaType -ne 'Document') {
            Write-Verbose -Message 'Verifying extension type...'
            $fileTypeEval = Test-FileExtension -FilePath $file -Type $MediaType
            if ($fileTypeEval -eq $false) {
                $results = $false
                return $results
            } #if_Extension
            else {
                Write-Verbose -Message 'Extension supported.'
            } #else_Extension
        }
        Write-Verbose -Message 'Verifying file size...'
        $fileSizeEval = Test-FileSize -Path $file
        if ($fileSizeEval -eq $false) {
            $results = $false
            return $results
        } #if_Size
        else {
            Write-Verbose -Message 'File size verified.'
        } #else_Size
    } #foreach_File

    return $results

} #Test-MediaGroupRequirements


<#
.Synopsis
    Verifies that poll options are supported by Telegram
.DESCRIPTION
    Evaluates if the provided poll options meet the Telegram poll requirements.
.EXAMPLE
    Test-PollOptions -PollOptions $options
 
    Verifies if the provided options meet the poll requirements.
.EXAMPLE
    Test-PollOptions -PollOptions $options
 
    Verifies if the provided options meet the poll requirements with verbose output.
.PARAMETER PollOptions
    Poll Options for eval
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
    Telegram currently supports 2-10 options 1-100 characters each
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-PollOptions {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'Poll Options for eval')]
        [string[]]$PollOptions
    )
    $results = $true #assume the best
    Write-Verbose -Message 'Evaluating number of options...'
    $optionCount = $PollOptions.Length
    if ($optionCount -lt 2 -or $optionCount -gt 10) {
        Write-Warning -Message 'Only 2-10 poll options are allowed.'
        $results = $false
    } #if_optionCount
    else {
        Write-Verbose -Message 'Option number verified.'
        Write-Verbose -Message 'Evaluating character length of options...'
        foreach ($option in $PollOptions) {
            if ($option.Length -lt 1 -or $option.Length -gt 100) {
                Write-Warning -Message "$option is not between 1-100 characters."
                $results = $false
            } #if_length
        } #foreach_option
    } #else_optionCount
    return $results
} #function_Test-PollOptions


<#
.Synopsis
    Verifies that specified URL path contains a supported Telegram extension type
.DESCRIPTION
    Evaluates the specified URL path to determine if the URL leads to a supported extension type
.EXAMPLE
    Test-URLExtension -URL $URL -Type Photo
 
    Verifies if the URL path specified is a supported photo extension type
.EXAMPLE
    Test-URLExtension -URL $PhotoURL -Type Photo -Verbose
 
    Verifies if the URL path specified is a supported photo extension type with Verbose output
.EXAMPLE
    Test-URLExtension -URL $VideoURL -Type Video
 
    Verifies if the URL path specified is a supported video extension type
.EXAMPLE
    Test-URLExtension -URL $AudioURL -Type Audio
 
    Verifies if the URL path specified is a supported audio extension type
.EXAMPLE
    Test-URLExtension -URL $AnimationURL -Type Animation
 
    Verifies if the URL path specified is a supported animation extension type
.EXAMPLE
    Test-URLExtension -URL $DocumentURL -Type Document
 
    Verifies if the URL path specified is a supported document extension type
.EXAMPLE
    Test-URLExtension -URL $StickerURL -Type Sticker
 
    Verifies if the URL path specified is a supported sticker extension type
.PARAMETER URL
    The URL string to the specified online file
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-URLExtension {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'URL string of document')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$URL,
        [Parameter(Mandatory = $true,
            HelpMessage = 'Telegram message type')]
        [ValidateSet('Photo', 'Video', 'Audio', 'Animation', 'Document', 'Sticker')]
        [string]$Type
    )
    #------------------------------------------------------------
    $supportedPhotoExtensions = @(
        'JPG',
        'JPEG',
        'PNG',
        'GIF',
        'BMP',
        'WEBP',
        'SVG',
        'TIFF'
    )
    $supportedVideoExtensions = @(
        'MP4'
    )
    $supportedAudioExtensions = @(
        'MP3',
        'M4A'
    )
    $supportedAnimationExtensions = @(
        'GIF'
    )
    $supportedDocumentExtensions = @(
        'PDF',
        'GIF',
        'ZIP'
    )
    $supportedStickerExtensions = @(
        'WEBP',
        'TGS'
    )
    switch ($Type) {
        Photo {
            $extType = $supportedPhotoExtensions
        } #photo
        Video {
            $extType = $supportedVideoExtensions
        } #video
        Audio {
            $extType = $supportedAudioExtensions
        } #audio
        Animation {
            $extType = $supportedAnimationExtensions
        } #animation
        Document {
            $extType = $supportedDocumentExtensions
        } #document
        Sticker {
            $extType = $supportedStickerExtensions
        } #sticker
    } #switch_Type
    Write-Verbose -Message "Validating type: $Type"
    #------------------------------------------------------------
    [bool]$results = $true #assume the best.
    #------------------------------------------------------------
    Write-Verbose -Message 'Testing provided URL'
    $urlEval = Confirm-URL -Uri $URL
    if ($urlEval -ne $true) {
        Write-Verbose -Message 'URL Confirmation did not return true.'
        $results = $false
        return $results
    } #if_urlEval
    #------------------------------------------------------------
    Write-Verbose -Message 'Resolving potential shortlink...'
    $slEval = Resolve-ShortLink -Uri $URL -ErrorAction SilentlyContinue
    if ($slEval) {
        $URL = $slEval
    } #if_slEval
    #------------------------------------------------------------
    Write-Verbose -Message "Processing $URL ..."
    $divide = $URL.Split('.')
    $rawExtension = $divide[$divide.Length - 1]
    $extension = $rawExtension.ToUpper()
    Write-Verbose -Message "Verifying discovered extension: $extension"
    switch ($extension) {
        { $extType -contains $_ } {
            Write-Verbose -Message 'Extension verified.'
        }
        default {
            Write-Warning -Message "The specified file is not a supported $Type extension."
            $results = $false
        } #default
    } #switch_extension
    #------------------------------------------------------------
    return $results
} #function_Test-URLExtension


<#
.Synopsis
    Verifies that specified URL file size is supported by Telegram
.DESCRIPTION
    Evaluates the specified URL path to determine if the file is at or below the supported Telegram file size
.EXAMPLE
    Test-URLFileSize -URL 'https://github.com/techthoughts2/PoshGram/raw/main/test/SourceFiles/techthoughts.png'
 
    Verifies if the file in the specified URL is at or below the Telegram maximum size
.EXAMPLE
    Test-URLFileSize -URL $URL -Verbose
 
    Verifies if the file in the specified URL is at or below the Telegram maximum size with verbose output
.PARAMETER URL
    URL address to file
.OUTPUTS
    System.Boolean
.NOTES
    Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/
    Telegram currently supports a 50MB file size for bots
.COMPONENT
    PoshGram - https://github.com/techthoughts2/PoshGram
#>

function Test-URLFileSize {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = 'URL address to file')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$URL
    )
    $results = $true #assume the best
    $supportedSize = 50
    try {
        $urlFileInfo = Invoke-WebRequest $URL -ErrorAction Stop
        if (($urlFileInfo.RawContentLength / 1MB) -gt $supportedSize) {
            Write-Warning -Message "The file is over $supportedSize (MB)"
            $results = $false
        } #if_size
    } #try_Invoke-WebRequest
    catch {
        Write-Warning -Message 'An error was encountered evaluating the file size'
        $results = $false
    } #catch_Invoke-WebRequest
    return $results
} #function_Test-URLFileSize


<#
.EXTERNALHELP PoshGram-help.xml
#>

function Get-TelegramStickerPackInfo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Sticker pack name')]
        [ValidateNotNullOrEmpty()]
        [string]$StickerSetName
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $form = @{
        name = $StickerSetName
    } #form

    $uri = 'https://api.telegram.org/bot{0}/getStickerSet' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Retrieving sticker information...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered getting the Telegram sticker info:'
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
            return $results
        }
        else {
            throw $_
        }
    } #catch_messageSend

    Write-Verbose -Message 'Sticker information found. Processing emoji information...'
    Write-Verbose -Message "Asset path: $script:assetPath"
    $je = Get-Content -Path $script:assetPath
    $psF = $je | ConvertFrom-Json
    $stickerData = @()
    foreach ($emoji in $results.result.stickers) {
        #-------------------
        $emojiData = $null
        $code = $null
        $name = $null
        #-------------------
        $bytes = [text.encoding]::unicode.getbytes($emoji.emoji)
        # $actual = [System.Text.Encoding]::Unicode.GetString($bytes)
        # $emoji | Add-Member -Type NoteProperty -Name ActualEmoji -Value $actual -Force
        $emoji | Add-Member -Type NoteProperty -Name Bytes -Value $bytes -Force
        $emojiData = $psf | Where-Object { $_.KDDI -eq $emoji.emoji }
        $code = $emojiData.Sheet
        $name = $emojiData.Google
        $emoji | Add-Member -Type NoteProperty -Name Code -Value $code -Force
        $emoji | Add-Member -Type NoteProperty -Name Shortcode -Value $name -Force
        $stickerData += $emoji
    }

    return $stickerData
} #function_Get-TelegramStickerPackInfo



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramContact {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Contact phone number')]
        [ValidateNotNullOrEmpty()]
        [string]$PhoneNumber,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Contact first name')]
        [ValidateNotNullOrEmpty()]
        [string]$FirstName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Contact last name')]
        [ValidateNotNullOrEmpty()]
        [string]$LastName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $form = @{
        chat_id              = $ChatID
        phone_number         = $PhoneNumber
        first_name           = $FirstName
        last_name            = $LastName
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendContact' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending contact...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram contact:'
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramContact



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramDice {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Emoji on which the dice throw animation is based.')]
        [ValidateSet('dice', 'dart', 'basketball', 'football', 'slotmachine', 'bowling')]
        [string]$Emoji,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    switch ($Emoji) {
        dice {
            $emojiSend = '🎲'
        }
        dart {
            $emojiSend = '🎯'
        }
        basketball {
            $emojiSend = '🏀'
        }
        football {
            $emojiSend = 'âš½'
        }
        slotmachine {
            $emojiSend = '🎰'
        }
        bowling {
            $emojiSend = '🎳'
        }
    }

    $form = @{
        chat_id              = $ChatID
        emoji                = $emojiSend
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendDice' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending dice...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram location:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramDice



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalAnimation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'File path to the animation you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$AnimationPath,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Animation caption')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of animation...'
    if (-not(Test-Path -Path $AnimationPath)) {
        throw ('The specified animation path: {0} was not found.' -f $AnimationPath)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying extension type...'
    $fileTypeEval = Test-FileExtension -FilePath $AnimationPath -Type Animation
    if ($fileTypeEval -eq $false) {
        throw 'File extension is not a supported Animation type'
    } #if_animationExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_animationExtension

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $AnimationPath
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_animationSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_animationSize

    Write-Verbose -Message 'Getting animation file...'
    try {
        $fileObject = Get-Item $AnimationPath -ErrorAction Stop
    } #try_Get-ItemAnimation
    catch {
        Write-Warning -Message 'The specified animation could not be interpreted properly.'
        throw $_
    } #catch_Get-ItemAnimation

    $form = @{
        chat_id              = $ChatID
        animation            = $fileObject
        caption              = $Caption
        parse_mode           = $ParseMode
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendAnimation' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending animation...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram animation message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalAnimation



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalAudio {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Local path to file you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$Audio,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Caption for file')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Duration of the audio in seconds')]
        [int]$Duration,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Performer')]
        [string]$Performer,

        [Parameter(Mandatory = $false,
            HelpMessage = 'TrackName')]
        [string]$Title,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Original File Name')]
        [string]$FileName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of file...'
    if (-not(Test-Path -Path $Audio)) {
        throw ('The specified file was not found {0}' -f $Audio)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying extension type...'
    $fileTypeEval = Test-FileExtension -FilePath $Audio -Type Audio
    if ($fileTypeEval -eq $false) {
        throw 'File extension is not a supported Audio type'
    } #if_audioExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_audioExtension

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $Audio
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_audioSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_audioSize

    Write-Verbose -Message 'Getting audio file...'
    try {
        $fileObject = Get-Item $Audio -ErrorAction Stop
    } #try_Get-ItemAudio
    catch {
        Write-Warning -Message 'The specified audio could not be interpreted properly.'
        throw $_
    } #catch_Get-ItemAudio

    $form = @{
        chat_id              = $ChatID
        audio                = $fileObject
        caption              = $Caption
        parse_mode           = $ParseMode
        duration             = $Duration
        performer            = $Performer
        title                = $Title
        file_name            = $FileName
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendAudio' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending audio...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram audio message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalAudio



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalDocument {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Local path to file you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$File,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Caption for file')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Disables automatic server-side content type detection')]
        [switch]$DisableContentTypeDetection,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of file...'
    if (-not(Test-Path -Path $File)) {
        throw ('The specified file was not found: {0}' -f $AnimationPath)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $File
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_fileSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_fileSize

    Write-Verbose -Message 'Getting document file...'
    try {
        $fileObject = Get-Item $File -ErrorAction Stop
    } #try_Get-Item
    catch {
        Write-Warning -Message 'The specified file could not be interpreted properly.'
        throw $_
    } #catch_Get-Item

    $form = @{
        chat_id                        = $ChatID
        document                       = $fileObject
        caption                        = $Caption
        parse_mode                     = $ParseMode
        disable_content_type_detection = $DisableContentTypeDetection.IsPresent
        disable_notification           = $DisableNotification.IsPresent
        protect_content                = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendDocument' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending document...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram document message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalDocument



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalPhoto {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'File path to the photo you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$PhotoPath,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Photo caption')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of photo...'
    if (-not(Test-Path -Path $PhotoPath)) {
        throw ('The specified photo path: {0} was not found.' -f $PhotoPath)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying extension type...'
    $fileTypeEval = Test-FileExtension -FilePath $PhotoPath -Type Photo
    if ($fileTypeEval -eq $false) {
        throw 'File extension is not a supported Photo type'
    } #if_photoExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_photoExtension

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $PhotoPath
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_photoSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_photoSize

    Write-Verbose -Message 'Getting photo file...'
    try {
        $fileObject = Get-Item $PhotoPath -ErrorAction Stop
    } #try_Get-ItemPhoto
    catch {
        Write-Warning -Message 'The specified photo could not be interpreted properly.'
        throw $_
    } #catch_Get-ItemPhoto

    $form = @{
        chat_id              = $ChatID
        photo                = $fileObject
        caption              = $Caption
        parse_mode           = $ParseMode
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendphoto' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending photo...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram photo message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalPhoto



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalSticker {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'File path to the sticker you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$StickerPath,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of sticker...'
    if (-not(Test-Path -Path $StickerPath)) {
        throw ('The specified sticker path: {0} was not found.' -f $AnimationPath)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying extension type...'
    $fileTypeEval = Test-FileExtension -FilePath $StickerPath -Type Sticker
    if ($fileTypeEval -eq $false) {
        throw 'File extension is not a supported Sticker type'
    } #if_stickerExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_stickerExtension

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $StickerPath
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_stickerSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_stickerSize

    Write-Verbose -Message 'Getting sticker file...'
    try {
        $fileObject = Get-Item $StickerPath -ErrorAction Stop
    } #try_Get-ItemSticker
    catch {
        Write-Warning -Message 'The specified sticker could not be interpreted properly.'
        throw $_
    } #catch_Get-ItemSticker

    $form = @{
        chat_id              = $ChatID
        sticker              = $fileObject
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendSticker' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending sticker...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram sticker message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalSticker



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocalVideo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Local path to file you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$Video,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Duration of video in seconds')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Duration,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Video width')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Width,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Video height')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Height,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Original File Name')]
        [string]$FileName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Caption for file')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Use if the uploaded video is suitable for streaming')]
        [switch]$Streaming,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying presence of file...'
    if (-not(Test-Path -Path $Video)) {
        throw ('The specified video file: {0} was not found.' -f $Video)
    } #if_testPath
    else {
        Write-Verbose -Message 'Path verified.'
    } #else_testPath

    Write-Verbose -Message 'Verifying extension type...'
    $fileTypeEval = Test-FileExtension -FilePath $Video -Type Video
    if ($fileTypeEval -eq $false) {
        throw 'File extension is not a supported Video type'
    } #if_videoExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_videoExtension

    Write-Verbose -Message 'Verifying file size...'
    $fileSizeEval = Test-FileSize -Path $Video
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_videoSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_videoSize

    Write-Verbose -Message 'Getting video file...'
    try {
        $fileObject = Get-Item $Video -ErrorAction Stop
    } #try_Get-ItemVideo
    catch {
        Write-Warning -Message 'The specified video file could not be interpreted properly.'
        throw $_
    } #catch_Get-ItemVideo

    $form = @{
        chat_id              = $ChatID
        video                = $fileObject
        duration             = $Duration
        width                = $Width
        height               = $Height
        file_name            = $FileName
        caption              = $Caption
        parse_mode           = $ParseMode
        supports_streaming   = $Streaming.IsPresent
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendVideo' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending video...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram video message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocalVideo



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramLocation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Latitude of the location')]
        [ValidateRange(-90, 90)]
        [single]$Latitude,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Longitude of the location')]
        [ValidateRange(-180, 180)]
        [single]$Longitude,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $form = @{
        chat_id              = $ChatID
        latitude             = $Latitude
        longitude            = $Longitude
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendLocation' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending location...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram location:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramLocation



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramMediaGroup {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Type of media to send')]
        [ValidateSet('Photo', 'Video', 'Document', 'Audio')]
        [string]$MediaType,

        [Parameter(Mandatory = $false,
            HelpMessage = 'List of filepaths for media you want to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string[]]$FilePaths,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $MediaType = $MediaType.ToLower()
    Write-Verbose -Message ('You have specified a media type of: {0}' -f $MediaType)

    Write-Verbose -Message 'Testing if media group meets requirements...'
    $mediaGroupReqsEval = Test-MediaGroupRequirements -MediaType $MediaType -FilePath $FilePaths
    if (-not $mediaGroupReqsEval) {
        throw 'Telegram media group requirements not met'
    }

    Write-Verbose -Message 'Forming serialized JSON for all media files...'
    $form = @{
        chat_id              = $ChatID;
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
        media                = ''
    }
    $json = @'
    [
 
'@


    $i = 1
    foreach ($file in $FilePaths) {
        $fInfo = $null
        try {
            $fInfo = Get-Item -Path $file -ErrorAction Stop
        }
        catch {
            throw ('An issue was encountered retrieving data from: {0}' -f $file)
        }
        $Form += @{"$MediaType$i" = $fInfo }
        $json += "{`"type`":`"$MediaType`",`"`media`":`"attach://$MediaType$i`"},"
        $i++
    }
    $json = $json.Substring(0, $json.Length - 1)

    $json += @'
 
]
'@


    $Form.media = $json
    Write-Verbose -Message 'JSON formation completed.'

    $uri = 'https://api.telegram.org/bot{0}/sendMediaGroup' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending media...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    Write-Verbose -Message 'Sending media...'
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
        Write-Verbose -Message 'Media sent.'
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram photo message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramMediaGroup



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramPoll {
    [CmdletBinding(DefaultParameterSetName = 'default')]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Poll question')]
        [ValidateLength(1, 300)]
        [string]$Question,

        [Parameter(Mandatory = $true,
            HelpMessage = 'String array of answer options')]
        [ValidateNotNullOrEmpty()]
        [string[]]$Options,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Set the poll to be anonymous or not')]
        [bool]$IsAnonymous = $true, #default is anonymous

        [Parameter(Mandatory = $false,
            HelpMessage = 'Poll Type')]
        [ValidateSet('quiz', 'regular')]
        [string]$PollType = 'regular', #default is regular

        [Parameter(Mandatory = $false,
            HelpMessage = 'Poll allows multiple answers - ignored in quiz mode')]
        [bool]$MultipleAnswers = $false, #default is false

        [Parameter(Mandatory = $false,
            HelpMessage = 'Quiz answer designator')]
        [int]$QuizAnswer,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Text that is shown when a user chooses an incorrect answer')]
        [string]$Explanation,

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for explanation formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ExplanationParseMode = 'HTML', #set to HTML by default

        [Parameter(ParameterSetName = 'OpenPeriod',
            Mandatory = $false,
            HelpMessage = 'Time in seconds the poll/quiz will be active after creation')]
        [ValidateRange(5, 600)]
        [int]$OpenPeriod,

        [Parameter(ParameterSetName = 'OpenDate',
            Mandatory = $false,
            HelpMessage = 'Point in time when the poll will be automatically closed.')]
        [datetime]$CloseDate,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Testing poll options...'
    $optionEval = Test-PollOptions -PollOptions $Options
    if ($optionEval -eq $false) {
        throw 'Poll options do not meet Telegram requirements'
    }

    Write-Verbose -Message 'Converting options to json format...'
    $Options = $Options | ConvertTo-Json
    $form = @{
        chat_id                 = $ChatID
        question                = $Question
        disable_notification    = $DisableNotification.IsPresent
        protect_content         = $ProtectContent.IsPresent
        options                 = $Options
        is_anonymous            = $IsAnonymous
        type                    = $PollType
        allows_multiple_answers = $MultipleAnswers
    } #form

    if ($PollType -eq 'quiz') {
        Write-Verbose -Message 'Processing quiz...'
        Write-Verbose -Message ('Quiz answer: {0}' -f $QuizAnswer)
        if (-not ($QuizAnswer -ge 0 -and $QuizAnswer -le 9)) {
            throw 'When PollType is quiz, you must supply a QuizAnswer designator between 0-9.'
        }
        else {
            $Form += @{correct_option_id = $QuizAnswer }

            if ($Explanation) {
                $explanationEval = Test-Explanation -Explanation $Explanation
                if ($explanationEval -eq $false) {
                    throw 'Explanation does not meet Telegram requirements.'
                }
                $Form += @{explanation = $Explanation }
                $Form += @{explanation_parse_mode = $ExplanationParseMode }
            }
        }
    }

    if ($OpenPeriod) {
        $Form += @{open_period = $OpenPeriod }
    }
    if ($CloseDate) {
        $Form += @{close_date = (New-TimeSpan -Start (Get-Date) -End $CloseDate).TotalSeconds }
    }

    $uri = 'https://api.telegram.org/bot{0}/sendPoll' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending poll...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram poll:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramPoll



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramSticker {
    [CmdletBinding()]
    param (
        [Parameter(ParameterSetName = 'FileIDG')]
        [Parameter(ParameterSetName = 'FileEmojiG')]
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(ParameterSetName = 'FileIDG')]
        [Parameter(ParameterSetName = 'FileEmojiG')]
        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(ParameterSetName = 'FileIDG')]
        [Parameter(Mandatory = $true,
            ParameterSetName = 'ByFileID',
            HelpMessage = 'Telegram sticker file_id')]
        [string]$FileID,

        [Parameter(ParameterSetName = 'FileEmojiG')]
        [Parameter(Mandatory = $true,
            ParameterSetName = 'BySPShortCode',
            HelpMessage = 'Name of the sticker set')]
        [string]$StickerSetName,

        [Parameter(ParameterSetName = 'FileEmojiG')]
        [Parameter(Mandatory = $true,
            ParameterSetName = 'BySPShortCode',
            HelpMessage = 'Emoji shortcode')]
        [ValidateSet(
            ':hash:',
            ':keycap_star:',
            ':zero:',
            ':one:',
            ':two:',
            ':three:',
            ':four:',
            ':five:',
            ':six:',
            ':seven:',
            ':eight:',
            ':nine:',
            ':copyright:',
            ':registered:',
            ':mahjong:',
            ':black_joker:',
            ':a:',
            ':b:',
            ':o2:',
            ':parking:',
            ':ab:',
            ':cl:',
            ':cool:',
            ':free:',
            ':id:',
            ':new:',
            ':ng:',
            ':ok:',
            ':sos:',
            ':up:',
            ':vs:',
            ':flag-ac:',
            ':flag-ad:',
            ':flag-ae:',
            ':flag-af:',
            ':flag-ag:',
            ':flag-ai:',
            ':flag-al:',
            ':flag-am:',
            ':flag-ao:',
            ':flag-aq:',
            ':flag-ar:',
            ':flag-as:',
            ':flag-at:',
            ':flag-au:',
            ':flag-aw:',
            ':flag-ax:',
            ':flag-az:',
            ':flag-ba:',
            ':flag-bb:',
            ':flag-bd:',
            ':flag-be:',
            ':flag-bf:',
            ':flag-bg:',
            ':flag-bh:',
            ':flag-bi:',
            ':flag-bj:',
            ':flag-bl:',
            ':flag-bm:',
            ':flag-bn:',
            ':flag-bo:',
            ':flag-bq:',
            ':flag-br:',
            ':flag-bs:',
            ':flag-bt:',
            ':flag-bv:',
            ':flag-bw:',
            ':flag-by:',
            ':flag-bz:',
            ':flag-ca:',
            ':flag-cc:',
            ':flag-cd:',
            ':flag-cf:',
            ':flag-cg:',
            ':flag-ch:',
            ':flag-ci:',
            ':flag-ck:',
            ':flag-cl:',
            ':flag-cm:',
            ':cn:',
            ':flag-co:',
            ':flag-cp:',
            ':flag-cr:',
            ':flag-cu:',
            ':flag-cv:',
            ':flag-cw:',
            ':flag-cx:',
            ':flag-cy:',
            ':flag-cz:',
            ':de:',
            ':flag-dg:',
            ':flag-dj:',
            ':flag-dk:',
            ':flag-dm:',
            ':flag-do:',
            ':flag-dz:',
            ':flag-ea:',
            ':flag-ec:',
            ':flag-ee:',
            ':flag-eg:',
            ':flag-eh:',
            ':flag-er:',
            ':es:',
            ':flag-et:',
            ':flag-eu:',
            ':flag-fi:',
            ':flag-fj:',
            ':flag-fk:',
            ':flag-fm:',
            ':flag-fo:',
            ':fr:',
            ':flag-ga:',
            ':gb:',
            ':flag-gd:',
            ':flag-ge:',
            ':flag-gf:',
            ':flag-gg:',
            ':flag-gh:',
            ':flag-gi:',
            ':flag-gl:',
            ':flag-gm:',
            ':flag-gn:',
            ':flag-gp:',
            ':flag-gq:',
            ':flag-gr:',
            ':flag-gs:',
            ':flag-gt:',
            ':flag-gu:',
            ':flag-gw:',
            ':flag-gy:',
            ':flag-hk:',
            ':flag-hm:',
            ':flag-hn:',
            ':flag-hr:',
            ':flag-ht:',
            ':flag-hu:',
            ':flag-ic:',
            ':flag-id:',
            ':flag-ie:',
            ':flag-il:',
            ':flag-im:',
            ':flag-in:',
            ':flag-io:',
            ':flag-iq:',
            ':flag-ir:',
            ':flag-is:',
            ':it:',
            ':flag-je:',
            ':flag-jm:',
            ':flag-jo:',
            ':jp:',
            ':flag-ke:',
            ':flag-kg:',
            ':flag-kh:',
            ':flag-ki:',
            ':flag-km:',
            ':flag-kn:',
            ':flag-kp:',
            ':kr:',
            ':flag-kw:',
            ':flag-ky:',
            ':flag-kz:',
            ':flag-la:',
            ':flag-lb:',
            ':flag-lc:',
            ':flag-li:',
            ':flag-lk:',
            ':flag-lr:',
            ':flag-ls:',
            ':flag-lt:',
            ':flag-lu:',
            ':flag-lv:',
            ':flag-ly:',
            ':flag-ma:',
            ':flag-mc:',
            ':flag-md:',
            ':flag-me:',
            ':flag-mf:',
            ':flag-mg:',
            ':flag-mh:',
            ':flag-mk:',
            ':flag-ml:',
            ':flag-mm:',
            ':flag-mn:',
            ':flag-mo:',
            ':flag-mp:',
            ':flag-mq:',
            ':flag-mr:',
            ':flag-ms:',
            ':flag-mt:',
            ':flag-mu:',
            ':flag-mv:',
            ':flag-mw:',
            ':flag-mx:',
            ':flag-my:',
            ':flag-mz:',
            ':flag-na:',
            ':flag-nc:',
            ':flag-ne:',
            ':flag-nf:',
            ':flag-ng:',
            ':flag-ni:',
            ':flag-nl:',
            ':flag-no:',
            ':flag-np:',
            ':flag-nr:',
            ':flag-nu:',
            ':flag-nz:',
            ':flag-om:',
            ':flag-pa:',
            ':flag-pe:',
            ':flag-pf:',
            ':flag-pg:',
            ':flag-ph:',
            ':flag-pk:',
            ':flag-pl:',
            ':flag-pm:',
            ':flag-pn:',
            ':flag-pr:',
            ':flag-ps:',
            ':flag-pt:',
            ':flag-pw:',
            ':flag-py:',
            ':flag-qa:',
            ':flag-re:',
            ':flag-ro:',
            ':flag-rs:',
            ':ru:',
            ':flag-rw:',
            ':flag-sa:',
            ':flag-sb:',
            ':flag-sc:',
            ':flag-sd:',
            ':flag-se:',
            ':flag-sg:',
            ':flag-sh:',
            ':flag-si:',
            ':flag-sj:',
            ':flag-sk:',
            ':flag-sl:',
            ':flag-sm:',
            ':flag-sn:',
            ':flag-so:',
            ':flag-sr:',
            ':flag-ss:',
            ':flag-st:',
            ':flag-sv:',
            ':flag-sx:',
            ':flag-sy:',
            ':flag-sz:',
            ':flag-ta:',
            ':flag-tc:',
            ':flag-td:',
            ':flag-tf:',
            ':flag-tg:',
            ':flag-th:',
            ':flag-tj:',
            ':flag-tk:',
            ':flag-tl:',
            ':flag-tm:',
            ':flag-tn:',
            ':flag-to:',
            ':flag-tr:',
            ':flag-tt:',
            ':flag-tv:',
            ':flag-tw:',
            ':flag-tz:',
            ':flag-ua:',
            ':flag-ug:',
            ':flag-um:',
            ':flag-un:',
            ':us:',
            ':flag-uy:',
            ':flag-uz:',
            ':flag-va:',
            ':flag-vc:',
            ':flag-ve:',
            ':flag-vg:',
            ':flag-vi:',
            ':flag-vn:',
            ':flag-vu:',
            ':flag-wf:',
            ':flag-ws:',
            ':flag-xk:',
            ':flag-ye:',
            ':flag-yt:',
            ':flag-za:',
            ':flag-zm:',
            ':flag-zw:',
            ':koko:',
            ':sa:',
            ':u7121:',
            ':u6307:',
            ':u7981:',
            ':u7a7a:',
            ':u5408:',
            ':u6e80:',
            ':u6709:',
            ':u6708:',
            ':u7533:',
            ':u5272:',
            ':u55b6:',
            ':ideograph_advantage:',
            ':accept:',
            ':cyclone:',
            ':foggy:',
            ':closed_umbrella:',
            ':night_with_stars:',
            ':sunrise_over_mountains:',
            ':sunrise:',
            ':city_sunset:',
            ':city_sunrise:',
            ':rainbow:',
            ':bridge_at_night:',
            ':ocean:',
            ':volcano:',
            ':milky_way:',
            ':earth_africa:',
            ':earth_americas:',
            ':earth_asia:',
            ':globe_with_meridians:',
            ':new_moon:',
            ':waxing_crescent_moon:',
            ':first_quarter_moon:',
            ':moon:',
            ':full_moon:',
            ':waning_gibbous_moon:',
            ':last_quarter_moon:',
            ':waning_crescent_moon:',
            ':crescent_moon:',
            ':new_moon_with_face:',
            ':first_quarter_moon_with_face:',
            ':last_quarter_moon_with_face:',
            ':full_moon_with_face:',
            ':sun_with_face:',
            ':star2:',
            ':stars:',
            ':thermometer:',
            ':mostly_sunny:',
            ':barely_sunny:',
            ':partly_sunny_rain:',
            ':rain_cloud:',
            ':snow_cloud:',
            ':lightning:',
            ':tornado:',
            ':fog:',
            ':wind_blowing_face:',
            ':hotdog:',
            ':taco:',
            ':burrito:',
            ':chestnut:',
            ':seedling:',
            ':evergreen_tree:',
            ':deciduous_tree:',
            ':palm_tree:',
            ':cactus:',
            ':hot_pepper:',
            ':tulip:',
            ':cherry_blossom:',
            ':rose:',
            ':hibiscus:',
            ':sunflower:',
            ':blossom:',
            ':corn:',
            ':ear_of_rice:',
            ':herb:',
            ':four_leaf_clover:',
            ':maple_leaf:',
            ':fallen_leaf:',
            ':leaves:',
            ':mushroom:',
            ':tomato:',
            ':eggplant:',
            ':grapes:',
            ':melon:',
            ':watermelon:',
            ':tangerine:',
            ':lemon:',
            ':banana:',
            ':pineapple:',
            ':apple:',
            ':green_apple:',
            ':pear:',
            ':peach:',
            ':cherries:',
            ':strawberry:',
            ':hamburger:',
            ':pizza:',
            ':meat_on_bone:',
            ':poultry_leg:',
            ':rice_cracker:',
            ':rice_ball:',
            ':rice:',
            ':curry:',
            ':ramen:',
            ':spaghetti:',
            ':bread:',
            ':fries:',
            ':sweet_potato:',
            ':dango:',
            ':oden:',
            ':sushi:',
            ':fried_shrimp:',
            ':fish_cake:',
            ':icecream:',
            ':shaved_ice:',
            ':ice_cream:',
            ':doughnut:',
            ':cookie:',
            ':chocolate_bar:',
            ':candy:',
            ':lollipop:',
            ':custard:',
            ':honey_pot:',
            ':cake:',
            ':bento:',
            ':stew:',
            ':fried_egg:',
            ':fork_and_knife:',
            ':tea:',
            ':sake:',
            ':wine_glass:',
            ':cocktail:',
            ':tropical_drink:',
            ':beer:',
            ':beers:',
            ':baby_bottle:',
            ':knife_fork_plate:',
            ':champagne:',
            ':popcorn:',
            ':ribbon:',
            ':gift:',
            ':birthday:',
            ':jack_o_lantern:',
            ':christmas_tree:',
            ':santa:',
            ':fireworks:',
            ':sparkler:',
            ':balloon:',
            ':tada:',
            ':confetti_ball:',
            ':tanabata_tree:',
            ':crossed_flags:',
            ':bamboo:',
            ':dolls:',
            ':flags:',
            ':wind_chime:',
            ':rice_scene:',
            ':school_satchel:',
            ':mortar_board:',
            ':medal:',
            ':reminder_ribbon:',
            ':studio_microphone:',
            ':level_slider:',
            ':control_knobs:',
            ':film_frames:',
            ':admission_tickets:',
            ':carousel_horse:',
            ':ferris_wheel:',
            ':roller_coaster:',
            ':fishing_pole_and_fish:',
            ':microphone:',
            ':movie_camera:',
            ':cinema:',
            ':headphones:',
            ':art:',
            ':tophat:',
            ':circus_tent:',
            ':ticket:',
            ':clapper:',
            ':performing_arts:',
            ':video_game:',
            ':dart:',
            ':slot_machine:',
            ':8ball:',
            ':game_die:',
            ':bowling:',
            ':flower_playing_cards:',
            ':musical_note:',
            ':notes:',
            ':saxophone:',
            ':guitar:',
            ':musical_keyboard:',
            ':trumpet:',
            ':violin:',
            ':musical_score:',
            ':running_shirt_with_sash:',
            ':tennis:',
            ':ski:',
            ':basketball:',
            ':checkered_flag:',
            ':snowboarder:',
            ':woman-running:',
            ':man-running:',
            ':runner:',
            ':woman-surfing:',
            ':man-surfing:',
            ':surfer:',
            ':sports_medal:',
            ':trophy:',
            ':horse_racing:',
            ':football:',
            ':rugby_football:',
            ':woman-swimming:',
            ':man-swimming:',
            ':swimmer:',
            ':woman-lifting-weights:',
            ':man-lifting-weights:',
            ':weight_lifter:',
            ':woman-golfing:',
            ':man-golfing:',
            ':golfer:',
            ':racing_motorcycle:',
            ':racing_car:',
            ':cricket_bat_and_ball:',
            ':volleyball:',
            ':field_hockey_stick_and_ball:',
            ':ice_hockey_stick_and_puck:',
            ':table_tennis_paddle_and_ball:',
            ':snow_capped_mountain:',
            ':camping:',
            ':beach_with_umbrella:',
            ':building_construction:',
            ':house_buildings:',
            ':cityscape:',
            ':derelict_house_building:',
            ':classical_building:',
            ':desert:',
            ':desert_island:',
            ':national_park:',
            ':stadium:',
            ':house:',
            ':house_with_garden:',
            ':office:',
            ':post_office:',
            ':european_post_office:',
            ':hospital:',
            ':bank:',
            ':atm:',
            ':hotel:',
            ':love_hotel:',
            ':convenience_store:',
            ':school:',
            ':department_store:',
            ':factory:',
            ':izakaya_lantern:',
            ':japanese_castle:',
            ':european_castle:',
            ':rainbow-flag:',
            ':waving_white_flag:',
            ':pirate_flag:',
            ':flag-england:',
            ':flag-scotland:',
            ':flag-wales:',
            ':waving_black_flag:',
            ':rosette:',
            ':label:',
            ':badminton_racquet_and_shuttlecock:',
            ':bow_and_arrow:',
            ':amphora:',
            ':skin-tone-2:',
            ':skin-tone-3:',
            ':skin-tone-4:',
            ':skin-tone-5:',
            ':skin-tone-6:',
            ':rat:',
            ':mouse2:',
            ':ox:',
            ':water_buffalo:',
            ':cow2:',
            ':tiger2:',
            ':leopard:',
            ':rabbit2:',
            ':cat2:',
            ':dragon:',
            ':crocodile:',
            ':whale2:',
            ':snail:',
            ':snake:',
            ':racehorse:',
            ':ram:',
            ':goat:',
            ':sheep:',
            ':monkey:',
            ':rooster:',
            ':chicken:',
            ':dog2:',
            ':pig2:',
            ':boar:',
            ':elephant:',
            ':octopus:',
            ':shell:',
            ':bug:',
            ':ant:',
            ':bee:',
            ':beetle:',
            ':fish:',
            ':tropical_fish:',
            ':blowfish:',
            ':turtle:',
            ':hatching_chick:',
            ':baby_chick:',
            ':hatched_chick:',
            ':bird:',
            ':penguin:',
            ':koala:',
            ':poodle:',
            ':dromedary_camel:',
            ':camel:',
            ':dolphin:',
            ':mouse:',
            ':cow:',
            ':tiger:',
            ':rabbit:',
            ':cat:',
            ':dragon_face:',
            ':whale:',
            ':horse:',
            ':monkey_face:',
            ':dog:',
            ':pig:',
            ':frog:',
            ':hamster:',
            ':wolf:',
            ':bear:',
            ':panda_face:',
            ':pig_nose:',
            ':feet:',
            ':chipmunk:',
            ':eyes:',
            ':eye-in-speech-bubble:',
            ':eye:',
            ':ear:',
            ':nose:',
            ':lips:',
            ':tongue:',
            ':point_up_2:',
            ':point_down:',
            ':point_left:',
            ':point_right:',
            ':facepunch:',
            ':wave:',
            ':ok_hand:',
            ':+1:',
            ':-1:',
            ':clap:',
            ':open_hands:',
            ':crown:',
            ':womans_hat:',
            ':eyeglasses:',
            ':necktie:',
            ':shirt:',
            ':jeans:',
            ':dress:',
            ':kimono:',
            ':bikini:',
            ':womans_clothes:',
            ':purse:',
            ':handbag:',
            ':pouch:',
            ':mans_shoe:',
            ':athletic_shoe:',
            ':high_heel:',
            ':sandal:',
            ':boot:',
            ':footprints:',
            ':bust_in_silhouette:',
            ':busts_in_silhouette:',
            ':boy:',
            ':girl:',
            ':male-farmer:',
            ':male-cook:',
            ':male-student:',
            ':male-singer:',
            ':male-artist:',
            ':male-teacher:',
            ':male-factory-worker:',
            ':man-boy-boy:',
            ':man-boy:',
            ':man-girl-boy:',
            ':man-girl-girl:',
            ':man-girl:',
            ':man-man-boy:',
            ':man-man-boy-boy:',
            ':man-man-girl:',
            ':man-man-girl-boy:',
            ':man-man-girl-girl:',
            ':man-woman-boy:',
            ':man-woman-boy-boy:',
            ':man-woman-girl:',
            ':man-woman-girl-boy:',
            ':man-woman-girl-girl:',
            ':male-technologist:',
            ':male-office-worker:',
            ':male-mechanic:',
            ':male-scientist:',
            ':male-astronaut:',
            ':male-firefighter:',
            ':male_red_haired:',
            ':male_curly_haired:',
            ':male_bald:',
            ':male_white_haired:',
            ':male-doctor:',
            ':male-judge:',
            ':male-pilot:',
            ':man-heart-man:',
            ':man-kiss-man:',
            ':man:',
            ':female-farmer:',
            ':female-cook:',
            ':female-student:',
            ':female-singer:',
            ':female-artist:',
            ':female-teacher:',
            ':female-factory-worker:',
            ':woman-boy-boy:',
            ':woman-boy:',
            ':woman-girl-boy:',
            ':woman-girl-girl:',
            ':woman-girl:',
            ':woman-woman-boy:',
            ':woman-woman-boy-boy:',
            ':woman-woman-girl:',
            ':woman-woman-girl-boy:',
            ':woman-woman-girl-girl:',
            ':female-technologist:',
            ':female-office-worker:',
            ':female-mechanic:',
            ':female-scientist:',
            ':female-astronaut:',
            ':female-firefighter:',
            ':female_red_haired:',
            ':female_curly_haired:',
            ':female_bald:',
            ':female_white_haired:',
            ':female-doctor:',
            ':female-judge:',
            ':female-pilot:',
            ':woman-heart-man:',
            ':woman-heart-woman:',
            ':woman-kiss-man:',
            ':woman-kiss-woman:',
            ':woman:',
            ':family:',
            ':couple:',
            ':two_men_holding_hands:',
            ':two_women_holding_hands:',
            ':female-police-officer:',
            ':male-police-officer:',
            ':cop:',
            ':woman-with-bunny-ears-partying:',
            ':man-with-bunny-ears-partying:',
            ':dancers:',
            ':bride_with_veil:',
            ':blond-haired-woman:',
            ':blond-haired-man:',
            ':person_with_blond_hair:',
            ':man_with_gua_pi_mao:',
            ':woman-wearing-turban:',
            ':man-wearing-turban:',
            ':man_with_turban:',
            ':older_man:',
            ':older_woman:',
            ':baby:',
            ':female-construction-worker:',
            ':male-construction-worker:',
            ':construction_worker:',
            ':princess:',
            ':japanese_ogre:',
            ':japanese_goblin:',
            ':ghost:',
            ':angel:',
            ':alien:',
            ':space_invader:',
            ':imp:',
            ':skull:',
            ':woman-tipping-hand:',
            ':man-tipping-hand:',
            ':information_desk_person:',
            ':female-guard:',
            ':male-guard:',
            ':guardsman:',
            ':dancer:',
            ':lipstick:',
            ':nail_care:',
            ':woman-getting-massage:',
            ':man-getting-massage:',
            ':massage:',
            ':woman-getting-haircut:',
            ':man-getting-haircut:',
            ':haircut:',
            ':barber:',
            ':syringe:',
            ':pill:',
            ':kiss:',
            ':love_letter:',
            ':ring:',
            ':gem:',
            ':couplekiss:',
            ':bouquet:',
            ':couple_with_heart:',
            ':wedding:',
            ':heartbeat:',
            ':broken_heart:',
            ':two_hearts:',
            ':sparkling_heart:',
            ':heartpulse:',
            ':cupid:',
            ':blue_heart:',
            ':green_heart:',
            ':yellow_heart:',
            ':purple_heart:',
            ':gift_heart:',
            ':revolving_hearts:',
            ':heart_decoration:',
            ':diamond_shape_with_a_dot_inside:',
            ':bulb:',
            ':anger:',
            ':bomb:',
            ':zzz:',
            ':boom:',
            ':sweat_drops:',
            ':droplet:',
            ':dash:',
            ':hankey:',
            ':muscle:',
            ':dizzy:',
            ':speech_balloon:',
            ':thought_balloon:',
            ':white_flower:',
            ':100:',
            ':moneybag:',
            ':currency_exchange:',
            ':heavy_dollar_sign:',
            ':credit_card:',
            ':yen:',
            ':dollar:',
            ':euro:',
            ':pound:',
            ':money_with_wings:',
            ':chart:',
            ':seat:',
            ':computer:',
            ':briefcase:',
            ':minidisc:',
            ':floppy_disk:',
            ':cd:',
            ':dvd:',
            ':file_folder:',
            ':open_file_folder:',
            ':page_with_curl:',
            ':page_facing_up:',
            ':date:',
            ':calendar:',
            ':card_index:',
            ':chart_with_upwards_trend:',
            ':chart_with_downwards_trend:',
            ':bar_chart:',
            ':clipboard:',
            ':pushpin:',
            ':round_pushpin:',
            ':paperclip:',
            ':straight_ruler:',
            ':triangular_ruler:',
            ':bookmark_tabs:',
            ':ledger:',
            ':notebook:',
            ':notebook_with_decorative_cover:',
            ':closed_book:',
            ':book:',
            ':green_book:',
            ':blue_book:',
            ':orange_book:',
            ':books:',
            ':name_badge:',
            ':scroll:',
            ':memo:',
            ':telephone_receiver:',
            ':pager:',
            ':fax:',
            ':satellite_antenna:',
            ':loudspeaker:',
            ':mega:',
            ':outbox_tray:',
            ':inbox_tray:',
            ':package:',
            ':e-mail:',
            ':incoming_envelope:',
            ':envelope_with_arrow:',
            ':mailbox_closed:',
            ':mailbox:',
            ':mailbox_with_mail:',
            ':mailbox_with_no_mail:',
            ':postbox:',
            ':postal_horn:',
            ':newspaper:',
            ':iphone:',
            ':calling:',
            ':vibration_mode:',
            ':mobile_phone_off:',
            ':no_mobile_phones:',
            ':signal_strength:',
            ':camera:',
            ':camera_with_flash:',
            ':video_camera:',
            ':tv:',
            ':radio:',
            ':vhs:',
            ':film_projector:',
            ':prayer_beads:',
            ':twisted_rightwards_arrows:',
            ':repeat:',
            ':repeat_one:',
            ':arrows_clockwise:',
            ':arrows_counterclockwise:',
            ':low_brightness:',
            ':high_brightness:',
            ':mute:',
            ':speaker:',
            ':sound:',
            ':loud_sound:',
            ':battery:',
            ':electric_plug:',
            ':mag:',
            ':mag_right:',
            ':lock_with_ink_pen:',
            ':closed_lock_with_key:',
            ':key:',
            ':lock:',
            ':unlock:',
            ':bell:',
            ':no_bell:',
            ':bookmark:',
            ':link:',
            ':radio_button:',
            ':back:',
            ':end:',
            ':on:',
            ':soon:',
            ':top:',
            ':underage:',
            ':keycap_ten:',
            ':capital_abcd:',
            ':abcd:',
            ':1234:',
            ':symbols:',
            ':abc:',
            ':fire:',
            ':flashlight:',
            ':wrench:',
            ':hammer:',
            ':nut_and_bolt:',
            ':hocho:',
            ':gun:',
            ':microscope:',
            ':telescope:',
            ':crystal_ball:',
            ':six_pointed_star:',
            ':beginner:',
            ':trident:',
            ':black_square_button:',
            ':white_square_button:',
            ':red_circle:',
            ':large_blue_circle:',
            ':large_orange_diamond:',
            ':large_blue_diamond:',
            ':small_orange_diamond:',
            ':small_blue_diamond:',
            ':small_red_triangle:',
            ':small_red_triangle_down:',
            ':arrow_up_small:',
            ':arrow_down_small:',
            ':om_symbol:',
            ':dove_of_peace:',
            ':kaaba:',
            ':mosque:',
            ':synagogue:',
            ':menorah_with_nine_branches:',
            ':clock1:',
            ':clock2:',
            ':clock3:',
            ':clock4:',
            ':clock5:',
            ':clock6:',
            ':clock7:',
            ':clock8:',
            ':clock9:',
            ':clock10:',
            ':clock11:',
            ':clock12:',
            ':clock130:',
            ':clock230:',
            ':clock330:',
            ':clock430:',
            ':clock530:',
            ':clock630:',
            ':clock730:',
            ':clock830:',
            ':clock930:',
            ':clock1030:',
            ':clock1130:',
            ':clock1230:',
            ':candle:',
            ':mantelpiece_clock:',
            ':hole:',
            ':man_in_business_suit_levitating:',
            ':female-detective:',
            ':male-detective:',
            ':sleuth_or_spy:',
            ':dark_sunglasses:',
            ':spider:',
            ':spider_web:',
            ':joystick:',
            ':man_dancing:',
            ':linked_paperclips:',
            ':lower_left_ballpoint_pen:',
            ':lower_left_fountain_pen:',
            ':lower_left_paintbrush:',
            ':lower_left_crayon:',
            ':raised_hand_with_fingers_splayed:',
            ':middle_finger:',
            ':spock-hand:',
            ':black_heart:',
            ':desktop_computer:',
            ':printer:',
            ':three_button_mouse:',
            ':trackball:',
            ':frame_with_picture:',
            ':card_index_dividers:',
            ':card_file_box:',
            ':file_cabinet:',
            ':wastebasket:',
            ':spiral_note_pad:',
            ':spiral_calendar_pad:',
            ':compression:',
            ':old_key:',
            ':rolled_up_newspaper:',
            ':dagger_knife:',
            ':speaking_head_in_silhouette:',
            ':left_speech_bubble:',
            ':right_anger_bubble:',
            ':ballot_box_with_ballot:',
            ':world_map:',
            ':mount_fuji:',
            ':tokyo_tower:',
            ':statue_of_liberty:',
            ':japan:',
            ':moyai:',
            ':grinning:',
            ':grin:',
            ':joy:',
            ':smiley:',
            ':smile:',
            ':sweat_smile:',
            ':laughing:',
            ':innocent:',
            ':smiling_imp:',
            ':wink:',
            ':blush:',
            ':yum:',
            ':relieved:',
            ':heart_eyes:',
            ':sunglasses:',
            ':smirk:',
            ':neutral_face:',
            ':expressionless:',
            ':unamused:',
            ':sweat:',
            ':pensive:',
            ':confused:',
            ':confounded:',
            ':kissing:',
            ':kissing_heart:',
            ':kissing_smiling_eyes:',
            ':kissing_closed_eyes:',
            ':stuck_out_tongue:',
            ':stuck_out_tongue_winking_eye:',
            ':stuck_out_tongue_closed_eyes:',
            ':disappointed:',
            ':worried:',
            ':angry:',
            ':rage:',
            ':cry:',
            ':persevere:',
            ':triumph:',
            ':disappointed_relieved:',
            ':frowning:',
            ':anguished:',
            ':fearful:',
            ':weary:',
            ':sleepy:',
            ':tired_face:',
            ':grimacing:',
            ':sob:',
            ':open_mouth:',
            ':hushed:',
            ':cold_sweat:',
            ':scream:',
            ':astonished:',
            ':flushed:',
            ':sleeping:',
            ':dizzy_face:',
            ':no_mouth:',
            ':mask:',
            ':smile_cat:',
            ':joy_cat:',
            ':smiley_cat:',
            ':heart_eyes_cat:',
            ':smirk_cat:',
            ':kissing_cat:',
            ':pouting_cat:',
            ':crying_cat_face:',
            ':scream_cat:',
            ':slightly_frowning_face:',
            ':slightly_smiling_face:',
            ':upside_down_face:',
            ':face_with_rolling_eyes:',
            ':woman-gesturing-no:',
            ':man-gesturing-no:',
            ':no_good:',
            ':woman-gesturing-ok:',
            ':man-gesturing-ok:',
            ':ok_woman:',
            ':woman-bowing:',
            ':man-bowing:',
            ':bow:',
            ':see_no_evil:',
            ':hear_no_evil:',
            ':speak_no_evil:',
            ':woman-raising-hand:',
            ':man-raising-hand:',
            ':raising_hand:',
            ':raised_hands:',
            ':woman-frowning:',
            ':man-frowning:',
            ':person_frowning:',
            ':woman-pouting:',
            ':man-pouting:',
            ':person_with_pouting_face:',
            ':pray:',
            ':rocket:',
            ':helicopter:',
            ':steam_locomotive:',
            ':railway_car:',
            ':bullettrain_side:',
            ':bullettrain_front:',
            ':train2:',
            ':metro:',
            ':light_rail:',
            ':station:',
            ':tram:',
            ':train:',
            ':bus:',
            ':oncoming_bus:',
            ':trolleybus:',
            ':busstop:',
            ':minibus:',
            ':ambulance:',
            ':fire_engine:',
            ':police_car:',
            ':oncoming_police_car:',
            ':taxi:',
            ':oncoming_taxi:',
            ':car:',
            ':oncoming_automobile:',
            ':blue_car:',
            ':truck:',
            ':articulated_lorry:',
            ':tractor:',
            ':monorail:',
            ':mountain_railway:',
            ':suspension_railway:',
            ':mountain_cableway:',
            ':aerial_tramway:',
            ':ship:',
            ':woman-rowing-boat:',
            ':man-rowing-boat:',
            ':rowboat:',
            ':speedboat:',
            ':traffic_light:',
            ':vertical_traffic_light:',
            ':construction:',
            ':rotating_light:',
            ':triangular_flag_on_post:',
            ':door:',
            ':no_entry_sign:',
            ':smoking:',
            ':no_smoking:',
            ':put_litter_in_its_place:',
            ':do_not_litter:',
            ':potable_water:',
            ':non-potable_water:',
            ':bike:',
            ':no_bicycles:',
            ':woman-biking:',
            ':man-biking:',
            ':bicyclist:',
            ':woman-mountain-biking:',
            ':man-mountain-biking:',
            ':mountain_bicyclist:',
            ':woman-walking:',
            ':man-walking:',
            ':walking:',
            ':no_pedestrians:',
            ':children_crossing:',
            ':mens:',
            ':womens:',
            ':restroom:',
            ':baby_symbol:',
            ':toilet:',
            ':wc:',
            ':shower:',
            ':bath:',
            ':bathtub:',
            ':passport_control:',
            ':customs:',
            ':baggage_claim:',
            ':left_luggage:',
            ':couch_and_lamp:',
            ':sleeping_accommodation:',
            ':shopping_bags:',
            ':bellhop_bell:',
            ':bed:',
            ':place_of_worship:',
            ':octagonal_sign:',
            ':shopping_trolley:',
            ':hammer_and_wrench:',
            ':shield:',
            ':oil_drum:',
            ':motorway:',
            ':railway_track:',
            ':motor_boat:',
            ':small_airplane:',
            ':airplane_departure:',
            ':airplane_arriving:',
            ':satellite:',
            ':passenger_ship:',
            ':scooter:',
            ':motor_scooter:',
            ':canoe:',
            ':sled:',
            ':flying_saucer:',
            ':skateboard:',
            ':zipper_mouth_face:',
            ':money_mouth_face:',
            ':face_with_thermometer:',
            ':nerd_face:',
            ':thinking_face:',
            ':face_with_head_bandage:',
            ':robot_face:',
            ':hugging_face:',
            ':the_horns:',
            ':call_me_hand:',
            ':raised_back_of_hand:',
            ':left-facing_fist:',
            ':right-facing_fist:',
            ':handshake:',
            ':crossed_fingers:',
            ':i_love_you_hand_sign:',
            ':face_with_cowboy_hat:',
            ':clown_face:',
            ':nauseated_face:',
            ':rolling_on_the_floor_laughing:',
            ':drooling_face:',
            ':lying_face:',
            ':woman-facepalming:',
            ':man-facepalming:',
            ':face_palm:',
            ':sneezing_face:',
            ':face_with_raised_eyebrow:',
            ':star-struck:',
            ':zany_face:',
            ':shushing_face:',
            ':face_with_symbols_on_mouth:',
            ':face_with_hand_over_mouth:',
            ':face_vomiting:',
            ':exploding_head:',
            ':pregnant_woman:',
            ':breast-feeding:',
            ':palms_up_together:',
            ':selfie:',
            ':prince:',
            ':man_in_tuxedo:',
            ':mrs_claus:',
            ':woman-shrugging:',
            ':man-shrugging:',
            ':shrug:',
            ':woman-cartwheeling:',
            ':man-cartwheeling:',
            ':person_doing_cartwheel:',
            ':woman-juggling:',
            ':man-juggling:',
            ':juggling:',
            ':fencer:',
            ':woman-wrestling:',
            ':man-wrestling:',
            ':wrestlers:',
            ':woman-playing-water-polo:',
            ':man-playing-water-polo:',
            ':water_polo:',
            ':woman-playing-handball:',
            ':man-playing-handball:',
            ':handball:',
            ':wilted_flower:',
            ':drum_with_drumsticks:',
            ':clinking_glasses:',
            ':tumbler_glass:',
            ':spoon:',
            ':goal_net:',
            ':first_place_medal:',
            ':second_place_medal:',
            ':third_place_medal:',
            ':boxing_glove:',
            ':martial_arts_uniform:',
            ':curling_stone:',
            ':lacrosse:',
            ':softball:',
            ':flying_disc:',
            ':croissant:',
            ':avocado:',
            ':cucumber:',
            ':bacon:',
            ':potato:',
            ':carrot:',
            ':baguette_bread:',
            ':green_salad:',
            ':shallow_pan_of_food:',
            ':stuffed_flatbread:',
            ':egg:',
            ':glass_of_milk:',
            ':peanuts:',
            ':kiwifruit:',
            ':pancakes:',
            ':dumpling:',
            ':fortune_cookie:',
            ':takeout_box:',
            ':chopsticks:',
            ':bowl_with_spoon:',
            ':cup_with_straw:',
            ':coconut:',
            ':broccoli:',
            ':pie:',
            ':pretzel:',
            ':cut_of_meat:',
            ':sandwich:',
            ':canned_food:',
            ':leafy_green:',
            ':mango:',
            ':moon_cake:',
            ':bagel:',
            ':smiling_face_with_3_hearts:',
            ':partying_face:',
            ':woozy_face:',
            ':hot_face:',
            ':cold_face:',
            ':pleading_face:',
            ':lab_coat:',
            ':goggles:',
            ':hiking_boot:',
            ':womans_flat_shoe:',
            ':crab:',
            ':lion_face:',
            ':scorpion:',
            ':turkey:',
            ':unicorn_face:',
            ':eagle:',
            ':duck:',
            ':bat:',
            ':shark:',
            ':owl:',
            ':fox_face:',
            ':butterfly:',
            ':deer:',
            ':gorilla:',
            ':lizard:',
            ':rhinoceros:',
            ':shrimp:',
            ':squid:',
            ':giraffe_face:',
            ':zebra_face:',
            ':hedgehog:',
            ':sauropod:',
            ':t-rex:',
            ':cricket:',
            ':kangaroo:',
            ':llama:',
            ':peacock:',
            ':hippopotamus:',
            ':parrot:',
            ':raccoon:',
            ':lobster:',
            ':mosquito:',
            ':microbe:',
            ':badger:',
            ':swan:',
            ':bone:',
            ':leg:',
            ':foot:',
            ':tooth:',
            ':female_superhero:',
            ':male_superhero:',
            ':female_supervillain:',
            ':male_supervillain:',
            ':cheese_wedge:',
            ':cupcake:',
            ':salt:',
            ':face_with_monocle:',
            ':adult:',
            ':child:',
            ':older_adult:',
            ':bearded_person:',
            ':person_with_headscarf:',
            ':woman_in_steamy_room:',
            ':man_in_steamy_room:',
            ':person_in_steamy_room:',
            ':woman_climbing:',
            ':man_climbing:',
            ':person_climbing:',
            ':woman_in_lotus_position:',
            ':man_in_lotus_position:',
            ':person_in_lotus_position:',
            ':female_mage:',
            ':male_mage:',
            ':mage:',
            ':female_fairy:',
            ':male_fairy:',
            ':fairy:',
            ':female_vampire:',
            ':male_vampire:',
            ':vampire:',
            ':mermaid:',
            ':merman:',
            ':merperson:',
            ':female_elf:',
            ':male_elf:',
            ':elf:',
            ':female_genie:',
            ':male_genie:',
            ':genie:',
            ':female_zombie:',
            ':male_zombie:',
            ':zombie:',
            ':brain:',
            ':orange_heart:',
            ':billed_cap:',
            ':scarf:',
            ':gloves:',
            ':coat:',
            ':socks:',
            ':red_envelope:',
            ':firecracker:',
            ':jigsaw:',
            ':test_tube:',
            ':petri_dish:',
            ':dna:',
            ':compass:',
            ':abacus:',
            ':fire_extinguisher:',
            ':toolbox:',
            ':bricks:',
            ':magnet:',
            ':luggage:',
            ':lotion_bottle:',
            ':thread:',
            ':yarn:',
            ':safety_pin:',
            ':teddy_bear:',
            ':broom:',
            ':basket:',
            ':roll_of_paper:',
            ':soap:',
            ':sponge:',
            ':receipt:',
            ':nazar_amulet:',
            ':bangbang:',
            ':interrobang:',
            ':tm:',
            ':information_source:',
            ':left_right_arrow:',
            ':arrow_up_down:',
            ':arrow_upper_left:',
            ':arrow_upper_right:',
            ':arrow_lower_right:',
            ':arrow_lower_left:',
            ':leftwards_arrow_with_hook:',
            ':arrow_right_hook:',
            ':watch:',
            ':hourglass:',
            ':keyboard:',
            ':eject:',
            ':fast_forward:',
            ':rewind:',
            ':arrow_double_up:',
            ':arrow_double_down:',
            ':black_right_pointing_double_triangle_with_vertical_bar:',
            ':black_left_pointing_double_triangle_with_vertical_bar:',
            ':black_right_pointing_triangle_with_double_vertical_bar:',
            ':alarm_clock:',
            ':stopwatch:',
            ':timer_clock:',
            ':hourglass_flowing_sand:',
            ':double_vertical_bar:',
            ':black_square_for_stop:',
            ':black_circle_for_record:',
            ':m:',
            ':black_small_square:',
            ':white_small_square:',
            ':arrow_forward:',
            ':arrow_backward:',
            ':white_medium_square:',
            ':black_medium_square:',
            ':white_medium_small_square:',
            ':black_medium_small_square:',
            ':sunny:',
            ':cloud:',
            ':umbrella:',
            ':snowman:',
            ':comet:',
            ':phone:',
            ':ballot_box_with_check:',
            ':umbrella_with_rain_drops:',
            ':coffee:',
            ':shamrock:',
            ':point_up:',
            ':skull_and_crossbones:',
            ':radioactive_sign:',
            ':biohazard_sign:',
            ':orthodox_cross:',
            ':star_and_crescent:',
            ':peace_symbol:',
            ':yin_yang:',
            ':wheel_of_dharma:',
            ':white_frowning_face:',
            ':relaxed:',
            ':female_sign:',
            ':male_sign:',
            ':aries:',
            ':taurus:',
            ':gemini:',
            ':cancer:',
            ':leo:',
            ':virgo:',
            ':libra:',
            ':scorpius:',
            ':sagittarius:',
            ':capricorn:',
            ':aquarius:',
            ':pisces:',
            ':chess_pawn:',
            ':spades:',
            ':clubs:',
            ':hearts:',
            ':diamonds:',
            ':hotsprings:',
            ':recycle:',
            ':infinity:',
            ':wheelchair:',
            ':hammer_and_pick:',
            ':anchor:',
            ':crossed_swords:',
            ':medical_symbol:',
            ':scales:',
            ':alembic:',
            ':gear:',
            ':atom_symbol:',
            ':fleur_de_lis:',
            ':warning:',
            ':zap:',
            ':white_circle:',
            ':black_circle:',
            ':coffin:',
            ':funeral_urn:',
            ':soccer:',
            ':baseball:',
            ':snowman_without_snow:',
            ':partly_sunny:',
            ':thunder_cloud_and_rain:',
            ':ophiuchus:',
            ':pick:',
            ':helmet_with_white_cross:',
            ':chains:',
            ':no_entry:',
            ':shinto_shrine:',
            ':church:',
            ':mountain:',
            ':umbrella_on_ground:',
            ':fountain:',
            ':golf:',
            ':ferry:',
            ':boat:',
            ':skier:',
            ':ice_skate:',
            ':woman-bouncing-ball:',
            ':man-bouncing-ball:',
            ':person_with_ball:',
            ':tent:',
            ':fuelpump:',
            ':scissors:',
            ':white_check_mark:',
            ':airplane:',
            ':email:',
            ':fist:',
            ':hand:',
            ':v:',
            ':writing_hand:',
            ':pencil2:',
            ':black_nib:',
            ':heavy_check_mark:',
            ':heavy_multiplication_x:',
            ':latin_cross:',
            ':star_of_david:',
            ':sparkles:',
            ':eight_spoked_asterisk:',
            ':eight_pointed_black_star:',
            ':snowflake:',
            ':sparkle:',
            ':x:',
            ':negative_squared_cross_mark:',
            ':question:',
            ':grey_question:',
            ':grey_exclamation:',
            ':exclamation:',
            ':heavy_heart_exclamation_mark_ornament:',
            ':heart:',
            ':heavy_plus_sign:',
            ':heavy_minus_sign:',
            ':heavy_division_sign:',
            ':arrow_right:',
            ':curly_loop:',
            ':loop:',
            ':arrow_heading_up:',
            ':arrow_heading_down:',
            ':arrow_left:',
            ':arrow_up:',
            ':arrow_down:',
            ':black_large_square:',
            ':white_large_square:',
            ':star:',
            ':o:',
            ':wavy_dash:',
            ':part_alternation_mark:',
            ':congratulations:',
            ':secret:'
        )]
        [string]$Shortcode,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    if ($FileID) {
        Write-Verbose -Message 'sticker file_id provided.'
        $sticker = $FileID
    } #if_fileid
    else {
        Write-Verbose -Message 'Sticker by emoji shortcode and sticker pack.'
        $stickerPackInfo = Get-TelegramStickerPackInfo -BotToken $BotToken -StickerSetName $StickerSetName
        if (-not ($stickerPackInfo -eq $false)) {
            $sticker = $stickerPackInfo | Where-Object { $_.Shortcode -eq $Shortcode } | Select-Object -First 1
            if (-not $sticker) {
                throw ('The sticker pack {0} does not contain the emoji {1}' -f $StickerSetName, $Shortcode)
            } #if_noSticker
            else {
                $sticker = $sticker.file_id
            } #else_noSticker
        } #if_sticker_info
        else {
            throw 'Unable to obtain sticker pack information.'
        } #else_sticker_info
    } #else_fileid

    $form = @{
        chat_id              = $ChatID
        sticker              = $sticker
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendSticker' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending sticker...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the sticker:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramSticker



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramTextMessage {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Text of the message to be sent')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$Message,

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Custom or inline keyboard object')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [psobject]$Keyboard,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Disables link previews')]
        [switch]$DisablePreview, #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $payload = @{
        chat_id                  = $ChatID
        text                     = $Message
        parse_mode               = $ParseMode
        disable_web_page_preview = $DisablePreview.IsPresent
        disable_notification     = $DisableNotification.IsPresent
        protect_content          = $ProtectContent.IsPresent
    } #payload

    if ($Keyboard) {
        $payload.Add('reply_markup', $Keyboard)
    }

    $uri = 'https://api.telegram.org/bot{0}/sendMessage' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending message...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = ([System.Text.Encoding]::UTF8.GetBytes((ConvertTo-Json -Compress -InputObject $payload -Depth 50)))
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramTextMessage



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLAnimation {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'URL path to animation')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$AnimationURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'animation caption')]
        [string]$Caption,

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported animation extension...'
    $fileTypeEval = Test-URLExtension -URL $AnimationURL -Type Animation
    if ($fileTypeEval -eq $false) {
        throw ('The specified animation URL: {0} does not contain a supported extension.' -f $AnimationURL)
    } #if_animationExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_animationExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $AnimationURL
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_animationSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_animationSize

    $payload = @{
        chat_id              = $ChatID
        animation            = $AnimationURL
        caption              = $Caption
        parse_mode           = $ParseMode
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendAnimation' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending animation...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLAnimation



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLAudio {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Local path to file you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$AudioURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Caption for file')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Duration of the audio in seconds')]
        [int]$Duration,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Performer')]
        [string]$Performer,

        [Parameter(Mandatory = $false,
            HelpMessage = 'TrackName')]
        [string]$Title,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Original File Name')]
        [string]$FileName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported audio extension...'
    $fileTypeEval = Test-URLExtension -URL $AudioURL -Type Audio
    if ($fileTypeEval -eq $false) {
        throw ('The specified audio URL: {0} does not contain a supported extension.' -f $AudioURL)
    } #if_audioExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_audioExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $AudioURL
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_audioSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_audioSize

    $payload = @{
        chat_id              = $ChatID
        audio                = $AudioURL
        caption              = $Caption
        parse_mode           = $ParseMode
        duration             = $Duration
        performer            = $Performer
        title                = $Title
        file_name            = $FileName
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendAudio' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending audio...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLAudio



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLDocument {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'URL path to file')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$FileURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'File caption')]
        [string]$Caption,

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Disables automatic server-side content type detection')]
        [switch]$DisableContentTypeDetection,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported document extension...'
    $fileTypeEval = Test-URLExtension -URL $FileURL -Type Document
    if ($fileTypeEval -eq $false) {
        throw ('The specified file URL: {0} does not contain a supported extension.' -f $FileURL)
    } #if_documentExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_documentExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $FileURL
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_documentSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_documentSize

    $payload = @{
        chat_id                        = $ChatID
        document                       = $FileURL
        caption                        = $Caption
        parse_mode                     = $ParseMode
        disable_content_type_detection = $DisableContentTypeDetection.IsPresent
        disable_notification           = $DisableNotification.IsPresent
        protect_content                = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendDocument' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending document...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLDocument



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLPhoto {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'URL path to photo')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$PhotoURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Photo caption')]
        [string]$Caption,

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported photo extension...'
    $fileTypeEval = Test-URLExtension -URL $PhotoURL -Type Photo
    if ($fileTypeEval -eq $false) {
        throw ('The specified photo URL: {0} does not contain a supported extension.' -f $AnimationURL)
    } #if_photoExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_photoExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $PhotoURL
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_photoSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_photoSize

    $payload = @{
        chat_id              = $ChatID
        photo                = $PhotoURL
        caption              = $Caption
        parse_mode           = $ParseMode
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendphoto' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending photo...'
    $invokeRestMethodSplat = @{
        Uri         = ('https://api.telegram.org/bot{0}/sendphoto' -f $BotToken)
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLPhoto



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLSticker {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'URL path to sticker')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$StickerURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported sticker extension...'
    $fileTypeEval = Test-URLExtension -URL $StickerURL -Type Sticker
    if ($fileTypeEval -eq $false) {
        throw ('The specified sticker URL: {0} does not contain a supported extension.' -f $StickerURL)
    } #if_stickerExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_stickerExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $StickerURL
    if ($fileSizeEval -eq $false) {
        throw 'File extension is not a supported Sticker type'
    } #if_stickerSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_stickerSize

    $payload = @{
        chat_id              = $ChatID
        sticker              = $StickerURL
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendSticker' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending sticker...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLSticker



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramURLVideo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'URL to file you wish to send')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$VideoURL,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Duration of video in seconds')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Duration,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Video width')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Width,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Video height')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [Int32]$Height,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Original File Name')]
        [string]$FileName,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Caption for file')]
        [string]$Caption = '', #set to false by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'HTML vs Markdown for message formatting')]
        [ValidateSet('Markdown', 'MarkdownV2', 'HTML')]
        [string]$ParseMode = 'HTML', #set to HTML by default

        [Parameter(Mandatory = $false,
            HelpMessage = 'Use if the uploaded video is suitable for streaming')]
        [switch]$Streaming,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    Write-Verbose -Message 'Verifying URL leads to supported document extension...'
    $fileTypeEval = Test-URLExtension -URL $VideoURL -Type Video
    if ($fileTypeEval -eq $false) {
        throw ('The specified Video URL: {0} does not contain a supported extension.' -f $VideoURL)
    } #if_videoExtension
    else {
        Write-Verbose -Message 'Extension supported.'
    } #else_videoExtension

    Write-Verbose -Message 'Verifying URL presence and file size...'
    $fileSizeEval = Test-URLFileSize -URL $VideoURL
    if ($fileSizeEval -eq $false) {
        throw 'File size does not meet Telegram requirements'
    } #if_videoSize
    else {
        Write-Verbose -Message 'File size verified.'
    } #else_videoSize

    $payload = @{
        chat_id              = $ChatID
        video                = $VideoURL
        duration             = $Duration
        width                = $Width
        height               = $Height
        file_name            = $FileName
        caption              = $Caption
        parse_mode           = $ParseMode
        supports_streaming   = $Streaming
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #payload

    $uri = 'https://api.telegram.org/bot{0}/sendVideo' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending video...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        Body        = (ConvertTo-Json -Compress -InputObject $payload)
        ErrorAction = 'Stop'
        ContentType = 'application/json'
        Method      = 'Post'
    }
    try {
        Write-Verbose -Message 'Sending message...'
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram message:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramURLVideo



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Send-TelegramVenue {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken, #you could set a token right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = '-#########')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$ChatID, #you could set a Chat ID right here if you wanted

        [Parameter(Mandatory = $true,
            HelpMessage = 'Latitude of the venue')]
        [ValidateRange(-90, 90)]
        [single]$Latitude,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Longitude of the venue')]
        [ValidateRange(-180, 180)]
        [single]$Longitude,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Name of the venue')]
        [ValidateNotNullOrEmpty()]
        [string]$Title,

        [Parameter(Mandatory = $true,
            HelpMessage = 'Address of the venue')]
        [ValidateNotNullOrEmpty()]
        [string]$Address,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Send the message silently')]
        [switch]$DisableNotification,

        [Parameter(Mandatory = $false,
            HelpMessage = 'Protects the contents of the sent message from forwarding and saving')]
        [switch]$ProtectContent
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $form = @{
        chat_id              = $ChatID
        latitude             = $Latitude
        longitude            = $Longitude
        title                = $Title
        address              = $Address
        disable_notification = $DisableNotification.IsPresent
        protect_content      = $ProtectContent.IsPresent
    } #form

    $uri = 'https://api.telegram.org/bot{0}/sendVenue' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Sending venue...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Form        = $form
        Method      = 'Post'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered sending the Telegram venue:'
        Write-Error $_
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Send-TelegramVenue



<#
.EXTERNALHELP PoshGram-help.xml
#>

function Test-BotToken {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true,
            HelpMessage = '#########:xxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxx')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$BotToken
    )

    Write-Verbose -Message ('Starting: {0}' -f $MyInvocation.Mycommand)

    $uri = 'https://api.telegram.org/bot{0}/getMe' -f $BotToken
    Write-Debug -Message ('Base URI: {0}' -f $uri)

    Write-Verbose -Message 'Testing Bot Token...'
    $invokeRestMethodSplat = @{
        Uri         = $uri
        ErrorAction = 'Stop'
        Method      = 'Get'
    }
    try {
        $results = Invoke-RestMethod @invokeRestMethodSplat
    } #try_messageSend
    catch {
        Write-Warning -Message 'An error was encountered testing the BOT token:'
        if ($_.ErrorDetails) {
            $results = $_.ErrorDetails | ConvertFrom-Json -ErrorAction SilentlyContinue
        }
        else {
            throw $_
        }
    } #catch_messageSend

    return $results
} #function_Test-BotToken