Celerium.AutoTask.psm1

#Region '.\Private\ApiCalls\Invoke-AutoTaskRequest.ps1' -1

function Invoke-AutoTaskRequest {
<#
    .SYNOPSIS
        Makes an API request to AutoTask
 
    .DESCRIPTION
        The Invoke-AutoTaskRequest cmdlet invokes an API request to the AutoTask API
 
        This is an internal function that is used by all public functions
 
    .PARAMETER Method
        Defines the type of API method to use
 
        Allowed values:
        'GET', 'PUT', 'POST', 'PATCH', 'DELETE'
 
    .PARAMETER ResourceURI
        Defines the resource uri (url) to use when creating the API call
 
    .PARAMETER Data
        Object containing supported AutoTask method schemas
 
    .PARAMETER AllResults
        Returns all items from an endpoint
 
    .EXAMPLE
        Invoke-AutoTaskRequest -Method GET -ResourceURI '/passwords' -UriFilter $UriFilter
 
        Invoke a rest method against the defined resource using the provided parameters
 
        Example HashTable:
            $UriParameters = @{
                'filter[id]'] = 123456789
                'filter[organization_id]'] = 12345
            }
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Invoke-AutoTaskRequest.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Invoke', SupportsShouldProcess)]
    param (
        [Parameter()]
        [ValidateSet('GET', 'PUT', 'POST', 'PATCH', 'DELETE')]
        [string]$Method = 'GET',

        [Parameter(Mandatory = $true)]
        [string]$ResourceURI,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        $Data,

        [Parameter()]
        [switch]$AllResults
    )

    begin {

        # Load Web assembly when needed as PowerShell Core has the assembly preloaded
        if ( !("System.Web.HttpUtility" -as [Type]) ) { Add-Type -Assembly System.Web }

        $FunctionName   = $MyInvocation.InvocationName
        $ParameterName  = $FunctionName + '_Parameters' -replace '-','_'

        $ApiSecret = Get-AutoTaskAPIKey -AsPlainText -WarningAction SilentlyContinue -WarningVariable 'Get_AutoTaskAPIKey_Warning'
        if ( $Get_AutoTaskAPIKey_Warning -or !$(Get-AutoTaskBaseURI -WarningAction SilentlyContinue)) {
            throw "No authentication method or base uri found, please run Add-AutoTaskAPIKey & Add-AutoTaskBaseURI to continue"
        }

        $Headers = @{
            'ApiIntegrationCode'    = $ApiSecret.ApiIntegrationCode
            'UserName'              = $ApiSecret.Username
            'Secret'                = $ApiSecret.Password
            'Content-Type'          = "application/json; charset=utf-8"
        }

    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        $AllResponseData = [System.Collections.Generic.List[object]]::new()

        $Page       = 1
        $RetryCount = 0
        $RetryMax   = 3

        Set-Variable -Name TEST_BASEURI -Value $AutoTaskModuleBaseUri -Scope Global -Force -Confirm:$false
        Set-Variable -Name TEST_RESOURCEURI -Value $ResourceURI -Scope Global -Force -Confirm:$false

        #POST ResourceURI have double // in the path
        $ResourceURI    = $ResourceURI -replace '(?<!:)/{2,}', '/'
        $TargetUri      = $AutoTaskModuleBaseUri + $ResourceURI

        $InvokeParams = @{
            Method      = $Method
            Headers     = $Headers
            URI         = $TargetUri
            UserAgent   = $AutoTaskModuleUserAgent
        }

        if ($Method -ne 'GET') {
            if ($Data -is [string]) { $SendingBody = $Data }
            else { $SendingBody = $Data | ConvertTo-Json -Depth $AutoTaskModuleJSONConversionDepth }

            $InvokeParams.Body  = $SendingBody
        }

        Set-Variable -Name $ParameterName -Value $InvokeParams -Scope Global -Force -Confirm:$false

        try{
            do {
                try{
                    $ApiResponse = Invoke-RestMethod @InvokeParams

                    if ($AllResults) {
                        $InvokeParams['Uri'] = $ApiResponse.pageDetails.nextPageUrl
                    }

                    # Returns blank unless $Items itself is returned for InvoicePDF function
                    if ($ResourceTarget -eq "InvoicePDF") {
                        Write-Verbose "Processing [ $(($ApiResponse | Measure-Object).Count) ] items from page [ $Page ]"
                        $AllResponseData.Add($ApiResponse)
                    }

                    if ($ApiResponse.fields) {
                        $AllResponseData.Add($ApiResponse)
                    }

                    if ($ApiResponse.items)   {
                        Write-Verbose "Processing [ $($ApiResponse.pageDetails.count) ] items from page [ $Page ]"
                        $AllResponseData.AddRange(@($ApiResponse.items))
                    }

                    if ($ApiResponse.item)    {
                        Write-Verbose "Processing [ $(($ApiResponse.item | Measure-Object).Count) ] items from page [ $Page ]"
                        $AllResponseData.AddRange(@($ApiResponse.item))
                    }

                    $Page++
                }
                catch {
                    $ExceptionError = $_.Exception.Message
                    Write-Warning 'The [ Invoke_AutoTaskRequest_Parameters, Invoke_AutoTaskRequest_ParametersQuery, & CmdletName_Parameters ] variables can provide extra details'

                    $RandomWaitTime = [Math]::Min( [Math]::Pow(2,$RetryCount) + (Get-Random -Minimum 0 -Maximum 30),120)

                    switch -Wildcard ($ExceptionError) {
                        '*400*' {   throw }
                        '*404*' {   throw "Invoke-AutoTaskRequest : URI not found - [ $TargetUri ]"}
                        '*429*' {
                                    $RetryAfter = $_.Exception.Response.Headers['Retry-After']
                                    if ($RetryAfter) { $RandomWaitTime = [int]$RetryAfter }

                                    Write-Error "Invoke-AutoTaskRequest : API rate limited - Sleeping for [ $RandomWaitTime ] seconds"

                                    if ($RetryAfter) { Start-Sleep -Seconds [int]$RetryAfter }
                                    else { Start-Sleep -Seconds $RandomWaitTime }
                                }
                        '*504*' {   Write-Error "Invoke-AutoTaskRequest : Gateway Timeout - Sleeping for [ $RandomWaitTime ] seconds"
                                    Start-Sleep -Seconds $RandomWaitTime
                                }
                        default { Write-Error $_ }
                    }

                    $RetryCount++
                    if ($RetryCount -lt $RetryMax) {
                        Write-Warning "Invoke-AutoTaskRequest : Retrying request [ $ResourceURI ] - Attempt [ $RetryCount/$RetryMax ]"
                    }
                    else{
                        throw "Invoke-AutoTaskRequest : Maximum retry attempts reached [ $RetryCount/$RetryMax ]"
                    }

                }
            }
            while ($AllResults -and $InvokeParams.Uri)
        }
        catch {
            Write-Error $_
            throw
        }
        finally {
            if ($Invoke_AutoTaskRequest_Parameters) {
                $Auth = $Invoke_AutoTaskRequest_Parameters['headers']['Secret']
                if ($Auth) {
                    $Invoke_AutoTaskRequest_Parameters['headers']['Secret'] = $Auth.Substring(0,[Math]::Min($Auth.Length,9)) + '*******'
                }
            }
        }

        return $AllResponseData

    }

    end {}

}
#EndRegion '.\Private\ApiCalls\Invoke-AutoTaskRequest.ps1' 203
#Region '.\Private\ApiCalls\New-AutoTaskResourceDynamicParameter.ps1' -1

