Public/Tasks.ps1

<#
.SYNOPSIS
    Get all ClickUp tasks under a particular list.
.DESCRIPTION
    Get all ClickUp tasks under a particular list or team. Can accept ListID or TeamID via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> Get-ClickUpTasks -ListID 11111111
    Gets all ClickUp tasks under List with ID "11111111".
.EXAMPLE
    PS C:\> Get-ClickUpTasks -ListID 22222222 -Archived $true -Page 1 -OrderBy 'updated' -Statuses 'New','In Progress'
    Gets all ClickUp tasks under List with ID "22222222" and various other options.
.EXAMPLE
    PS C:\> Get-ClickUpList -ListID 11111111 | Get-ClickUpTasks
    Gets tasks by piping list ID from Get-ClickUpList.
.INPUTS
    System.String. ListID or TeamID via pipeline by property name.
.OUTPUTS
    System.Object
    System.Array
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/gettasks
.LINK
    https://developer.clickup.com/reference/getfilteredteamtasks
#>

function Get-ClickUpTasks {
    [CmdletBinding(DefaultParameterSetName = 'ListID')]
    [OutputType([System.Object], [System.Array])]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'ListID', ValueFromPipelineByPropertyName = $true)]
        [Alias('list_id', 'id')]
        [string]$ListID,

        [Parameter(Mandatory = $true, ParameterSetName = 'TeamID', ValueFromPipelineByPropertyName = $true)]
        [Alias('team_id', 'id')]
        [string]$TeamID,

        [Parameter(ParameterSetName = 'ListID')]
        [bool]$Archived = $false,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [uint64]$Page = 0,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [ValidateSet('id', 'created', 'updated', 'due_date')]
        [string]$OrderBy = 'created',

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [bool]$Reverse = $false,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [bool]$Subtasks = $false,

        [Parameter(ParameterSetName = 'TeamID')]
        [uint64[]]$SpaceIDs,

        [Parameter(ParameterSetName = 'TeamID')]
        [uint64[]]$ProjectIDs,

        [Parameter(ParameterSetName = 'TeamID')]
        [uint64[]]$ListIDs,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [string[]]$Statuses,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [bool]$IncludeClosed = $false,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [string[]]$Assignees,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DueDateGreaterThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DueDateLessThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DateCreatedGreaterThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DateCreatedLessThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DateUpdatedGreaterThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [datetime]$DateUpdatedLessThan,

        [Parameter(ParameterSetName = 'ListID')]
        [Parameter(ParameterSetName = 'TeamID')]
        [array]$CustomFields,

        [Parameter(ParameterSetName = 'TeamID')]
        [bool]$CustomTaskIDs
    )

    $QueryString = @{
        page           = $Page
        order_by       = $OrderBy
        reverse        = $Reverse
        subtasks       = $Subtasks
        include_closed = $IncludeClosed
    }
    if ($PSBoundParameters.ContainsKey('Archived')) {
        $QueryString.Add('archived', $Archived)
    }
    if ($PSBoundParameters.ContainsKey('SpaceIDs')) {
        $QueryString.Add('space_ids[]', $SpaceIDs)
    }
    if ($PSBoundParameters.ContainsKey('ProjectIDs')) {
        $QueryString.Add('project_ids[]', $ProjectIDs)
    }
    if ($PSBoundParameters.ContainsKey('ListIDs')) {
        $QueryString.Add('list_ids[]', $ListIDs)
    }
    if ($PSBoundParameters.ContainsKey('Statuses')) {
        $QueryString.Add('statuses[]', $Statuses)
    }
    if ($PSBoundParameters.ContainsKey('Assignees')) {
        $QueryString.Add('assignees[]', $Assignees)
    }
    if ($PSBoundParameters.ContainsKey('DueDateGreaterThan')) {
        $QueryString.Add('due_date_gt', (Get-DatePosixMilliseconds -DateTime $DueDateGreaterThan))
    }
    if ($PSBoundParameters.ContainsKey('DueDateLessThan')) {
        $QueryString.Add('due_date_lt', (Get-DatePosixMilliseconds -DateTime $DueDateLessThan))
    }
    if ($PSBoundParameters.ContainsKey('DateCreatedGreaterThan')) {
        $QueryString.Add('date_created_gt', (Get-DatePosixMilliseconds -DateTime $DateCreatedGreaterThan))
    }
    if ($PSBoundParameters.ContainsKey('DateCreatedLessThan')) {
        $QueryString.Add('date_created_lt', (Get-DatePosixMilliseconds -DateTime $DateCreatedLessThan))
    }
    if ($PSBoundParameters.ContainsKey('DateUpdatedGreaterThan')) {
        $QueryString.Add('date_updated_gt', (Get-DatePosixMilliseconds -DateTime $DateUpdatedGreaterThan))
    }
    if ($PSBoundParameters.ContainsKey('DateUpdatedLessThan')) {
        $QueryString.Add('date_updated_lt', (Get-DatePosixMilliseconds -DateTime $DateUpdatedLessThan))
    }
    if ($PSBoundParameters.ContainsKey('CustomFields')) {
        $QueryString.Add('custom_fields', $CustomFields)
    }

    Write-Verbose 'Entering Get-ClickUpTasks'
    try {
        if ($PSBoundParameters.ContainsKey('ListID')) {
            Write-Verbose "Getting tasks for list ID: $ListID"
            $Tasks = Invoke-ClickUpAPIGet -Arguments $QueryString -Endpoint "list/$ListID/task"
        } elseif ($PSBoundParameters.ContainsKey('TeamID')) {
            Write-Verbose "Getting tasks for team ID: $TeamID"
            $Tasks = Invoke-ClickUpAPIGet -Arguments $QueryString -Endpoint "team/$TeamID/task"
        }
        Write-Verbose 'Successfully retrieved tasks'
        return $Tasks.tasks
    } catch {
        Write-Error "Error in Get-ClickUpTasks: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Get a ClickUp task.
.DESCRIPTION
    Get a ClickUp task. The TaskID can be provided via pipeline from other cmdlets that return task objects.
.EXAMPLE
    PS C:\> Get-ClickUpTask -TaskID 9hz
    Get a ClickUp task with Task ID "9hz".
.EXAMPLE
    PS C:\> Get-ClickUpTask -TaskID 9hz -CustomTaskIDs $true -TeamID 123
    Get a ClickUp task with Task ID "9hz" using custom task IDs and specifying a Team ID.
.INPUTS
    System.String. You can pipe a task ID to this cmdlet.
.OUTPUTS
    System.Object
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/gettask
#>

function Get-ClickUpTask {
    [CmdletBinding(DefaultParameterSetName = 'TaskID')]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id','id')]
        [string]$TaskID,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [bool]$CustomTaskIDs,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [uint64]$TeamID,
        [Parameter(ParameterSetName = 'TaskID')]
        [Parameter(ParameterSetName = 'CustomTaskIDs')]
        $IncludeSubtasks = $false
    )

    $QueryString = @{
        include_subtasks = $IncludeSubtasks
    }

    if ($PSBoundParameters.ContainsKey('CustomTaskIDs')) {
        $QueryString += @{
            custom_task_ids = $CustomTaskIDs
            team_id         = $TeamID
        }
    }

    Write-Verbose 'Entering Get-ClickUpTask'
    try {
        Write-Verbose "Getting task with ID: $TaskID"
        $Task = Invoke-ClickUpAPIGet -Arguments $QueryString -Endpoint "task/$TaskID"
        Write-Verbose 'Successfully retrieved task'
        return $Task
    } catch {
        Write-Error "Error in Get-ClickUpTask: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Get a ClickUp task's time in status.
.DESCRIPTION
    Get a ClickUp task's time in status. Can accept TaskID via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> Get-ClickUpTaskTimeInStatus -TaskID 9hz
    Gets a ClickUp task's time in status with ID "9hz".
.EXAMPLE
    PS C:\> Get-ClickUpTaskTimeInStatus -TaskID "CustomTaskID" -CustomTaskIDs $true -TeamID 123
    Gets a ClickUp task's time in status with custom ID "CustomTaskID".
.EXAMPLE
    PS C:\> Get-ClickUpTask -TaskID 9hz | Get-ClickUpTaskTimeInStatus
    Gets task time in status by piping task ID from Get-ClickUpTask.
.INPUTS
    System.String. TaskID via pipeline by property name.
.OUTPUTS
    System.Object
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/gettaskstimeinstatus
#>

function Get-ClickUpTaskTimeInStatus {
    [CmdletBinding(DefaultParameterSetName = 'TaskID')]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID', ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs', ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id', 'id')]
        [string]$TaskID,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [bool]$CustomTaskIDs,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [uint64]$TeamID,
        [Parameter(ParameterSetName = 'TaskID')]
        [Parameter(ParameterSetName = 'CustomTaskIDs')]
        $IncludeSubtasks = $false
    )

    $QueryString = @{
        include_subtasks = $IncludeSubtasks
    }

    if ($PSBoundParameters.ContainsKey('CustomTaskIDs')) {
        $QueryString += @{
            custom_task_ids = $CustomTaskIDs
            team_id         = $TeamID
        }
    }

    Write-Verbose 'Entering Get-ClickUpTaskTimeInStatus'
    try {
        Write-Verbose "Getting time in status for task ID: $TaskID"
        $Task = Invoke-ClickUpAPIGet -Arguments $QueryString -Endpoint "task/$TaskID/time_in_status"
        Write-Verbose 'Successfully retrieved task time in status'
        return $Task
    } catch {
        Write-Error "Error in Get-ClickUpTaskTimeInStatus: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Get a ClickUp bulk task's time in status.
.DESCRIPTION
    View how long two or more tasks have been in each status. The Total time in Status ClickApp must first be enabled by the Workspace owner or an admin. Can accept TaskID array via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> Get-ClickUpTaskTimeInStatusBulk -TaskID 9hz,3cuh,g4fs
    Gets time in status for multiple ClickUp tasks with IDs "9hz", "3cuh", and "g4fs".
.EXAMPLE
    PS C:\> Get-ClickUpTaskTimeInStatusBulk -TaskID "CustomTaskID 1","CustomTaskID 2","CustomTaskID 3" -CustomTaskIDs $true -TeamID 123
    Gets multiple ClickUp task's time in status with custom IDs "CustomTaskID 1", "CustomTaskID 2", and "CustomTaskID 3".
.EXAMPLE
    PS C:\> Get-ClickUpTasks -ListID 123 | Select-Object -ExpandProperty id | Get-ClickUpTaskTimeInStatusBulk
    Gets bulk time in status by piping task IDs from Get-ClickUpTasks.
.INPUTS
    System.String[]. TaskID array via pipeline by property name.
.OUTPUTS
    System.Object
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/getbulktaskstimeinstatus
#>

function Get-ClickUpTaskTimeInStatusBulk {
    [CmdletBinding(DefaultParameterSetName = 'TaskID')]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID', ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs', ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id', 'id')]
        [string[]]$TaskID,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [bool]$CustomTaskIDs,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [uint64]$TeamID
    )

    $QueryString = @{
        task_ids = $TaskID
    }

    if ($PSBoundParameters.ContainsKey('CustomTaskIDs')) {
        $QueryString += @{
            custom_task_ids = $CustomTaskIDs
            team_id         = $TeamID
        }
    }

    Write-Verbose 'Entering Get-ClickUpTaskTimeInStatusBulk'
    try {
        Write-Verbose "Getting bulk time in status for task IDs: $($TaskID -join ', ')"
        $Task = Invoke-ClickUpAPIGet -Arguments $QueryString -Endpoint 'task/bulk_time_in_status/task_ids'
        Write-Verbose 'Successfully retrieved bulk task time in status'
        return $Task
    } catch {
        Write-Error "Error in Get-ClickUpTaskTimeInStatusBulk: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Create a new ClickUp task.
.DESCRIPTION
    Create a new ClickUp task. Can accept ListID via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> New-ClickUpTask -ListID 11111111 -Name 'This is a new task'
    Creates a new ClickUp Task called "This is a new task" under the list with ID "11111111".
.EXAMPLE
    PS C:\> New-ClickUpTask -ListID 22222222 -Name 'This is another new task' -Description "Description of the other new task" -Assignees 33333333 -Status 'Review' -Priority 1
    Creates a new ClickUp Task called "This is another new task" under the list with ID "22222222" with various other parameters.
.EXAMPLE
    PS C:\> Get-ClickUpList -ListID 11111111 | New-ClickUpTask -Name 'Task from Pipeline'
    Creates task by piping list ID from Get-ClickUpList.
.INPUTS
    System.UInt64. ListID via pipeline by property name.
.OUTPUTS
    System.Object
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/createtask
#>

function New-ClickUpTask {
    [CmdletBinding()]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('list_id', 'id')]
        [uint64]$ListID,
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [string]$Description,
        [uint64[]]$Assignees,
        [string[]]$Tags,
        [string]$Status,
        [uint64]$Priority,
        [datetime]$DueDate,
        [bool]$DueDateTime = $false,
        [uint64]$TimeEstimate,
        [datetime]$StartDate,
        [bool]$StartDateTime = $false,
        [bool]$NotifyAll,
        [string]$Parent,
        [string]$LinksTo,
        [bool]$CheckRequiredCustomFields,
        [hashtable[]]$CustomFields
    )

    $Body = @{
        name        = $Name
        description = $Description
    }
    if ($PSBoundParameters.ContainsKey('Assignees')) {
        $Body.Add('assignees', $Assignees)
    }
    if ($PSBoundParameters.ContainsKey('Tags')) {
        $Body.Add('tags', $Tags)
    }
    if ($PSBoundParameters.ContainsKey('Status')) {
        $Body.Add('status', $Status)
    }
    if ($PSBoundParameters.ContainsKey('Priority')) {
        $Body.Add('priority', $Priority)
    }
    if ($PSBoundParameters.ContainsKey('DueDate')) {
        $Body.Add('due_date', $DueDate)
        $Body.Add('due_date_time', $DueDateTime)
    }
    if ($PSBoundParameters.ContainsKey('TimeEstimate')) {
        $Body.Add('time_estimate', $TimeEstimate)
    }
    if ($PSBoundParameters.ContainsKey('StartDate')) {
        $Body.Add('start_date', $StartDate)
        $Body.Add('start_date_time', $StartDateTime)
    }
    if ($PSBoundParameters.ContainsKey('NotifyAll')) {
        $Body.Add('notify_all', $NotifyAll)
    }
    if ($PSBoundParameters.ContainsKey('Parent')) {
        $Body.Add('parent', $Parent)
    }
    if ($PSBoundParameters.ContainsKey('LinksTo')) {
        $Body.Add('links_to', $LinksTo)
    }
    if ($PSBoundParameters.ContainsKey('CheckRequiredCustomFields')) {
        $Body.Add('check_required_custom_fields', $CheckRequiredCustomFields)
    }
    if ($PSBoundParameters.ContainsKey('CustomFields')) {
        $Body.Add('custom_fields', $CustomFields)
    }

    Write-Verbose 'Entering New-ClickUpTask'
    try {
        Write-Verbose "Creating new task '$Name' in list ID: $ListID"
        $Task = Invoke-ClickUpAPIPost -Endpoint "list/$ListID/task" -Body $Body
        Write-Verbose 'Successfully created task'
        return $Task
    } catch {
        Write-Error "Error in New-ClickUpTask: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Update a ClickUp task.
.DESCRIPTION
    Update a ClickUp task. The TaskID can be provided via pipeline from other cmdlets that return task objects.
.EXAMPLE
    PS C:\> $Body = @{
    >> name = "Updated Task Name"
    >> description = "Updated Task Content"
    >> status = "in progress"
    >> }
    PS C:\> Set-ClickUpTask -TaskID 9hx -Body $Body
    Updated the task with ID "9hx".
.EXAMPLE
    PS C:\> $Body = @{
    >> name = "Updated Task Name"
    >> description = "Updated Task Content"
    >> status = "in progress"
    >> priority = 1
    >> time_estimate = 8640000
    >> assignees = @{
    >> "add = @(
    >> 182
    >> )
    >> "rem = @(
    >> 183
    >> )
    >> }
    >> "archived = false
    >> }
    PS C:\> Set-ClickUpTask -TaskID 9hx -Body $Body
    Updated the task with ID "9hx".
.INPUTS
    System.String. You can pipe a task ID to this cmdlet.
.OUTPUTS
    System.Object
.NOTES
    See the link for information on how to format the body.

Body format:
    @{
        name = "Updated Task Name"
        description = "Updated Task Content"
        status = "in progress"
        priority = 1
        time_estimate = 8640000
        assignees = @{
            "add = @(
                182
            )
            "rem = @(
                183
            )
        }
        "archived = false
    }
