Public/Invoke/Invoke-CWMAllResult.ps1
|
<#
.SYNOPSIS Automatic pagination handler that retrieves all pages of results. .DESCRIPTION Handles automatic pagination for API requests using forward-only pagination. Called by Invoke-CWMGetMaster and Invoke-CWMSearchMaster when -all switch is used. Automatically follows pagination links in response headers to retrieve all pages of results. Uses page size 1000 (the API maximum, or -PageSize) and forward-only pagination for better performance. This function iterates through all pages until no more results are available. .PARAMETER Arguments Hashtable containing web request parameters: - Uri: Initial request URI - Method: HTTP method (GET or POST) - Body: Request body (for POST requests) - Headers: Request headers .PARAMETER PageSize Records per request. Defaults to 1000, the API's maximum; values below 1 or above 1000 use 1000. .EXAMPLE $Condition = [System.Web.HttpUtility]::UrlEncode("status/name='Open'") $RequestArguments = @{ Uri = "https://na.myconnectwise.net/v4_6_release/apis/3.0/service/tickets?conditions=$Condition" Method = 'GET' } Invoke-CWMAllResult -Arguments $RequestArguments Retrieves all pages of open tickets. .NOTES Author: Chris Taylor Internal Function: - Called by Invoke-CWMGetMaster and Invoke-CWMSearchMaster - Uses forward-only pagination for performance - Uses page size 1000 (the API maximum) unless -PageSize is smaller - Follows Link headers for next page, but only to the connected server: the next-page URL must use https (or the scheme of the first request, never a downgrade) and the connection's host and port. Any other URL stops paging with a terminating error, so credentials are never sent to another host and the caller never gets a silently partial result. - Returns results from all pages Performance: - More efficient than manual pagination - Reduces number of API calls - Recommended for retrieving large datasets .LINK Invoke-CWMWebRequest .LINK Invoke-CWMGetMaster .LINK Invoke-CWMSearchMaster #> function Invoke-CWMAllResult { [CmdletBinding()] param( $Arguments, [int]$PageSize = 1000 ) if ($PageSize -lt 1 -or $PageSize -gt 1000) { $PageSize = 1000 } # The next-page URL comes from the server's Link header and is requested with the connection's credentials, # so it may only point at the connected server, over https (never a downgrade from the first request). try { $AllowedUri = [uri]"https://$($script:CWMServerConnection.Server)"; $AllowedHost = $AllowedUri.Host } catch { $AllowedUri = $null; $AllowedHost = $null } try { $FirstScheme = ([uri][string]$Arguments.Uri).Scheme } catch { $FirstScheme = $null } # Update header for new pagination-type $Arguments.Headers += @{ 'pagination-type' = 'forward-only' } $Arguments.URI += "&pageSize=$PageSize" do { $PageResult = Invoke-CWMWebRequest -Arguments $Arguments if (!$PageResult) { return } if (!$PageResult.Headers.ContainsKey('Link')) { throw "The $((Get-PSCallStack)[2].Command) Endpoint doesn't support 'forward-only' pagination. Please report to ConnectWise." } $Link = Get-CWMResponseHeader -Response $PageResult -Name 'Link' # Link may list several relations (<url>; rel="next", <url>; rel="last"). Follow rel="next"; a single # link without any rel is taken as the next page. $NextPage = $null if ($Link) { $Links = @($Link -split ',(?=\s*<)') $Next = $Links | Where-Object { $_ -match ';\s*rel\s*=\s*"?next"?' } | Select-Object -First 1 if (!$Next -and $Links.Count -eq 1 -and $Links[0] -notmatch ';\s*rel\s*=') { $Next = $Links[0] } if ($Next -match '<([^>]+)>') { $NextPage = $Matches[1] } } $Arguments.Uri = $NextPage ConvertFrom-CWMJson $PageResult.Content if ($NextPage) { $NextUri = $null if (![uri]::TryCreate($NextPage, [System.UriKind]::Absolute, [ref]$NextUri) -or @('https', $FirstScheme) -notcontains $NextUri.Scheme -or !$AllowedHost -or $NextUri.Host -ne $AllowedHost -or $NextUri.UserInfo -or # Same port; an omitted port and the scheme's default (443 for https) count as equal ($NextUri.Port -ne $AllowedUri.Port -and !($NextUri.IsDefaultPort -and $AllowedUri.IsDefaultPort))) { # Terminating: a caller that asked for -all must not carry on with a silently partial result throw "Stopped paging: the server's next-page link points to '$NextPage', which is not an https URL on the connected server ($AllowedHost). The result is incomplete. Please report this at https://github.com/christaylorcodes/ConnectWiseManageAPI/issues" } } } while ($NextPage) } |