function New-AutoTaskResourceDynamicParameter {
<#
    .SYNOPSIS
        Creates a new AutoTask resource dynamic parameter
 
    .DESCRIPTION
        The New-AutoTaskResourceDynamicParameter cmdlet creates a new dynamic parameter
        for either the resource list or definitions list inside of swagger json
        by opening the file, reading the contents and converting a custom object
 
    .PARAMETER ParameterType
        Defines the type of resource or definition to use when creating the dynamic parameter
 
    .PARAMETER JsonSpec
        Defines the path to the swagger json file to use when creating the dynamic parameter
 
        By default the value used is the one defined in the root of the module folder
 
    .EXAMPLE
        New-AutoTaskResourceDynamicParameter
 
        You will be prompted to select a parameter type and resource
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/ApiCalls/New-AutoTaskResourceDynamicParameter.html
 
    .LINK
        https://webservices24.autotask.net/atservicesrest/swagger/ui/index#
#>


    [CmdletBinding(DefaultParameterSetName = 'GenerateResource')]
    Param (
        [Parameter(Mandatory = $true)]
        [string]$ParameterType,

        [Parameter(Mandatory = $false)]
        [string]$JsonSpec
    )

    begin {}

    process {

        $ParameterName                  = "Resource"
        $RuntimeParameterDictionary     = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        $AttributeCollection            = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $ParameterAttribute             = New-Object System.Management.Automation.ParameterAttribute
        $ParameterAttribute.Mandatory   = $true
        $AttributeCollection.Add($ParameterAttribute)

        Set-Variable -Name "AutoTaskModuleSwagger" -Value $(Get-Content $JsonSpec -Raw | ConvertFrom-Json) -Option ReadOnly -Scope Global -Force

        $Queries = foreach ($Path in $AutoTaskModuleSwagger.Paths.PSObject.Properties) {
            [PSCustomObject]@{
                Index  = $($path.name.split("/")[2])
                Name   = $($path.Name)
                Get    = $($Path.value.get.tags)
                Post   = $($Path.value.post.tags)
                Patch  = $($Path.value.patch.tags)
                Delete = $($Path.value.delete.tags)

            }
        }
        Set-Variable -Name "AutoTaskModuleQueries" -Value $Queries -Option ReadOnly -Scope Global -Force

        $ResourceList = $null
        foreach ( $Type in $ParameterType.Split( ' ' ) ) {
            $ResourceList += foreach ($Query in $Queries | Where-Object { $null -ne $_."$Type" }  ) {
                $Resource = $Query."$Type" | Select-Object -Last 1
                $Resource
            }
        }
        $ResourceList = $ResourceList | Sort-Object -Unique

        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($ResourceList)
        $AttributeCollection.Add($ValidateSetAttribute)

        $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
        $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)

        return $RuntimeParameterDictionary

    }

    end{}
}
#EndRegion '.\Private\ApiCalls\New-AutoTaskResourceDynamicParameter.ps1' 90
#Region '.\Private\ApiCalls\Set-AutoTaskResourceDynamicParameter.ps1' -1

function Set-AutoTaskResourceDynamicParameter {
<#
    .SYNOPSIS
        Helper function for the New-AutoTaskResourceDynamicParameter
 
    .DESCRIPTION
        The Set-AutoTaskResourceDynamicParameter cmdlet is a simple helper
        function for the New-AutoTaskResourceDynamicParameter cmdlet that creates
        a new dynamic parameter for either the resource list or definitions
        list inside of swagger json
 
    .PARAMETER JsonSpec
        Defines the path to the swagger json file to use when creating the dynamic parameter
 
        By default the value used is the one defined in the root of the module folder
 
    .EXAMPLE
        Set-AutoTaskResourceDynamicParameter
 
        Generates the dynamic parameter for either the resource list or definitions list
        inside of swagger json
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/ApiCalls/Set-AutoTaskResourceDynamicParameter.html
 
    .LINK
        https://webservices24.autotask.net/atservicesrest/swagger/ui/index#
#>


    [CmdletBinding(DefaultParameterSetName = 'GenerateResource')]
    Param (
        [Parameter(Mandatory = $false)]
        [string]$JsonSpec = $(Join-Path -Path "$($MyInvocation.MyCommand.Module.ModuleBase)" -ChildPath "AutoTaskAPI-v1-2023.6.json")
    )

    begin {}

    process {

        Write-Verbose "Configuring API resource methods"

        Set-Variable -Name "AutoTaskModuleGetParameter"         -Value (New-AutoTaskResourceDynamicParameter -ParameterType "Get" -JsonSpec $JsonSpec)          -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModulePatchParameter"       -Value (New-AutoTaskResourceDynamicParameter -ParameterType "Patch" -JsonSpec $JsonSpec)        -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModuleDeleteParameter"      -Value (New-AutoTaskResourceDynamicParameter -ParameterType "Delete" -JsonSpec $JsonSpec)       -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModulePostParameter"        -Value (New-AutoTaskResourceDynamicParameter -ParameterType "Post" -JsonSpec $JsonSpec)         -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModulePostPatchParameter"   -Value (New-AutoTaskResourceDynamicParameter -ParameterType "Post Patch" -JsonSpec $JsonSpec)   -Option ReadOnly -Scope Global -Force


    }

    end{}
}
#EndRegion '.\Private\ApiCalls\Set-AutoTaskResourceDynamicParameter.ps1' 56
#Region '.\Private\ApiKeys\Add-AutoTaskAPIKey.ps1' -1

function Add-AutoTaskAPIKey {
<#
    .SYNOPSIS
        Sets your API key used to authenticate all API calls
 
    .DESCRIPTION
        The Add-AutoTaskAPIKey cmdlet sets your API key which is used to
        authenticate all API calls made to AutoTask
 
        AutoTask API keys can be generated via the AutoTask web interface
            Resources > API User > Credentials
 
    .PARAMETER ApiUsername
        Plain text API username
 
    .PARAMETER ApiSecretKey
        Plain text API secret key
 
        If not defined the cmdlet will prompt you to enter the API secret key which
        will be stored as a SecureString
 
    .PARAMETER ApiKeySecureString
        Input a SecureString object containing the API key
 
    .PARAMETER ApiIntegrationCode
        Plain text API integration code
 
    .EXAMPLE
        Add-AutoTaskAPIKey -ApiUsername 'Celerium@Celerium.org' -ApiIntegrationCode '12345'
 
        Prompts to enter in the API secret key which will be stored as a SecureString
 
    .EXAMPLE
        Add-AutoTaskAPIKey -ApiUsername 'Celerium@Celerium.org' -ApiIntegrationCode '12345' -ApiSecretKey '12345'
 
        Converts the string to a SecureString and stores it in the global variable
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Add-AutoTaskAPIKey.html
#>


    [CmdletBinding(DefaultParameterSetName = 'AsPlainText')]
    [Alias('Set-AutoTaskAPIKey')]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ApiUsername,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, ParameterSetName = 'AsPlainText')]
        [AllowEmptyString()]
        [string]$ApiSecretKey,

        [Parameter(Mandatory = $false, ValueFromPipeline = $true, ParameterSetName = 'AsSecureString')]
        [validateNotNullOrEmpty()]
        [securestring]$ApiKeySecureString,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ApiIntegrationCode
    )

    begin {}

    process{

        Set-Variable -Name "AutoTaskModuleApiUsername"          -Value $ApiUsername -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModuleApiIntegrationCode"   -Value $ApiIntegrationCode -Option ReadOnly -Scope Global -Force

        switch ($PSCmdlet.ParameterSetName) {
            'AsPlainText'       {

                if ($ApiSecretKey) {
                    $SecureString = ConvertTo-SecureString $ApiSecretKey -AsPlainText -Force
                }
                else {
                    Write-Output "Please enter your API key:"
                    $SecureString = Read-Host -AsSecureString
                }

                Set-Variable -Name "AutoTaskModuleApiSecretKey" -Value $SecureString -Option ReadOnly -Scope Global -Force

            }
            'AsSecureString'    {

                Set-Variable -Name "AutoTaskModuleApiSecretKey" -Value $ApiKeySecureString -Option ReadOnly -Scope Global -Force

            }
        }

    }

    end {}

}
#EndRegion '.\Private\ApiKeys\Add-AutoTaskAPIKey.ps1' 98
#Region '.\Private\ApiKeys\Get-AutoTaskAPIKey.ps1' -1

function Get-AutoTaskAPIKey {
<#
    .SYNOPSIS
        Gets the AutoTask API key
 
    .DESCRIPTION
        The Get-AutoTaskAPIKey cmdlet gets the AutoTask API key from
        the global variable and returns it as an object
 
    .PARAMETER AsPlainText
        Decrypt and return the API key in plain text
 
    .EXAMPLE
        Get-AutoTaskAPIKey
 
        Gets the Api keys and returns them as an object. The
        API secret key is returned as a secure string
 
    .EXAMPLE
        Get-AutoTaskAPIKey -AsPlainText
 
        Gets the Api keys and returns them as an object. The
        API secret key is returned as plain text
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Get-AutoTaskAPIKey.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Index')]
    Param (
        [Parameter(Mandatory = $false)]
        [switch]$AsPlainText
    )

    begin {}

    process {

        try {

            if ($AutoTaskModuleApiSecretKey) {

                if ($AsPlainText) {
                    $ApiSecretKey = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($AutoTaskModuleApiSecretKey)

                    [PSCustomObject]@{
                        Username            = $AutoTaskModuleApiUsername
                        Password            = ( [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ApiSecretKey) ).ToString()
                        ApiIntegrationCode  = $AutoTaskModuleApiIntegrationCode
                    }
                }
                else {
                    [PSCustomObject]@{
                        Username            = $AutoTaskModuleApiUsername
                        Password            = $AutoTaskModuleApiSecretKey
                        ApiIntegrationCode  = $AutoTaskModuleApiIntegrationCode
                    }
                }

            }
            else { Write-Warning "The AutoTask API secret key is not set. Run Add-AutoTaskAPIKey to set the API key" }

        }
        catch {
            Write-Error $_
        }
        finally {
            if ($ApiSecretKey) {
                [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ApiSecretKey)
            }
        }


    }

    end {}

}
#EndRegion '.\Private\ApiKeys\Get-AutoTaskAPIKey.ps1' 82
#Region '.\Private\ApiKeys\Remove-AutoTaskAPIKey.ps1' -1