.LINK
    https://developer.clickup.com/reference/updatetask
#>

function Set-ClickUpTask {
    [CmdletBinding(DefaultParameterSetName = 'TaskID')]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id','id')]
        [string]$TaskID,
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID')]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [hashtable]$Body,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [bool]$CustomTaskIDs,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [uint64]$TeamID
    )


    if ($PSBoundParameters.ContainsKey('CustomTaskIDs')) {
        $QueryString = @{
            custom_task_ids = $true
            team_id         = $TeamID
        }
    } else {
        $QueryString = @{}
    }

    Write-Verbose 'Entering Set-ClickUpTask'
    try {
        Write-Verbose "Updating task with ID: $TaskID"
        $Task = Invoke-ClickUpAPIPut -Arguments $QueryString -Endpoint "task/$TaskID/" -Body $Body
        Write-Verbose 'Successfully updated task'
        return $Task
    } catch {
        Write-Error "Error in Set-ClickUpTask: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Remove a ClickUp task.
.DESCRIPTION
    Remove a ClickUp task. The TaskID can be provided via pipeline from other cmdlets that return task objects.
.EXAMPLE
    PS C:\> Remove-ClickUpTask -TaskID 9hx
    Remove the task with ID "9hx".
.EXAMPLE
    PS C:\> Remove-ClickUpTask -TaskID 'CustomTaskID' -CustomTaskIDs $True -TeamID 1111111
    Remove the task with custom ID "CustomTaskID".
.EXAMPLE
    PS C:\> Get-ClickUpTasks -ListID 123 | Remove-ClickUpTask
    Pipe task IDs from Get-ClickUpTasks to remove multiple tasks.
.INPUTS
    System.String. You can pipe a task ID to this cmdlet.
.OUTPUTS
    None. This cmdlet does not return any output.
.NOTES
    See the link for more information.
.LINK
    https://developer.clickup.com/reference/deletetask
#>

function Remove-ClickUpTask {
    [CmdletBinding(DefaultParameterSetName = 'TaskID', SupportsShouldProcess, ConfirmImpact = 'High')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'TaskID', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id','id')]
        [string]$TaskID,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [bool]$CustomTaskIDs,
        [Parameter(Mandatory = $true, ParameterSetName = 'CustomTaskIDs')]
        [uint64]$TeamID
    )

    Write-Verbose 'Entering Remove-ClickUpTask'
    if ($PSCmdlet.ShouldProcess($TaskID)) {
        if ($PSBoundParameters.ContainsKey('CustomTaskIDs')) {
            $QueryString = @{
                custom_task_ids = $true
                team_id         = $TeamID
            }
        } else {
            $QueryString = @{}
        }

        try {
            Write-Verbose "Removing task with ID: $TaskID"
            $Null = Invoke-ClickUpAPIDelete -Arguments $QueryString -Endpoint "task/$TaskID"
            Write-Verbose 'Successfully removed task'
        } catch {
            Write-Error "Error in Remove-ClickUpTask: $($_.Exception.Message)"
            throw $_
        }
    }
}

<#
.SYNOPSIS
    Merge ClickUp tasks.
.DESCRIPTION
    Merge multiple ClickUp tasks into a single task. The source tasks will be merged into the target task. Can accept TaskID via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> Merge-ClickUpTasks -TaskID '9hz' -SourceTaskIDs '3cuh','g4fs'
    Merges tasks with IDs "3cuh" and "g4fs" into the task with ID "9hz".
.EXAMPLE
    PS C:\> Merge-ClickUpTasks -TaskID 'abc123' -SourceTaskIDs 'def456','ghi789','jkl012'
    Merges three source tasks into the target task with ID "abc123".
.EXAMPLE
    PS C:\> Get-ClickUpTask -TaskID '9hz' | Merge-ClickUpTasks -SourceTaskIDs '3cuh','g4fs'
    Merges tasks by piping task ID from Get-ClickUpTask.
.INPUTS
    System.String. TaskID via pipeline by property name.
.OUTPUTS
    None. This cmdlet does not return any output.
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/mergetasks
#>

function Merge-ClickUpTasks {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('task_id', 'id')]
        [string]$TaskID,
        [Parameter(Mandatory = $true)]
        [string[]]$SourceTaskIDs
    )

    $Body = @{
        source_task_ids = $SourceTaskIDs
    }

    Write-Verbose 'Entering Merge-ClickUpTasks'
    try {
        Write-Verbose "Merging tasks $($SourceTaskIDs -join ', ') into task ID: $TaskID"
        $Null = Invoke-ClickUpAPIPost -Endpoint "task/$TaskID/merge" -Body $Body
        Write-Verbose 'Successfully merged tasks'
    } catch {
        Write-Error "Error in Merge-ClickUpTasks: $($_.Exception.Message)"
        throw $_
    }
}

