Public/Invoke-SNOWWebRequest.ps1

function Invoke-SNOWWebRequest {

    <#
    .SYNOPSIS
        A generic way to make rest calls to servicenow API's
    .DESCRIPTION
        A wrapper for Invoke-WebRequest & RestMethod that leverages authentication set with Set-SNOWAuth, provides support for proxy auth and also handles rate limiting (if set with -HandleRateLimiting on Set-SNOWAuth).
    .LINK
        https://github.com/insomniacc/PSSnow/blob/main/docs/functions/Invoke-SNOWWebRequest.md
    .EXAMPLE
        $Response = Invoke-SNOWWebRequest -UseRestMethod -uri "api/now/v2/table/sys_user?sysparm_limit=1"
    .EXAMPLE
        $Body = @{first_name="john";last_name="smith"} | ConvertTo-json
        $Headers = @{"Content-Type"="Application/Json"}
        $Response = Invoke-SNOWWebRequest -UseRestMethod -uri "api/now/v2/table/sys_user" -Method "POST" -Body $Body -Headers $Headers
    #>
    

    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [string]$URI,
        [ValidateSet(
            'Default',
            'Delete',
            'Get',
            'Head',
            'Merge',
            'Options',
            'Patch',
            'Post',
            'Put',
            'Trace'
        )]
        [string]$Method = "Get",
        [hashtable]$Headers,
        [object]$Body,
        [string]$ContentType,
        [string]$OutFile,
        [string]$InFile,
        [string]$TransferEncoding,
        [switch]$PassThru,
        [int]$WebCallTimeoutSeconds = $Script:SNOWAuth.WebCallTimeoutSeconds,
        [switch]$UseRestMethod,
        [switch]$SkipHeaderValidation
    )

    Begin {
        Assert-SNOWAuth

        if($URI -notlike "https://$($script:SNOWAuth.Instance).service-now.com*"){
            $PSBoundParameters.URI = "https://$($script:SNOWAuth.Instance).service-now.com/$URI"
        }

        #? Timeout properties
        if($WebCallTimeoutSeconds -gt 0){
            if($PSVersionTable.PSVersion.ToString() -gt 7.3){
                $TimeoutSplat = @{
                    OperationTimeoutSeconds = $WebCallTimeoutSeconds
                }
            }else{
                $TimeoutSplat = @{
                    TimeoutSec = $WebCallTimeoutSeconds
                }
            }
        }else{
            $TimeoutSplat = @{}
        }

        #? Proxy Auth
        if($script:SNOWAuth.ProxyAuth){
            $ProxyAuth = $script:SNOWAuth.ProxyAuth
        }else{
            $ProxyAuth = @{}
        }
        
        #? Headers
        if($Headers){
            $PSBoundParameters.Headers = (Get-AuthHeader) + $Headers
        }else{
            $PSBoundParameters.Headers = (Get-AuthHeader)
        }

        #? Version Control
        if($PSVersionTable.PSVersion.ToString() -lt "5.2"){
            if($SkipHeaderValidation){
                Write-Warning "PSVersion 5.1 does not support -SkipHeaderValidation. Omitting parameter."
            }
        }

        #? Cleanup
        # Remove all non standard properties from passthrough params
        [Void]$PSBoundParameters.Remove('WebCallTimeoutSeconds')
        [Void]$PSBoundParameters.Remove('UseRestMethod')

        # Removes GUI and increases performance
        $ProgressPreference = "SilentlyContinue"
    }

    Process {
       Do{
            try{
                if($UseRestMethod.IsPresent){
                    Invoke-RestMethod @PSBoundParameters @ProxyAuth @TimeoutSplat -UseBasicParsing -ErrorAction Stop
                }else{
                    Invoke-WebRequest @PSBoundParameters @ProxyAuth @TimeoutSplat -UseBasicParsing -ErrorAction Stop
                }
                break
            }catch{
                if($_.Exception.Response.StatusCode -eq 429){
                    
                    $RateLimitRule = $_.Exception.Response.Headers.GetValues("X-RateLimit-Rule") | Out-String
                    $RateLimitLimit = $_.Exception.Response.Headers.GetValues("X-RateLimit-Limit") | Out-String
                    
                    $ResetTime = $_.Exception.Response.Headers.GetValues("X-RateLimit-Reset") | Out-String
                    $UnixDate = get-date "1/1/1970"
                    $RateLimitResetTime = $UnixDate.AddSeconds($ResetTime).ToLocalTime()
                    $RateLimitResetDuration = New-TimeSpan -Start (get-date) -End $RateLimitResetTime

                    if($Script:SNOWAuth.HandleRatelimiting){
                        Write-Warning "Rate limit hit, only $RateLimitLimit requests allowed per hour (Rule: $RateLimitRule), cooling off for $RateLimitResetDuration"
                        Start-Sleep $RateLimitResetDuration.TotalSeconds + 1
                    }else{
                        Write-Error "Rate limit hit (Rule: $RateLimitRule). Duration until reset: $RateLimitResetDuration. Use -HandleRateLimiting on Set-SNOWAuth to automatically wait and retry."
                        break
                    }
                }else{
                    throw
                }
            }
        }While($true)
    }
}