function Remove-AutoTaskAPIKey {
<#
    .SYNOPSIS
        Removes the Api keys from the global variables
 
    .DESCRIPTION
        The Remove-AutoTaskAPIKey cmdlet removes the Api keys
        from the global variables
 
    .EXAMPLE
        Remove-AutoTaskAPIKey
 
        Removes the Api keys from the global variables
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Remove-AutoTaskAPIKey.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Destroy', SupportsShouldProcess, ConfirmImpact = 'None')]
    Param ()

    begin {}

    process {

        switch ([bool]$AutoTaskModuleApiUsername) {
            $true   { Remove-Variable -Name "AutoTaskModuleApiUsername" -Scope Global -Force }
            $false  { Write-Warning "The AutoTask API key is not set. Nothing to remove" }
        }

        switch ([bool]$AutoTaskModuleApiSecretKey) {
            $true   { Remove-Variable -Name "AutoTaskModuleApiSecretKey" -Scope Global -Force }
            $false  { Write-Warning "The AutoTask API secret key is not set. Nothing to remove" }
        }

        switch ([bool]$AutoTaskModuleApiIntegrationCode) {
            $true   { Remove-Variable -Name "AutoTaskModuleApiIntegrationCode" -Scope Global -Force }
            $false  { Write-Warning "The AutoTask API integration code is not set. Nothing to remove" }
        }

    }

    end {}

}
#EndRegion '.\Private\ApiKeys\Remove-AutoTaskAPIKey.ps1' 49
#Region '.\Private\ApiKeys\Test-AutoTaskAPIKey.ps1' -1

function Test-AutoTaskAPIKey {
<#
    .SYNOPSIS
        Test the AutoTask API key
 
    .DESCRIPTION
        The Test-AutoTaskAPIKey cmdlet tests the base URI & API key that
        are defined in the Get-AutoTaskBaseURI & Get-AutoTaskAPIKey cmdlets
 
        Helpful when needing to validate general functionality or when using
        RMM deployment tools
 
    .PARAMETER BaseUri
        Define the base URI for the AutoTask API connection
        using AutoTask's URI or a custom URI
 
        By default the value used is the one defined by the
        Get-AutoTaskBaseURI function
 
    .EXAMPLE
        Test-AutoTaskAPIKey
 
        Tests the base URI & API key that are defined in the
        Get-AutoTaskBaseURI & Get-AutoTaskAPIKey cmdlets
 
    .EXAMPLE
        Test-AutoTaskAPIKey -BaseUri http://myapi.gateway.celerium.org
 
        Tests the defined base URI & API key that was defined in
        the Get-AutoTaskAPIKey cmdlet
 
        The full base uri test path in this example is:
            http://myapi.gateway.celerium.org/Companies/query
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Test-AutoTaskAPIKey.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Test')]
    Param (
        [parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$BaseUri = $AutoTaskModuleBaseUriComplete
    )

    begin { $ResourceUri = "/Companies/query?Search" }

    process {

        if ([bool]$BaseUri -eq $false -or [bool](Get-AutoTaskAPIKey -ErrorAction Stop) -eq $false) {
            Write-Error "The BaseUri and or ApiKeys are not set. Please run the Get-AutoTaskApiKey & Get-AutoTaskBaseURI cmdlets before running this function"
            return
        }

        Write-Verbose "Testing API key against [ $($BaseUri + $ResourceUri) ]"

        try {

            $ApiSecret  = Get-AutoTaskAPIKey -AsPlainText
            $Headers    = @{
                'ApiIntegrationCode'    = $ApiSecret.ApiIntegrationCode
                'UserName'              = $ApiSecret.Username
                'Secret'                = $ApiSecret.Password
                'Content-Type'          = "application/json"
            }

            $Body = @{
                MaxRecords = 1
                filter = @(
                    @{
                        op    = "gte"
                        field = "id"
                        value = 0
                    }
                )
            } | ConvertTo-Json -Depth 5

            $Parameters = @{
                'Method'        = 'POST'
                'Uri'           = $BaseUri + $ResourceUri
                'Headers'       = $Headers
                'Body'          = $Body
                'UserAgent'     = $AutoTaskModuleUserAgent
                UseBasicParsing = $true
            }

            $RestOutput = Invoke-WebRequest @Parameters -ErrorAction Stop

        }
        catch {

            [PSCustomObject]@{
                Method              = $_.Exception.Response.Method
                StatusCode          = $_.Exception.Response.StatusCode.value__
                StatusDescription   = $_.Exception.Response.StatusDescription
                Message             = $_.Exception.Message
                URI                 = $($BaseUri + $ResourceUri)
            }

        } finally {
            [void] ($Headers)
        }

        if ($RestOutput) {
            $Data = @{}
            $Data = $RestOutput

            [PSCustomObject]@{
                StatusCode          = $Data.StatusCode
                StatusDescription   = $Data.StatusDescription
                URI                 = $($BaseUri + $ResourceUri)
            }
        }

    }

    end {}

}
#EndRegion '.\Private\ApiKeys\Test-AutoTaskAPIKey.ps1' 123
#Region '.\Private\BaseUri\Add-AutoTaskBaseURI.ps1' -1

function Add-AutoTaskBaseURI {
<#
    .SYNOPSIS
        Sets the base URI for the AutoTask API connection
 
    .DESCRIPTION
        The Add-AutoTaskBaseURI cmdlet sets the base URI which is used
        to construct the full URI for all API calls
 
    .PARAMETER AutoDetect
        Attempts to automatically detect the base URI for the AutoTask API connection
 
    .PARAMETER BaseUri
        Sets the base URI for the AutoTask API connection. Helpful
        if using a custom API gateway or an undocumented AutoTask API endpoint
 
    .PARAMETER DataCenter
        Defines the data center (platform) to use which in turn defines which
        base API URL is used
 
        https://ww24.autotask.net/DeveloperHelp/Content/APIs/General/API_Zones.htm
 
        Allowed values are:
        America East https://webservices3.autotask.net/atservicesrest
        America East 2 https://webservices14.autotask.net/atservicesrest
        America East 3 https://webservices22.autotask.net/atservicesrest
        America West https://webservices5.autotask.net/atservicesrest
        America West 2 https://webservices15.autotask.net/atservicesrest
        America West 3 https://webservices24.autotask.net/atservicesrest
        America West 4 https://webservices25.autotask.net/atservicesrest
        Australia / New Zealand https://webservices6.autotask.net/atservicesrest
        Australia 2 https://webservices26.autotask.net/atservicesrest
        Australia 3 https://webservices29.autotask.net/atservicesrest
        Deutsch German https://webservices18.autotask.net/atservicesrest
        Deutsch Pre-Release https://prde.autotask.net/atservicesrest
        Español Pre-Release https://pres.autotask.net/atservicesrest
        Español Spanish https://webservices12.autotask.net/atservicesrest
        EU1 (English Europe and Asia) https://webservices19.autotask.net/atservicesrest
        Limited Release https://webservices1.autotask.net/atservicesrest
        Pre-release https://webservices2.autotask.net/atservicesrest
        UK https://webservices4.autotask.net/atservicesrest
        UK Limited Release https://webservices17.autotask.net/atservicesrest
        UK Pre-release https://webservices11.autotask.net/atservicesrest
        UK2 https://webservices16.autotask.net/atservicesrest
        UK3 https://webservices28.autotask.net/atservicesrest
 
    .EXAMPLE
        Add-AutoTaskBaseURI
 
        Attempts to automatically detect the base URI for the AutoTask API connection
 
    .EXAMPLE
        Add-AutoTaskBaseURI -BaseUri 'https://gateway.celerium.org'
 
        The base URI will use https://gateway.celerium.org
 
    .EXAMPLE
        Add-AutoTaskBaseURI -DataCenter 'America West 3'
 
        The base URI will use https://webservices24.autotask.net/atservicesrest/v1.0
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Add-AutoTaskBaseURI.html
#>


    [CmdletBinding(DefaultParameterSetName = 'AutoDetect')]
    [Alias('Set-AutoTaskBaseURI')]
    Param (
        [Parameter(Mandatory = $false, ParameterSetName = 'AutoDetect')]
        [switch]$AutoDetect,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$Version = $((Invoke-RestMethod -Uri "https://webservices2.autotask.net/atservicesrest/VersionInformation").apiVersions | Select-Object -Last 1),

        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'CustomUri')]
        [ValidateNotNullOrEmpty()]
        [string]$BaseUri,

        [Parameter(Mandatory = $false, ParameterSetName = 'Datacenter')]
        [ValidateSet(
            'America East',
            'America East 2',
            'America East 3',
            'America West',
            'America West 2',
            'America West 3',
            'America West 4',
            'Australia / New Zealand',
            'Australia 2',
            'Australia 3',
            'Deutsch German',
            'Deutsch Pre-Release',
            'Español Pre-Release',
            'Español Spanish',
            'EU1 (English Europe and Asia)',
            'Limited Release',
            'Pre-release',
            'UK',
            'UK Limited Release',
            'UK Pre-release',
            'UK2',
            'UK3'
        )]
        [Alias('Platform')]
        [string]$DataCenter
    )

    begin {}

    process{

        if ($AutoDetect) {

            try {
                $ValidationUri  = 'https://webservices2.autotask.net/atservicesrest'
                $BaseUri        = (Invoke-RestMethod -Uri "$ValidationUri/$Version/ZoneInformation?user=$AutoTaskModuleApiUsername").url

            }
            catch {
                $ErrorMessage = $_ | Out-String
                Write-Error "Could not retrieve AutoTask BaseURI. $($ErrorMessage.Trim())"
                throw
            }

        }

        if ($DataCenter) {

            switch ($DataCenter) {
                'America East'                  {$BaseUri = 'https://webservices3.autotask.net/atservicesrest'}
                'America East 2'                {$BaseUri = 'https://webservices14.autotask.net/atservicesrest'}
                'America East 3'                {$BaseUri = 'https://webservices22.autotask.net/atservicesrest'}
                'America West'                  {$BaseUri = 'https://webservices5.autotask.net/atservicesrest'}
                'America West 2'                {$BaseUri = 'https://webservices15.autotask.net/atservicesrest'}
                'America West 3'                {$BaseUri = 'https://webservices24.autotask.net/atservicesrest'}
                'America West 4'                {$BaseUri = 'https://webservices25.autotask.net/atservicesrest'}
                'Australia / New Zealand'       {$BaseUri = 'https://webservices6.autotask.net/atservicesrest'}
                'Australia 2'                   {$BaseUri = 'https://webservices26.autotask.net/atservicesrest'}
                'Australia 3'                   {$BaseUri = 'https://webservices29.autotask.net/atservicesrest'}
                'Deutsch German'                {$BaseUri = 'https://webservices18.autotask.net/atservicesrest'}
                'Deutsch Pre-Release'           {$BaseUri = 'https://prde.autotask.net/atservicesrest'}
                'Español Pre-Release'           {$BaseUri = 'https://pres.autotask.net/atservicesrest'}
                'Español Spanish'               {$BaseUri = 'https://webservices12.autotask.net/atservicesrest'}
                'EU1 (English Europe and Asia)' {$BaseUri = 'https://webservices19.autotask.net/atservicesrest'}
                'Limited Release'               {$BaseUri = 'https://webservices1.autotask.net/atservicesrest'}
                'Pre-release'                   {$BaseUri = 'https://webservices2.autotask.net/atservicesrest'}
                'UK'                            {$BaseUri = 'https://webservices4.autotask.net/atservicesrest'}
                'UK Limited Release'            {$BaseUri = 'https://webservices17.autotask.net/atservicesrest'}
                'UK Pre-release'                {$BaseUri = 'https://webservices11.autotask.net/atservicesrest'}
                'UK2'                           {$BaseUri = 'https://webservices16.autotask.net/atservicesrest'}
                'UK3'                           {$BaseUri = 'https://webservices28.autotask.net/atservicesrest'}
            }

        }

        if($BaseUri[$BaseUri.Length-1] -eq "/") {
            $BaseUri = $BaseUri.Substring(0,$BaseUri.Length-1)
        }

        Write-Verbose "Using URI: [ $($BaseURI + "/$Version") ]"

        Set-Variable -Name "AutoTaskModuleBaseUri"              -Value $BaseURI -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModuleBaseUriApiVersion"    -Value $Version -Option ReadOnly -Scope Global -Force
        Set-Variable -Name "AutoTaskModuleBaseUriComplete"      -Value ($BaseURI + "/$Version") -Option ReadOnly -Scope Global -Force

    }

    end {}

}
#EndRegion '.\Private\BaseUri\Add-AutoTaskBaseURI.ps1' 175
#Region '.\Private\BaseUri\Get-AutoTaskBaseURI.ps1' -1