<#
.SYNOPSIS
    Create Task From Template
.DESCRIPTION
    Create a new task using a task template defined in your workspace. Publicly shared templates must be added to your Workspace before you can use them with the public API. Can accept ListID via pipeline input for integration with other cmdlets.
.EXAMPLE
    PS C:\> New-ClickUpTaskFromTemplate -ListID 11111111 -TemplateID 'abc123' -Name 'Task from template'
    Creates a new ClickUp Task called "Task from template" using the template with ID "abc123" under the list with ID "11111111".
.EXAMPLE
    PS C:\> New-ClickUpTaskFromTemplate -ListID 22222222 -TemplateID 'def456' -Name 'Another task from template'
    Creates a new ClickUp Task called "Another task from template" using the template with ID "def456" under the list with ID "22222222".
.EXAMPLE
    PS C:\> Get-ClickUpList -ListID 11111111 | New-ClickUpTaskFromTemplate -TemplateID 'abc123' -Name 'Task from pipeline'
    Creates task from template by piping list ID from Get-ClickUpList.
.INPUTS
    System.UInt64. ListID via pipeline by property name.
.OUTPUTS
    None. This cmdlet does not return any output.
.NOTES
    See the link for information.
.LINK
    https://developer.clickup.com/reference/createtaskfromtemplate
#>

function New-ClickUpTaskFromTemplate {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('list_id', 'id')]
        [uint64]$ListID,
        [Parameter(Mandatory = $true)]
        [string]$TemplateID,
        [Parameter(Mandatory = $true)]
        [string]$Name
    )

    $Body = @{
        name = $Name
    }

    Write-Verbose 'Entering New-ClickUpTaskFromTemplate'
    try {
        Write-Verbose "Creating task '$Name' from template ID: $TemplateID in list ID: $ListID"
        $Null = Invoke-ClickUpAPIPost -Endpoint "list/$ListID/taskTemplate/$TemplateID" -Body $Body
        Write-Verbose 'Successfully created task from template'
    } catch {
        Write-Error "Error in New-ClickUpTaskFromTemplate: $($_.Exception.Message)"
        throw $_
    }
}