Private/NestedFunctions/Invoke-JCApi.ps1
|
function Invoke-JCApi { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0)][ValidateNotNullOrEmpty()][string]$Url, [Parameter(Mandatory = $true, Position = 1)][ValidateNotNullOrEmpty()][string]$Method, [Parameter(Mandatory = $false, Position = 2)][ValidateNotNullOrEmpty()][ValidateRange(1, [int]::MaxValue)][int]$Limit = 100, [Parameter(Mandatory = $false, Position = 3)][ValidateNotNullOrEmpty()][ValidateRange(0, [int]::MaxValue)][int]$Skip = 0, [Parameter(Mandatory = $false, Position = 4)][ValidateNotNull()][array]$Fields = @(), [Parameter(Mandatory = $false, Position = 5)][ValidateNotNull()][string]$Body = '', [Parameter(Mandatory = $false, Position = 6)][ValidateNotNullOrEmpty()][bool]$Paginate = $false, [Parameter(Mandatory = $false, Position = 7)][ValidateNotNullOrEmpty()][switch]$ReturnCount ) begin { # Debug message for parameter call $PSBoundParameters | Out-DebugParameter | Write-Debug # Populate $env:JCApiKey if its not set if ([System.String]::IsNullOrEmpty($env:JCApiKey)) { Connect-JCOnline -force | Out-Null } # Populate $env:JCOrgId if its not set if (-not [System.String]::IsNullOrEmpty($env:JCApiKey) -and [System.String]::IsNullOrEmpty($env:JCOrgId) -and $Url -notlike '*/api/organizations*') { Set-JCOrganization -JumpCloudAPIKey:($env:JCApiKey) | Out-Null } #Set JC headers $Headers = @{ 'Content-Type' = 'application/json'; 'Accept' = 'application/json'; 'x-api-key' = "$($env:JCApiKey)"; 'x-org-id' = "$($env:JCOrgId)"; } # TODO: CUT-4439 need a dynamic list of endpoints that do not accept x-org-id # Organizations endpoint does not accept x-org-id in header if ( ($Url -like '*/api/organizations*') -or ($URL -like "*/api/v2/providers/*") -or ($URL -like "*/api/v2/organizations/*")) { $Headers.Remove('x-org-id') | Out-Null } } process { try { $Results = @() if ([System.String]::IsNullOrEmpty($global:JCUrlBasePath)) { if ($env:JCEnvironment -eq 'EU') { $JCUrlBasePath = 'https://console.eu.jumpcloud.com' } else { $JCUrlBasePath = 'https://console.jumpcloud.com' } } if ($Url -notlike ('*' + $JCUrlBasePath + '*')) { $Url = $JCUrlBasePath + $Url } if ($Url -like '*`?*') { $SearchOperator = '&' } else { $SearchOperator = '?' } # Convert passed in body to json if ($Body) { $ObjectBody = $Body | ConvertFrom-Json } else { $ObjectBody = '' } # Pagination do { $QueryStrings = @() # Add fields if ($Fields) { $JoinedFields = ($Fields -join ' ') if ($ObjectBody.PSObject.Properties.name -eq 'fields') { $JoinedFields = $ObjectBody.fields } else { $ObjectBody = $ObjectBody | Select-Object *, @{Name = 'fields'; Expression = { $JoinedFields } } } if ($Url -notlike '*fields*') { $QueryStrings += 'fields=' + $JoinedFields } } # Add limit if ($ObjectBody.PSObject.Properties.name -eq 'limit') { $ObjectBody.limit = $Limit } else { $ObjectBody = $ObjectBody | Select-Object *, @{Name = 'limit'; Expression = { $Limit } } } if ($Url -notlike '*limit*') { $QueryStrings += 'limit=' + $Limit } # Add skip if ($ObjectBody.PSObject.Properties.name -eq 'skip') { $ObjectBody.skip = $Skip } else { $ObjectBody = $ObjectBody | Select-Object *, @{Name = 'skip'; Expression = { $Skip } } } if ($Url -notlike '*skip*') { $QueryStrings += 'skip=' + $Skip } # Build url query string and body $ObjectBody = $ObjectBody | Select-Object -Property * -ExcludeProperty Length $Body = $ObjectBody | ConvertTo-Json -Depth:(10) -Compress | Sort-Object if ($QueryStrings) { $Uri = $Url + $SearchOperator + (($QueryStrings | Sort-Object) -join '&') } else { $Uri = $Url } # Run request $UserAgent = Get-JCUserAgent Write-Verbose ('Connecting to: ' + $Uri) # PowerShell 5 won't let you send a GET with a body. if ($Method -eq 'GET') { Write-Debug("[CallFunction]: Invoke-WebRequest -Method:('$Method') -Headers:(@" + ($Headers | ConvertTo-Json -Compress).Replace(':', '=').Replace(',', ';') + ") -Uri:('$Uri') -UseBasicParsing -UserAgent:('$UserAgent')") $RequestResult = Invoke-WebRequest -Method:($Method) -Headers:($Headers) -Uri:($Uri) -UserAgent:($UserAgent) -UseBasicParsing } else { Write-Debug("[CallFunction]: Invoke-WebRequest -Method:('$Method') -Headers:(@" + ($Headers | ConvertTo-Json -Compress).Replace(':', '=').Replace(',', ';') + ") -Uri:('$Uri') -UseBasicParsing -UserAgent:('$UserAgent') -Body:('$Body')") $RequestResult = Invoke-WebRequest -Method:($Method) -Headers:($Headers) -Uri:($Uri) -UserAgent:($UserAgent) -Body:($Body) -UseBasicParsing } if ($RequestResult) { $Result = $RequestResult.Content | ConvertFrom-Json $httpMetaData = $RequestResult | Select-Object -Property:('*') -ExcludeProperty:('Content') if ($Result) { $ResultPopulated = $false # Specific logic for v1 and v2 api specs if ($Url -like '*/api/*' -and ($Url -notlike '*/api/v2/*' -and $Result.PSObject.Properties.name -eq 'results')) { $ResultCount = ($Result.results | Measure-Object).Count if ($ResultCount -gt 0) { $ResultPopulated = $true if ($ReturnCount) { $ResultObjects = $Result $Paginate = $false } else { $ResultObjects = $Result.results } } } elseif ($Url -like '*/api/*' -and ($Url -like '*/api/v2/*' -or $Result.PSObject.Properties.name -ne 'results')) { $ResultCount = ($Result | Measure-Object).Count if ($ResultCount -gt 0) { $ResultPopulated = $true if ($ReturnCount) { $ResultObjects = [PSCustomObject]@{'totalCount' = [int](($httpMetaData.Headers.'X-Total-Count') -join ','); 'results' = $Result; } $Paginate = $false } else { $ResultObjects = $Result } } } else { Write-Error ('Url is not a valid JumpCloud V1 or V2 endpoint') } if ($ResultPopulated -eq $true) { $Skip += $ResultCount $Results += $ResultObjects } } else { if ($Paginate) { $ResultCount = ($Result | Measure-Object).Count } } } Write-Debug ('Paginate:' + [string]$Paginate + ';ResultsCount:' + [string]$ResultCount + ';Limit:' + [string]$Limit + ';') } while ($Paginate -and $ResultCount -eq $Limit) Write-Verbose ('Returned ' + [string]($Results | Measure-Object).Count + ' total results.') } catch { Invoke-Command -ScriptBlock:($ScriptBlock_TryCatchError) -ArgumentList:($_, $true) -NoNewScope } } end { # List values to add to results $HiddenProperties = @('httpMetaData') # Validate that all fields passed into the function exist in the output if ($Results) { # Append meta info to each result record Get-Variable -Name:($HiddenProperties) | ForEach-Object { $Variable = $_ $Results | ForEach-Object { Add-Member -InputObject:($_) -MemberType:('NoteProperty') -Name:($Variable.Name) -Value:($Variable.Value) } } # Validate results properties returned $Fields | ForEach-Object { if ($_ -notin ($Results | ForEach-Object { $_.PSObject.Properties.Name } | Select-Object -Unique)) { Write-Warning ('API output does not contain the field "' + $_ + '". Please refer to https://docs.jumpcloud.com for API endpoint field names.') } } } else { $Results += [PSCustomObject]@{ 'NoContent' = $null; 'httpMetaData' = $httpMetaData; } } # Set the meta info to be hidden by default return Hide-ObjectProperty -Object:($Results) -HiddenProperties:($HiddenProperties) } } |