function Get-AutoTaskBaseURI {
<#
    .SYNOPSIS
        Shows the AutoTask base URI
 
    .DESCRIPTION
        The Get-AutoTaskBaseURI cmdlet shows the AutoTask base URI from
        the global variable
 
    .PARAMETER AndApiUri
        Also include the default Api version uri
 
    .EXAMPLE
        Get-AutoTaskBaseURI
 
        Shows the AutoTask base URI value defined in the global variable
 
    .EXAMPLE
        Get-AutoTaskBaseURI -AndApiUri
 
        Shows the AutoTask base URI value with the default Api version uri defined in the global variable
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Get-AutoTaskBaseURI.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Index')]
    Param (
        [Parameter(Mandatory = $false)]
        [switch]$AndApiUri
    )

    begin {}

    process {

        switch ([bool]$AutoTaskModuleBaseUri) {
            $true   {
                if ($AndApiUri) { $AutoTaskModuleBaseUri + "/" + $AutoTaskModuleBaseUriApiVersion }
                else { $AutoTaskModuleBaseUri }
            }
            $false  { Write-Warning "The AutoTask base URI is not set. Run Add-AutoTaskBaseURI to set the base URI." }
        }

    }

    end {}

}
#EndRegion '.\Private\BaseUri\Get-AutoTaskBaseURI.ps1' 53
#Region '.\Private\BaseUri\Remove-AutoTaskBaseURI.ps1' -1

function Remove-AutoTaskBaseURI {
<#
    .SYNOPSIS
        Removes the AutoTask base URI global variable
 
    .DESCRIPTION
        The Remove-AutoTaskBaseURI cmdlet removes the AutoTask base URI from
        the global variable
 
    .EXAMPLE
        Remove-AutoTaskBaseURI
 
        Removes the AutoTask base URI value from the global variable
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Remove-AutoTaskBaseURI.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Destroy', SupportsShouldProcess, ConfirmImpact = 'None')]
    Param ()

    begin {}

    process {

        switch ([bool]$AutoTaskModuleBaseUri) {

            $true   {
                if ($PSCmdlet.ShouldProcess('AutoTaskModuleBaseUri')) {
                    Remove-Variable -Name "AutoTaskModuleBaseUri" -Scope Global -Force
                    Remove-Variable -Name "AutoTaskModuleBaseUriApiVersion" -Scope Global -Force
                    Remove-Variable -Name "AutoTaskModuleBaseUriComplete" -Scope Global -Force
                }
            }
            $false  { Write-Warning "The AutoTask base URI variable is not set. Nothing to remove" }

        }

    }

    end {}

}
#EndRegion '.\Private\BaseUri\Remove-AutoTaskBaseURI.ps1' 47
#Region '.\Private\ModuleSettings\Export-AutoTaskModuleSettings.ps1' -1

