Private/Invoke-AutomateAPIMaster.ps1
function Invoke-AutomateAPIMaster { <# .SYNOPSIS Internal function used to make API calls .DESCRIPTION Internal function used to make API calls .PARAMETER Arguments Required parameters for the API call .OUTPUTS The returned results from the API call .NOTES Version: 1.1.0 Author: Darren White Creation Date: 2020-07-03 Purpose/Change: Initial script development Update Date: 2020-08-01 Purpose/Change: Change to use CWAIsConnected script variable to track connection state Update Date: 2020-11-19 Author: Brandon Fahnestock Purpose/Change: ConnectWise Automate v2020.11 requires a registered ClientID for API access. Added Support for ClientIDs .EXAMPLE Invoke-AutomateAPIMaster -Arguments $Arguments #> [CmdletBinding()] param( [Parameter(Mandatory = $True)] $Arguments, [int]$MaxRetry = 5 ) Begin { } Process { # Check that we have cached connection info If (!$Script:CWAIsConnected) { $ErrorMessage = @() $ErrorMessage += "Not connected to an Automate server." $ErrorMessage += $_.ScriptStackTrace $ErrorMessage += '' $ErrorMessage += "----> Run 'Connect-AutomateAPI' to initialize the connection before issuing other AutomateAPI commandlets." Write-Error ($ErrorMessage | Out-String) Return } # Add default set of arguments $Arguments.Item('UseBasicParsing') = $Null If (!$Arguments.Headers) { $Arguments.Headers = @{} } Foreach ($Key in $script:CWAToken.Keys) { If ($Arguments.Headers.Keys -notcontains $Key) { $Arguments.Headers += @{$Key = $script:CWAToken.$Key } } } # if(!$Arguments.SessionVariable){ $Arguments.WebSession = $global:CWMServerConnection.Session } # Check URI format If ($Arguments.URI -notlike '*`?*' -and $Arguments.URI -like '*`&*') { $Arguments.URI = $Arguments.URI -replace '(.*?)&(.*)', '$1?$2' } If ($Arguments.URI -notmatch '^https?://') { $Arguments.URI = ($Script:CWAServer + $Arguments.URI) } #Add required CWA ClientID to API request If ($Arguments.Headers.Keys -notcontains 'clientID' -and $Script:CWAClientID -match '.+') { $Arguments.Headers += @{'clientID' = "$Script:CWAClientID" } } # Issue request Try { Write-Debug "Calling AutomateAPI with the following arguments:`n$(($Arguments|Out-String -Stream) -join "`n")" $ProgressPreference = 'SilentlyContinue' $Result = Invoke-WebRequest @Arguments } Catch { If ($_.Exception.Response) { if ($psversiontable.psversion.major -lt 6) { # Read exception response $ErrorStream = $_.Exception.Response.GetResponseStream() $Reader = New-Object System.IO.StreamReader($ErrorStream) $global:ErrBody = $Reader.ReadToEnd() | ConvertFrom-Json # Start error message $ErrorMessage = @() if ($errBody.code) { $ErrorMessage += "An exception has been thrown." $ErrorMessage += $_.ScriptStackTrace $ErrorMessage += '' $ErrorMessage += "--> $($ErrBody.code)" if ($errBody.code -eq 'Unauthorized') { $ErrorMessage += "-----> $($ErrBody.message)" $ErrorMessage += "-----> Use 'Connect-AutomateAPI' to set new authentication." } else { $ErrorMessage += "-----> $($ErrBody.message)" $ErrorMessage += "-----> ^ Error has not been documented please report. ^" } } } if ($_.ErrorDetails) { $ErrorMessage += "An error has been thrown." $ErrorMessage += $_.ScriptStackTrace $ErrorMessage += '' $global:errDetails = $_.ErrorDetails | ConvertFrom-Json $ErrorMessage += "--> $($errDetails.code)" $ErrorMessage += "--> $($errDetails.message)" if ($errDetails.errors.message) { $ErrorMessage += "-----> $($errDetails.errors.message)" } } Write-Error ($ErrorMessage | out-string) Return } } # Not sure this will be hit with current iwr error handling # May need to move to catch block need to find test # TODO Find test for retry # Retry the request $Retry = 0 while ($Retry -lt $MaxRetry -and $Result.StatusCode -eq 500) { $Retry++ $Wait = $([math]::pow( 2, $Retry)) Write-Warning "Issue with request, status: $($Result.StatusCode) $($Result.StatusDescription)" Write-Warning "$($Retry)/$($MaxRetry) retries, waiting $($Wait)ms." Start-Sleep -Milliseconds $Wait $ProgressPreference = 'SilentlyContinue' $Result = Invoke-WebRequest @Arguments } If ($Retry -ge $MaxRetry -and $Result.StatusCode -eq 500) { $Script:CWAIsConnected = $False Write-Error "Max retries hit. Status: $($Result.StatusCode) $($Result.StatusDescription)" Return } } End { Return $Result } } |