Private/Get-AtwsData.ps1

<#
    .COPYRIGHT
    Copyright (c) Office Center H�nefoss AS. All rights reserved. Licensed under the MIT license.
    See https://github.com/ecitsolutions/Autotask/blob/master/LICENSE.md for license information.
 
#>


Function Get-AtwsData {
    <#
      .SYNOPSIS
      This function queries the Autotask Web API for entities matching a specified type and filter.
      .DESCRIPTION
      This function queries the Autotask Web API for entities matching a specified type and filter.
      Valid operators:
      -and, -or
 
      Valid comparison operators:
      -eq, -ne, -lt, -le, -gt, -ge, -isnull, -isnotnull, -isthisday
 
      Valid text comparison operators:
      -contains, -like, -notlike, -beginswith, -endswith, -soundslike
          
      Special operators to nest conditions:
      -begin, -end
 
      .INPUTS
      Nothing.
      .OUTPUTS
      Autotask.Entity[]. One or more Autotask entities returned from Autotask Web API.
      .EXAMPLE
      Get-AtwsData -Entity Ticket -Filter {id -gt 0}
      Gets all tickets with an id greater than 0 from Autotask Web API
      .NOTES
      NAME: Get-AtwsData
      .LINK
      Set-AtwsData
      New-AtwsData
      Remove-AtwsData
  #>

  
    [cmdletbinding()]
    [OutputType([PSObject[]])]
    param
    (
        [Parameter(
            Mandatory = $true,
            Position = 0
        )]
        [string]
        $Entity,
          
        [Parameter(
            Mandatory = $true,
            ValueFromRemainingArguments = $true,
            Position = 1
        )]
        [string[]]
        $Filter,
    
        [string]
        $GetReferenceEntityById,
    
        [string]
        $GetExternalEntityByThisEntityId,
    
        [switch]
        $NoPickListLabel
    )

    begin { 
        # Enable modern -Debug behavior
        if ($PSCmdlet.MyInvocation.BoundParameters['Debug'].IsPresent) { $DebugPreference = 'Continue' }
    
        Write-Debug ('{0}: Begin of function' -F $MyInvocation.MyCommand.Name)
       
        if (-not($Script:Atws.integrationsValue)) {
            Throw [ApplicationException] 'Not connected to Autotask WebAPI. Re-import module with valid credentials.'
        }
    
        $result = @()
    }
  
    process {
        # $Filter is usually passed as a flat string. Make sure it is formatted properly
        if ($Filter.Count -eq 1 -and $Filter -match ' ' ) { 
            $Filter = . Update-AtwsFilter -Filterstring $Filter
        }
    
        # Squash into a flat array with entity first
        [Array]$Query = @($Entity) + $Filter
  
        Write-Verbose ('{0}: Converting query string into QueryXml. string as array looks like: {1}' -F $MyInvocation.MyCommand.Name, $($Query -join ', '))
        [xml]$QueryXml = ConvertTo-QueryXML @Query

        Write-Debug ('{0}: QueryXml looks like: {1}' -F $MyInvocation.MyCommand.Name, $QueryXml.InnerXml.Tostring())
    
        Write-Verbose ('{0}: Adding looping construct to query to handle more than 500 results.' -F $MyInvocation.MyCommand.Name)
    
        # Native XML is rather tedious...
        $field = $QueryXml.CreateElement('field')
        $expression = $QueryXml.CreateElement('expression')
        $expression.SetAttribute('op', 'greaterthan')
        $expression.InnerText = 0
        $field.InnerText = 'id'
        [void]$field.AppendChild($expression)
    
        $FirstPass = $true
        Do {
            Write-Verbose ('{0}: Passing QueryXML to Autotask API' -F $MyInvocation.MyCommand.Name)

            # Get the first batch - the API returns max 500 items
            $lastquery = $Script:Atws.query($Script:Atws.IntegrationsValue, $QueryXml.InnerXml)

            # Handle any errors
            if ($lastquery.Errors.Count -gt 0) {
                foreach ($atwsError in $lastquery.Errors) {
                    Write-Error $atwsError.Message
                }
                return
            }

            # Add all returned objects to the Result - if any
            if ($lastquery.EntityResults.Count -gt 0) { 
                $result += ConvertTo-LocalObject -InputObject $lastquery.EntityResults
            }
            
            # Results are sorted by object Id. The Id of the last object is the highest object id in the result
            $upperBound = $lastquery.EntityResults[$lastquery.EntityResults.GetUpperBound(0)].id

            # Add the higest Id (so far) to the id -gt ? condition
            $expression.InnerText = $upperBound

            # If this is the first pass we append the expression to the query
            if ($FirstPass) {
                # Insert looping construct into query
                [void]$QueryXml.queryxml.query.AppendChild($field)
                $FirstPass = $false        
            }
        }
        # The last query we have to make will have between 0 and 499 items
        Until ($lastquery.EntityResults.Count -lt 500)
     
    }
  
    end { 
        # Some last minute changes
        if ($result) { 
            # Should we return an indirect object?
            if ($GetReferenceEntityById) {
                Write-Verbose ('{0}: User has asked for external reference objects by {1}' -F $MyInvocation.MyCommand.Name, $GetReferenceEntityById)
                $fields = Get-AtwsFieldInfo -Entity $result[0].GetType().Name
                $field = $fields.Where( { $_.Name -eq $GetReferenceEntityById })
                $resultValues = $result | Where-Object { $null -ne $_.$GetReferenceEntityById }
                if ($resultValues.Count -lt $result.Count) {
                    Write-Warning ('{0}: Only {1} of the {2}s in the primary query had a value in the property {3}.' -F $MyInvocation.MyCommand.Name, 
                        $resultValues.Count,
                        $Entity,
                        $GetReferenceEntityById) -WarningAction Continue
                }
                $Filter = 'id -eq {0}' -F $($resultValues.$GetReferenceEntityById -join ' -or id -eq ')
                $result = Get-Atwsdata -Entity $field.ReferenceEntityType -Filter $Filter
            }
            elseif ($GetExternalEntityByThisEntityId) {
                Write-Verbose ('{0}: User has asked for {1} that are referencing this result' -F $MyInvocation.MyCommand.Name, $GetExternalEntityByThisEntityId)
                $ReferenceInfo = $GetExternalEntityByThisEntityId -Split ':'
                $Filter = '{0} -eq {1}' -F $ReferenceInfo[1], $($result.id -join (' -or {0}id -eq ' -F $ReferenceInfo[1]))
                $result = Get-Atwsdata -Entity $ReferenceInfo[0] -Filter $Filter
            }

            Write-Debug ('{0}: End of function' -F $MyInvocation.MyCommand.Name)
            Return $result
        }
    }
  
}