function Export-AutoTaskModuleSettings {
<#
    .SYNOPSIS
        Exports the AutoTask BaseURI, API, & JSON configuration information to file
 
    .DESCRIPTION
        The Export-AutoTaskModuleSettings cmdlet exports the AutoTask BaseURI, API, & JSON configuration information to file
 
        Making use of PowerShell's System.Security.SecureString type, exporting module settings encrypts your API key in a format
        that can only be unencrypted with the your Windows account as this encryption is tied to your user principal
        This means that you cannot copy your configuration file to another computer or user account and expect it to work
 
    .PARAMETER AutoTaskConfigPath
        Define the location to store the AutoTask configuration file
 
        By default the configuration file is stored in the following location:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigFile
        Define the name of the AutoTask configuration file
 
        By default the configuration file is named:
            config.psd1
 
    .EXAMPLE
        Export-AutoTaskModuleSettings
 
        Validates that the BaseURI, API, and JSON depth are set then exports their values
        to the current user's AutoTask configuration file located at:
            $env:USERPROFILE\Celerium.AutoTask\config.psd1
 
    .EXAMPLE
        Export-AutoTaskModuleSettings -AutoTaskConfigPath C:\Celerium.AutoTask -AutoTaskConfigFile MyConfig.psd1
 
        Validates that the BaseURI, API, and JSON depth are set then exports their values
        to the current user's AutoTask configuration file located at:
            C:\Celerium.AutoTask\MyConfig.psd1
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Export-AutoTaskModuleSettings.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Set')]
    Param (
        [Parameter()]
        [string]$AutoTaskConfigPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop') {"Celerium.AutoTask"}else{".Celerium.AutoTask"}) ),

        [Parameter()]
        [string]$AutoTaskConfigFile = 'config.psd1'
    )

    begin {}

    process {

        Write-Warning "Secrets are stored using Windows Data Protection API (DPAPI)"
        Write-Warning "DPAPI provides user context encryption in Windows but NOT in other operating systems like Linux or UNIX. It is recommended to use a more secure & cross-platform storage method"

        $AutoTaskConfig = Join-Path -Path $AutoTaskConfigPath -ChildPath $AutoTaskConfigFile

        $GlobalModuleVariables = @('AutoTaskModuleBaseUri', 'AutoTaskModuleBaseUriApiVersion', 'AutoTaskModuleApiUsername', 'AutoTaskModuleApiSecretKey', 'AutoTaskModuleUserAgent', 'AutoTaskModuleJSONConversionDepth')
        foreach ($GlobalVariable in  $GlobalModuleVariables) {
            if (-not (Get-Variable -Name $GlobalVariable -ErrorAction SilentlyContinue -ErrorVariable GlobalVariableCheck)){
                Write-Error "The required module variable [ $GlobalVariable ] is not set"
            }
        }

        # Confirm variables exist and are not null before exporting
        if (-not $GlobalVariableCheck) {
            $SecureString = $AutoTaskModuleApiSecretKey | ConvertFrom-SecureString

            if ($IsWindows -or $PSEdition -eq 'Desktop') {
                New-Item -Path $AutoTaskConfigPath -ItemType Directory -Force | ForEach-Object { $_.Attributes = $_.Attributes -bor "Hidden" }
            }
            else{
                New-Item -Path $AutoTaskConfigPath -ItemType Directory -Force
            }
@"
    @{
        AutoTaskModuleBaseUri = '$AutoTaskModuleBaseUri'
        AutoTaskModuleBaseUriApiVersion = '$AutoTaskModuleBaseUriApiVersion'
        AutoTaskModuleBaseUriComplete = '$AutoTaskModuleBaseUriComplete'
        AutoTaskModuleApiUsername = '$AutoTaskModuleApiUsername'
        AutoTaskModuleApiSecretKey = '$SecureString'
        AutoTaskModuleApiIntegrationCode = '$AutoTaskModuleApiIntegrationCode'
        AutoTaskModuleUserAgent = '$AutoTaskModuleUserAgent'
        AutoTaskModuleJSONConversionDepth = '$AutoTaskModuleJSONConversionDepth'
    }
"@
 | Out-File -FilePath $AutoTaskConfig -Force
        }
        else {
            Write-Error "Failed to export AutoTask Module settings to [ $AutoTaskConfig ]"
            Write-Error $_
            exit 1
        }

    }

    end {}

}
#EndRegion '.\Private\ModuleSettings\Export-AutoTaskModuleSettings.ps1' 105
#Region '.\Private\ModuleSettings\Get-AutoTaskModuleSettings.ps1' -1

function Get-AutoTaskModuleSettings {
<#
    .SYNOPSIS
        Gets the saved AutoTask configuration settings
 
    .DESCRIPTION
        The Get-AutoTaskModuleSettings cmdlet gets the saved AutoTask configuration settings
        from the local system
 
        By default the configuration file is stored in the following location:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigPath
        Define the location to store the AutoTask configuration file
 
        By default the configuration file is stored in the following location:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigFile
        Define the name of the AutoTask configuration file
 
        By default the configuration file is named:
            config.psd1
 
    .PARAMETER OpenConfigFile
        Opens the AutoTask configuration file
 
    .EXAMPLE
        Get-AutoTaskModuleSettings
 
        Gets the contents of the configuration file that was created with the
        Export-AutoTaskModuleSettings
 
        The default location of the AutoTask configuration file is:
            $env:USERPROFILE\Celerium.AutoTask\config.psd1
 
    .EXAMPLE
        Get-AutoTaskModuleSettings -AutoTaskConfigPath C:\Celerium.AutoTask -AutoTaskConfigFile MyConfig.psd1 -OpenConfFile
 
        Opens the configuration file from the defined location in the default editor
 
        The location of the AutoTask configuration file in this example is:
            C:\Celerium.AutoTask\MyConfig.psd1
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Get-AutoTaskModuleSettings.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Index')]
    Param (
        [Parameter()]
        [string]$AutoTaskConfigPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop') {"Celerium.AutoTask"}else{".Celerium.AutoTask"}) ),

        [Parameter()]
        [string]$AutoTaskConfigFile = 'config.psd1',

        [Parameter()]
        [switch]$OpenConfigFile
    )

    begin {
        $AutoTaskConfig = Join-Path -Path $AutoTaskConfigPath -ChildPath $AutoTaskConfigFile
    }

    process {

        if (Test-Path -Path $AutoTaskConfig) {

            if($OpenConfigFile) {
                Invoke-Item -Path $AutoTaskConfig
            }
            else{
                Import-LocalizedData -BaseDirectory $AutoTaskConfigPath -FileName $AutoTaskConfigFile
            }

        }
        else{
            Write-Verbose "No configuration file found at [ $AutoTaskConfig ]"
        }

    }

    end {}

}
#EndRegion '.\Private\ModuleSettings\Get-AutoTaskModuleSettings.ps1' 89
#Region '.\Private\ModuleSettings\Import-AutoTaskModuleSettings.ps1' -1

function Import-AutoTaskModuleSettings {
<#
    .SYNOPSIS
        Imports the AutoTask BaseURI, API, & JSON configuration information to the current session
 
    .DESCRIPTION
        The Import-AutoTaskModuleSettings cmdlet imports the AutoTask BaseURI, API, & JSON configuration
        information stored in the AutoTask configuration file to the users current session
 
        By default the configuration file is stored in the following location:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigPath
        Define the location to store the AutoTask configuration file
 
        By default the configuration file is stored in the following location:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigFile
        Define the name of the AutoTask configuration file
 
        By default the configuration file is named:
            config.psd1
 
    .PARAMETER JsonSpec
        Defines the path to the swagger json file to use when creating the dynamic parameter
 
        By default the value used is the one defined in the root of the module folder
 
    .EXAMPLE
        Import-AutoTaskModuleSettings
 
        Validates that the configuration file created with the Export-AutoTaskModuleSettings cmdlet exists
        then imports the stored data into the current users session
 
        The default location of the AutoTask configuration file is:
            $env:USERPROFILE\Celerium.AutoTask\config.psd1
 
    .EXAMPLE
        Import-AutoTaskModuleSettings -AutoTaskConfigPath C:\Celerium.AutoTask -AutoTaskConfigFile MyConfig.psd1
 
        Validates that the configuration file created with the Export-AutoTaskModuleSettings cmdlet exists
        then imports the stored data into the current users session
 
        The location of the AutoTask configuration file in this example is:
            C:\Celerium.AutoTask\MyConfig.psd1
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Import-AutoTaskModuleSettings.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Set')]
    Param (
        [Parameter()]
        [string]$AutoTaskConfigPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop') {"Celerium.AutoTask"}else{".Celerium.AutoTask"}) ),

        [Parameter()]
        [string]$AutoTaskConfigFile = 'config.psd1'
    )

    begin {
        $AutoTaskConfig = Join-Path -Path $AutoTaskConfigPath -ChildPath $AutoTaskConfigFile

        $ModuleVersion = $MyInvocation.MyCommand.Version.ToString()

        switch ($PSVersionTable.PSEdition){
            'Core'      { $UserAgent = "Celerium.AutoTask/$ModuleVersion - PowerShell/$($PSVersionTable.PSVersion) ($($PSVersionTable.Platform) $($PSVersionTable.OS))" }
            'Desktop'   { $UserAgent = "Celerium.AutoTask/$ModuleVersion - WindowsPowerShell/$($PSVersionTable.PSVersion) ($($PSVersionTable.BuildVersion))" }
            default     { $UserAgent = "Celerium.AutoTask/$ModuleVersion - $([Microsoft.PowerShell.Commands.PSUserAgent].GetMembers('Static, NonPublic').Where{$_.Name -eq 'UserAgent'}.GetValue($null,$null))" }
        }

    }

    process {

        if (Test-Path $AutoTaskConfig) {
            $TempConfig = Import-LocalizedData -BaseDirectory $AutoTaskConfigPath -FileName $AutoTaskConfigFile

            $TempConfig.AutoTaskModuleApiSecretKey = ConvertTo-SecureString $TempConfig.AutoTaskModuleApiSecretKey

            Set-Variable -Name "AutoTaskModuleBaseUri"              -Value $TempConfig.AutoTaskModuleBaseUri                -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleBaseUriApiVersion"    -Value $TempConfig.AutoTaskModuleBaseUriApiVersion      -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleBaseUriComplete"      -Value $TempConfig.AutoTaskModuleBaseUriComplete        -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleApiUsername"          -Value $TempConfig.AutoTaskModuleApiUsername            -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleApiSecretKey"         -Value $TempConfig.AutoTaskModuleApiSecretKey           -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleApiIntegrationCode"   -Value $TempConfig.AutoTaskModuleApiIntegrationCode     -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleUserAgent"            -Value $TempConfig.AutoTaskModuleUserAgent              -Option ReadOnly -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleJSONConversionDepth"  -Value $TempConfig.AutoTaskModuleJSONConversionDepth    -Option ReadOnly -Scope Global -Force

            Write-Verbose "Celerium.AutoTask Module configuration loaded successfully from [ $AutoTaskConfig ]"

            # Clean things up
            Remove-Variable "TempConfig"
        }
        else {
            Write-Verbose "No configuration file found at [ $AutoTaskConfig ] run Add-AutoTaskAPIKey & Add-AutoTaskBaseUri to get started"

            Set-Variable -Name "AutoTaskModuleUserAgent" -Value $UserAgent -Scope Global -Force
            Set-Variable -Name "AutoTaskModuleJSONConversionDepth" -Value 100 -Scope Global -Force
        }

    }

    end {}

}
#EndRegion '.\Private\ModuleSettings\Import-AutoTaskModuleSettings.ps1' 110
#Region '.\Private\ModuleSettings\Initialize-AutoTaskModuleSettings.ps1' -1

#Used to auto load either baseline settings or saved configurations when the module is imported
Import-AutoTaskModuleSettings -Verbose:$false

if ($null -eq $AutoTaskModuleSwagger) {

    Write-Verbose "Loading dynamic parameters for API resource methods"
    Set-AutoTaskResourceDynamicParameter

}
#EndRegion '.\Private\ModuleSettings\Initialize-AutoTaskModuleSettings.ps1' 10
#Region '.\Private\ModuleSettings\Remove-AutoTaskModuleSettings.ps1' -1

function Remove-AutoTaskModuleSettings {
<#
    .SYNOPSIS
        Removes the stored AutoTask configuration folder
 
    .DESCRIPTION
        The Remove-AutoTaskModuleSettings cmdlet removes the AutoTask folder and its files
        This cmdlet also has the option to remove sensitive AutoTask variables as well
 
        By default configuration files are stored in the following location and will be removed:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AutoTaskConfigPath
        Define the location of the AutoTask configuration folder
 
        By default the configuration folder is located at:
            $env:USERPROFILE\Celerium.AutoTask
 
    .PARAMETER AndVariables
        Define if sensitive AutoTask variables should be removed as well
 
        By default the variables are not removed
 
    .EXAMPLE
        Remove-AutoTaskModuleSettings
 
        Checks to see if the default configuration folder exists and removes it if it does
 
        The default location of the AutoTask configuration folder is:
            $env:USERPROFILE\Celerium.AutoTask
 
    .EXAMPLE
        Remove-AutoTaskModuleSettings -AutoTaskConfigPath C:\Celerium.AutoTask -AndVariables
 
        Checks to see if the defined configuration folder exists and removes it if it does
        If sensitive AutoTask variables exist then they are removed as well
 
        The location of the AutoTask configuration folder in this example is:
            C:\Celerium.AutoTask
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Internal/Remove-AutoTaskModuleSettings.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Destroy',SupportsShouldProcess, ConfirmImpact = 'None')]
    Param (
        [Parameter()]
        [string]$AutoTaskConfigPath = $(Join-Path -Path $home -ChildPath $(if ($IsWindows -or $PSEdition -eq 'Desktop') {"Celerium.AutoTask"}else{".Celerium.AutoTask"}) ),

        [Parameter()]
        [switch]$AndVariables
    )

    begin {}

    process {

        if(Test-Path $AutoTaskConfigPath)  {

            Remove-Item -Path $AutoTaskConfigPath -Recurse -Force -WhatIf:$WhatIfPreference

            If ($AndVariables) {
                Remove-AutoTaskApiKey
                Remove-AutoTaskBaseUri
            }

            if ($WhatIfPreference -eq $false) {

                if (!(Test-Path $AutoTaskConfigPath)) {
                    Write-Output "The Celerium.AutoTask configuration folder has been removed successfully from [ $AutoTaskConfigPath ]"
                }
                else {
                    Write-Error "The Celerium.AutoTask configuration folder could not be removed from [ $AutoTaskConfigPath ]"
                }

            }

        }
        else {
            Write-Warning "No configuration folder found at [ $AutoTaskConfigPath ]"
        }

    }

    end {}

}
#EndRegion '.\Private\ModuleSettings\Remove-AutoTaskModuleSettings.ps1' 91
#Region '.\Public\Get-AutoTaskResource.ps1' -1

function Get-AutoTaskResource {
<#
    .SYNOPSIS
        Gets a resource
 
    .DESCRIPTION
        The Get-AutoTaskResource cmdlet gets a resource from the AutoTask API
        by ID or by using a simple or advanced search query
 
    .PARAMETER ID
        Defines the ID of the resource to get
 
    .PARAMETER ChildID
        Defines the ID of the child resource to get
 
    .PARAMETER SimpleSearch
        Defines a simple search query to use when getting the resource
 
        Limited to a single filter such as
        "isActive eq true" or "id eq 8765309"
 
    .PARAMETER AdvancedSearch
        Defines an advanced search query to use when getting the resource
 
        '{
            "MaxRecords":100,
            "filter":[
                {"op":"eq","field":"IsActive","value":true},
                {"op":"and","items":[
                    {"op":"beginsWith","field":"companyName","value":"D"}
                ]}
            ]
        }'
 
    .PARAMETER Method
        Defines the type of API method to use
 
        Allowed values:
        'GET', 'POST'
 
    .PARAMETER AllResults
        Returns all items from an endpoint
 
        By default only the first 500 items are returned
 
    .EXAMPLE
        Get-AutoTaskResource -Resource Companies -ID 8765309
 
        Get the company with ID 8765309
 
    .EXAMPLE
        Get-AutoTaskResource -Resource Companies -SimpleSearch "isActive eq true"
 
        Gets the first 500 active companies
 
    .EXAMPLE
        Get-AutoTaskResource -Resource Companies -AdvancedSearch '{"MaxRecords":100,"filter":[{"op":"eq","field":"IsActive","value":true},{"op":"and","items":[{"op":"beginsWith","field":"companyName","value":"D"}]}]}'
 
        Gets the first 100 active companies with a name starting with "D"
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/Get-AutoTaskResource.html
#>


    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'ID')]
        [int64]$ID,

        [Parameter(Mandatory = $false, ParameterSetName = 'ID')]
        [int64]$ChildID,

        [Parameter(Mandatory = $true, ParameterSetName = 'SimpleSearch')]
        [String]$SimpleSearch,

        [Parameter(Mandatory = $true, ParameterSetName = 'AdvancedSearch')]
        [String]$AdvancedSearch,

        [Parameter(Mandatory = $false, ParameterSetName = 'AdvancedSearch')]
        [ValidateSet('GET', 'POST')]
        [String]$Method,

        [Parameter(ParameterSetName = 'SimpleSearch')]
        [Parameter(ParameterSetName = 'AdvancedSearch')]
        [switch]$AllResults
    )

    DynamicParam {
        $AutoTaskModuleGetParameter
    }

    begin {

        $FunctionName       = $MyInvocation.InvocationName
        $ParameterName      = $functionName + '_Parameters'      -replace '-','_'

        $ResourceTarget     = $PSBoundParameters.Resource
        $ResourceIndex      = $AutoTaskModuleQueries | Group-Object Index -AsHashTable -AsString
        $ResourceEntry      = @(($ResourceIndex[$ResourceTarget] | Where-Object { $_.Get -eq $ResourceTarget }))[0]
        $ResourceUriName    = $ResourceEntry.Name -replace '/query$', '/{PARENTID}'

        # Fix path to InvoicePDF URL, must be unique vs. /Invoices in Swagger file
        $ResourceUriName    = $ResourceUriName -replace 'InvoicePDF', 'Invoices/{id}/InvoicePDF'

        if ($SimpleSearch) {
            $SearchOps      = $SimpleSearch -split ' '
            $AdvancedSearch    = ConvertTo-Json @{
                filter      = @(@{
                                field = $SearchOps[0]
                                op    = $SearchOps[1]
                                value = $SearchOps | Select-Object -Skip 2
                            })
            } -Compress
        }

    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        if ($ResourceTarget -like "*child*" -and $AdvancedSearch) {
            Write-Warning "JSON search cannot be performed on child items use the parent ID"
            break
        }

        switch ($PSCmdlet.ParameterSetName) {
            'ID'    { $Method = 'GET'  }
            default { $Method = 'POST' }
        }

        $ResourceUri = $ResourceUriName
        if ($ID) { $ResourceUri = ("$ResourceUri" -replace '{parentid}', "$($ID)")  }

        if ($ChildID) { $ResourceUri = ("$($ResourceUri)/$ChildID") }

        if ($AdvancedSearch) {
            switch ($Method) {
                'GET'   { $ResourceUri = ("$ResourceUri/query?search=$AdvancedSearch" -replace '{PARENTID}', '')}
                'POST'  {
                    $ResourceUri    = ("$ResourceUri/query" -replace '{PARENTID}', '')
                    $Body           = $AdvancedSearch
                }
                Default {

                    if (($AutoTaskModuleBaseUri.Length + $ResourceUri.Length + $AdvancedSearch.Length + 15 + 120 + 100) -ge 2048){
                        #15 characters for "//query?search="
                        #TODO: Calculation does not include Overwritten ParentID and is currently a better estimation. Therefore a "safe factor" of +120 chars is used
                        #100 characters for Call of next page (Including "paging={"pageSize":500,"previousIds":[<ID>],"nextIds":[<ID>]}&" UTF-8 encoded)
                        Write-Information "Using POST-Request as Request exceeded limit of 2100 characters. You can use -Method GET/POST to set a fixed Method."
                        $ResourceUri    = ("$ResourceUri/query" -replace '{PARENTID}', '')
                        $Body           = $AdvancedSearch
                    }
                    else { $ResourceUri = ("$ResourceUri/query?search=$AdvancedSearch" -replace '{PARENTID}', '') }

                }

            }

        }

        if ($ResourceTarget -eq "InvoicePDF" -and $ID) {
            $ResourceUri = ("$($ResourceUri)" -replace '{id}', "$($ID)")
        }

        $InvokeParams = @{
            Method      = $Method
            ResourceURI = $ResourceUri
            AllResults  = $AllResults
        }

        if ($Method -eq 'POST') { $InvokeParams.Data = $Body }

        Set-Variable -Name $ParameterName -Value $InvokeParams -Scope Global -Force -Confirm:$false

        return Invoke-AutoTaskRequest @InvokeParams

    }

}
#EndRegion '.\Public\Get-AutoTaskResource.ps1' 185
#Region '.\Public\New-AutoTaskBody.ps1' -1

function New-AutoTaskBody {
<#
    .SYNOPSIS
        Creates a new resource body object
 
    .DESCRIPTION
        The New-AutoTaskBody cmdlet creates a new resource body
        for the AutoTask API
 
        Helpful when working with resource queries, modifications,
        and creating filters for advanced searches
 
    .PARAMETER Empty
        Creates a new resource body with no content
 
    .EXAMPLE
        New-AutoTaskBody -Resource ContactGroups
 
        Creates a template showing all available fields with their types and picklist values
 
    .EXAMPLE
        New-AutoTaskBody -Resource Companies -Empty
 
        Creates a new resource body for the company with no content
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/New-AutoTaskBody.html
#>


    [CmdletBinding(DefaultParameterSetName = 'Empty')]
    Param(
        [Parameter(Mandatory = $false, ParameterSetName = 'Empty')]
        [switch]$Empty
    )

    DynamicParam {
        $AutoTaskModulePostPatchParameter
    }

    begin {

        $FunctionName   = $MyInvocation.InvocationName
        $ResourceTarget = $PSBoundParameters.Resource

    }
    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        $ResourceURI = ($AutoTaskModuleQueries | Where-Object { $_.Post -eq $ResourceTarget } | Select-Object -First 1).Name -replace '/query$', ''
        if (-not $ResourceURI) {
            $ResourceURI = ($AutoTaskModuleQueries | Where-Object { $_.Patch -eq $ResourceTarget } | Select-Object -First 1).Name -replace '/query$', ''
        }

        $TargetURI = "$ResourceURI/entityInformation"
        try {


            $ObjectTemplate = (Invoke-AutoTaskRequest -Method GET -ResourceURI "$TargetURI/fields").fields
            try {
                $UDFs = (Invoke-AutoTaskRequest -Method GET -ResourceURI "$TargetURI/userDefinedFields").fields | Select-Object Name,Value
            }
            catch {
                if ( $_.Exception.Response.StatusCode -ne "NotFound" ) { throw }
            }

            if (-not $ObjectTemplate) { Write-Warning "Could not retrieve entityInformation for [ $ResourceTarget ]" }
            else {

                $OutputResults  = [System.Collections.Generic.List[object]]::new()
                $Properties     = [ordered]@{}

                if ($Empty) {
                    foreach ($Property in $ObjectTemplate | Where-Object { -not $_.IsReadOnly }) {
                        $Properties[$Property.Name] = $null
                    }
                    $OutputResults.Add([PSCustomObject]$Properties)
                }
                else {
                    foreach ($Property in $ObjectTemplate) {
                        $FieldMetadata = [PSCustomObject]@{
                            Name           = $Property.Name
                            DataType       = $Property.DataType
                            Length         = $Property.Length
                            IsReadOnly     = $Property.IsReadOnly
                            IsRequired     = $Property.IsRequired
                            PickListValues = if ($Property.PickListValues) {
                                $Property.PickListValues | Select-Object Label,Value,IsActive
                            } else { $null }
                        }
                        $OutputResults.Add($FieldMetadata)
                    }

                    if ($UDFs) {
                        $UDFMetadata = [PSCustomObject]@{
                            Name           = "userDefinedFields"
                            DataType       = "object[]"
                            IsReadOnly     = $false
                            IsRequired     = $false
                            PickListValues = $UDFs
                        }
                        $OutputResults.Add($UDFMetadata)
                    }
                }

            }

            return $OutputResults

        }
        catch {
            Write-Error $_
        }

    }
}
#EndRegion '.\Public\New-AutoTaskBody.ps1' 120
#Region '.\Public\New-AutoTaskResource.ps1' -1

function New-AutoTaskResource {
<#
    .SYNOPSIS
        Creates a new resource
 
    .DESCRIPTION
        The New-AutoTaskResource cmdlet creates a new resource
        in the AutoTask API
 
    .PARAMETER Data
        The data body to use when creating the resource
 
    .EXAMPLE
        New-AutoTaskResource -Resource Companies -Data $data
 
        Creates a new resource for the company with the specified data body
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/New-AutoTaskResource.html
#>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
    Param(
        [Parameter(Mandatory = $false)]
        [String]$ParentId,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        $Data
    )

    DynamicParam {
        $AutoTaskModulePostParameter
    }

    begin {

        $FunctionName   = $MyInvocation.InvocationName
        $ParameterName  = $FunctionName + '_Parameters' -replace '-','_'

        $ResourceTarget = $PSBoundParameters.Resource
        $ResourceUri    = ($AutoTaskModuleQueries | Where-Object { $_.Post -eq $ResourceTarget } | Select-Object -First 1).Name -replace '/query$', ''

    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        if ($ResourceTarget -like "*child*") {
            if (-not $ParentId ) {
                Write-Error "You must specify a parentId when creating a child resource"
                break
            }
            $ResourceUri = $ResourceUri -replace '{parentId}', $ParentId
        }

        $InvokeParams = @{
            Method      = 'POST'
            ResourceURI = $ResourceUri
            Data        = $Data
        }

        Set-Variable -Name $ParameterName -Value $InvokeParams -Scope Global -Force -Confirm:$false

        if ($PSCmdlet.ShouldProcess($ResourceUri)) {
            return Invoke-AutoTaskRequest @InvokeParams
        }

    }
}
#EndRegion '.\Public\New-AutoTaskResource.ps1' 75
#Region '.\Public\Remove-AutoTaskResource.ps1' -1

function Remove-AutoTaskResource {
<#
    .SYNOPSIS
        Deletes a resource
 
    .DESCRIPTION
        The Remove-AutoTaskResource cmdlet deletes a resource
        in the AutoTask API
 
    .PARAMETER ID
        The ID of the resource to delete
 
    .PARAMETER ChildID
        The ID of the child resource to delete
 
    .EXAMPLE
        Remove-AutoTaskResource -Resource Companies -ID 123
 
        Deletes the company resource with the specified ID
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/Remove-AutoTaskResource.html
#>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    Param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [int64]$ID,

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [int64]$ChildID
    )

    DynamicParam {
        $AutoTaskModuleDeleteParameter
    }

    begin {

        $FunctionName   = $MyInvocation.InvocationName
        $ParameterName  = $functionName + '_Parameters'      -replace '-','_'

        $ResourceTarget = $PSBoundParameters.Resource
        #$ResourceUri = (($AutoTaskModuleQueries | Where-Object { $_.Delete -eq $ResourceTarget }).Name | Select-Object -First 1) -replace '/query', '/{PARENTID}' | Select-Object -First 1
        $ResourceUri    = ($AutoTaskModuleQueries | Where-Object { $_.Delete -eq $ResourceTarget } | Select-Object -First 1).Name -replace '/query$', '/{PARENTID}'

    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        if (-not $ChildID -and $ResourceTarget -like "*Child*") {
            Write-Warning "You must enter a ChildID to delete a Child resource"
            break
        }

        $ResourceUri = $ResourceUri -replace '{PARENTID}', $ID

        if ($ID)        { $ResourceUri = $ResourceUri -replace '{ID}', $ID }
        if ($ChildID)   { $ResourceUri = $ResourceUri -replace '{ID}', $ChildID }

        $InvokeParams = @{
            Method      = 'DELETE'
            ResourceURI = $ResourceUri
        }

        Set-Variable -Name $ParameterName -Value $InvokeParams -Scope Global -Force -Confirm:$false

        if ($PSCmdlet.ShouldProcess($ResourceUri)) {
            return Invoke-AutoTaskRequest @InvokeParams
        }


    }
}
#EndRegion '.\Public\Remove-AutoTaskResource.ps1' 80
#Region '.\Public\Set-AutoTaskResource.ps1' -1

function Set-AutoTaskResource {
<#
    .SYNOPSIS
        Updates a resource
 
    .DESCRIPTION
        The Set-AutoTaskResource cmdlet updates a resource
        in the AutoTask API
 
    .PARAMETER ID
        The ID of the resource to update
 
    .PARAMETER ParentID
        The ID of the parent resource to update
 
    .EXAMPLE
        Set-AutoTaskResource -Resource Companies -ID 123 -Data $data
 
        Updates the company resource with the specified ID
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/Set-AutoTaskResource.html
#>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    Param(
        [Parameter(ParameterSetName = 'ParentID', Mandatory = $false)]
        [int64]$ParentId,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [int64]$ID,

        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        $Data
    )

    DynamicParam {
        $AutoTaskModulePatchParameter
    }

    begin {

        $FunctionName   = $MyInvocation.InvocationName
        $ParameterName  = $functionName + '_Parameters'      -replace '-','_'

        $ResourceTarget = $PSBoundParameters.Resource
        $ResourceUri    = ($AutoTaskModuleQueries | Where-Object { $_.Patch -eq $ResourceTarget } | Select-Object -First 1).Name -replace '/query$', ''


    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        if ($ResourceTarget -like "*child*") {
            if (-not $ParentId) {
                Write-Warning "You must specify a parentId when setting a child resource"
                break
            }
            $ResourceUri = $ResourceUri -replace '{parentId}', $ParentId
        }

        $InvokeParams = @{
            Method      = 'PATCH'
            ResourceURI = $ResourceUri
            Data        = $Data
        }

        Set-Variable -Name $ParameterName -Value $InvokeParams -Scope Global -Force -Confirm:$false

        if ($PSCmdlet.ShouldProcess($ResourceUri)) {
            return Invoke-AutoTaskRequest @InvokeParams
        }

    }
}
#EndRegion '.\Public\Set-AutoTaskResource.ps1' 82
#Region '.\Public\Show-AutoTaskResource.ps1' -1

function Show-AutoTaskResource {
<#
    .SYNOPSIS
        Shows available values from the dynamically generated
        resource parameter
 
    .DESCRIPTION
        The Show-AutoTaskResource cmdlet shows available values
        from the dynamically generated resource parameter
 
        By default all available values are show
 
    .PARAMETER Name
        Defines the name of the resource to limit the output to
 
        This is a wildcard search and will return all resources
        that start with the provided value
 
    .PARAMETER Method
        Defines the type of API method to show available values for
 
        Allowed values:
        'GET', 'PUT', 'POST', 'PATCH', 'DELETE'
 
    .PARAMETER UniqueOnly
        Returns only unique resource names
 
    .PARAMETER JsonSpec
        Defines the path to the swagger json file to use when creating
        the dynamic parameter
 
    .EXAMPLE
        Show-AutoTaskResource
 
        Show all available values from the dynamically generated resource parameter
 
    .EXAMPLE
        Show-AutoTaskResource -Name Companies
 
        Shows available values on the Companies* resources
 
    .EXAMPLE
        Show-AutoTaskResource -Name Companies -Method GET
 
        Shows available values for the GET method on the Companies* resource
 
    .NOTES
        N/A
 
    .LINK
        https://celerium.github.io/Celerium.AutoTask/site/Public/Show-AutoTaskResource.html
#>


    [CmdletBinding(defaultParameterSetName = 'All')]
    Param(
        [Parameter(Mandatory = $false)]
        [string]$Name,

        [Parameter(Mandatory = $false)]
        [ValidateSet('GET', 'PUT', 'POST', 'PATCH', 'DELETE')]
        [String]$Method,

        [Parameter(Mandatory = $false, ParameterSetName = 'UniqueOnly')]
        [switch]$UniqueOnly,

        [Parameter(Mandatory = $false)]
        [string]$JsonSpec = $(Join-Path -Path "$($MyInvocation.MyCommand.Module.ModuleBase)" -ChildPath "AutoTaskAPI-v1-2023.6.json")
    )


    begin {

        $FunctionName       = $MyInvocation.InvocationName
        $ParameterName      = $functionName + '_Parameters'      -replace '-','_'

    }

    process {

        Write-Verbose "[ $FunctionName ] - Running the [ $($PSCmdlet.ParameterSetName) ] parameterSet"

        if (-not $AutoTaskModuleSwagger) {
            $Swagger = Get-Content $JsonSpec -Raw | ConvertFrom-Json

            $Queries = foreach ($Path in $Swagger.Paths.PSObject.Properties) {
                [PSCustomObject]@{
                    Index  = $Path.Name.Split('/')[2]
                    Name   = $Path.Name
                    GET    = $Path.Value.GET.Tags
                    PUT    = $Path.Value.PUT.Tags
                    POST   = $Path.Value.POST.Tags
                    PATCH  = $Path.Value.PATCH.Tags
                    DELETE = $Path.Value.DELETE.Tags
                }
            }
        }
        else {
            $Queries = $AutoTaskModuleQueries
        }

        $ResourceList = foreach ($Type in 'GET','PUT','POST','PATCH','DELETE') {
            foreach ($Query in $Queries | Where-Object { $null -ne $_.$Type }) {
                [PSCustomObject]@{
                    Method   = $Type
                    Resource = $Query.$Type | Select-Object -Last 1
                    Path     = $Query.Name
                    Index    = $Query.Index
                }
            }
        }

        $ResourceList = $ResourceList | Sort-Object Resource,Method,Path

        if ($Name)      { $ResourceList = $ResourceList | Where-Object Resource -like "$Name*"}
        if ($Method)    { $ResourceList = $ResourceList | Where-Object Method -eq $Method }
        if ($UniqueOnly){ $ResourceList = $ResourceList | Select-Object -Property Resource -Unique }

        Set-Variable -Name $ParameterName -Value $PSBoundParameters -Scope Global -Force -Confirm:$false

        return $ResourceList

    }

}
#EndRegion '.\Public\Show-AutoTaskResource.ps1' 125