Public/Remove-PatCollection.ps1

function Remove-PatCollection {
    <#
    .SYNOPSIS
        Removes a collection from a Plex library.
 
    .DESCRIPTION
        Deletes a collection from the Plex library. Can identify the collection by ID or name.
        This action is irreversible - the collection and its item associations will be
        permanently deleted. The media items themselves are not affected.
 
    .PARAMETER CollectionId
        The unique identifier of the collection to remove.
 
    .PARAMETER CollectionName
        The name of the collection to remove. Supports tab completion.
        Requires LibraryName or LibraryId to be specified.
 
    .PARAMETER LibraryName
        The name of the library containing the collection. Supports tab completion.
        Required when using -CollectionName. This is the preferred way to specify a library.
 
    .PARAMETER LibraryId
        The library section ID containing the collection. Required when using -CollectionName.
        Use Get-PatLibrary to find library IDs.
 
    .PARAMETER ServerUri
        The base URI of the Plex server (e.g., http://plex.example.com:32400).
        If not specified, uses the default stored server.
 
    .PARAMETER PassThru
        If specified, returns the collection object that was removed.
 
    .EXAMPLE
        Remove-PatCollection -CollectionId 12345
 
        Removes the collection with ID 12345 after confirmation.
 
    .EXAMPLE
        Remove-PatCollection -CollectionName 'Old Collection' -LibraryName 'Movies' -Confirm:$false
 
        Removes the collection named 'Old Collection' from Movies library without confirmation.
 
    .EXAMPLE
        Get-PatCollection -LibraryName 'Movies' | Where-Object Title -like 'Temp*' | Remove-PatCollection
 
        Removes collections starting with 'Temp' from Movies library via pipeline.
 
    .EXAMPLE
        Remove-PatCollection -CollectionName 'Test Collection' -LibraryName 'Movies' -WhatIf
 
        Shows what would be removed without actually removing it.
 
    .EXAMPLE
        Remove-PatCollection -CollectionId 12345 -PassThru
 
        Removes the collection and returns the removed collection object for logging.
 
    .OUTPUTS
        PlexAutomationToolkit.Collection (when -PassThru is specified)
 
        Returns the removed collection object for auditing purposes.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'commandName',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'parameterName',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSReviewUnusedParameter',
        'commandAst',
        Justification = 'Standard ArgumentCompleter parameter, not always used'
    )]
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'ById')]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'ById', ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $CollectionId,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryName')]
        [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryId')]
        [ValidateNotNullOrEmpty()]
        [ArgumentCompleter({
            param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

            $quoteChar = ''
            $strippedWord = $wordToComplete
            if ($wordToComplete -match "^([`"'])(.*)$") {
                $quoteChar = $Matches[1]
                $strippedWord = $Matches[2]
            }

            $getParams = @{ ErrorAction = 'SilentlyContinue' }
            if ($fakeBoundParameters.ContainsKey('ServerUri')) {
                $getParams['ServerUri'] = $fakeBoundParameters['ServerUri']
            }
            if ($fakeBoundParameters.ContainsKey('LibraryName')) {
                $getParams['LibraryName'] = $fakeBoundParameters['LibraryName']
            }
            elseif ($fakeBoundParameters.ContainsKey('LibraryId')) {
                $getParams['LibraryId'] = $fakeBoundParameters['LibraryId']
            }
            else {
                return
            }

            $collections = Get-PatCollection @getParams

            foreach ($collection in $collections) {
                if ($collection.Title -ilike "$strippedWord*") {
                    $title = $collection.Title
                    if ($quoteChar) {
                        $text = "$quoteChar$title$quoteChar"
                    }
                    elseif ($title -match '\s') {
                        $text = "'$title'"
                    }
                    else {
                        $text = $title
                    }

                    [System.Management.Automation.CompletionResult]::new(
                        $text,
                        $title,
                        'ParameterValue',
                        $title
                    )
                }
            }
        })]
        [string]
        $CollectionName,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryName')]
        [ValidateNotNullOrEmpty()]
        [ArgumentCompleter({
            param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

            $quoteChar = ''
            $strippedWord = $wordToComplete
            if ($wordToComplete -match "^([`"'])(.*)$") {
                $quoteChar = $Matches[1]
                $strippedWord = $Matches[2]
            }

            $getParams = @{ ErrorAction = 'SilentlyContinue' }
            if ($fakeBoundParameters.ContainsKey('ServerUri')) {
                $getParams['ServerUri'] = $fakeBoundParameters['ServerUri']
            }

            $libraries = Get-PatLibrary @getParams

            foreach ($lib in $libraries.Directory) {
                if ($lib.title -ilike "$strippedWord*") {
                    $title = $lib.title
                    if ($quoteChar) {
                        $text = "$quoteChar$title$quoteChar"
                    }
                    elseif ($title -match '\s') {
                        $text = "'$title'"
                    }
                    else {
                        $text = $title
                    }

                    [System.Management.Automation.CompletionResult]::new(
                        $text,
                        $title,
                        'ParameterValue',
                        $title
                    )
                }
            }
        })]
        [string]
        $LibraryName,

        [Parameter(Mandatory = $true, ParameterSetName = 'ByNameWithLibraryId')]
        [ValidateRange(1, [int]::MaxValue)]
        [int]
        $LibraryId,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-PatServerUri -Uri $_ })]
        [string]
        $ServerUri,

        [Parameter(Mandatory = $false)]
        [switch]
        $PassThru
    )

    begin {
        try {
            $script:serverContext = Resolve-PatServerContext -ServerUri $ServerUri
        }
        catch {
            throw "Failed to resolve server: $($_.Exception.Message)"
        }

        $effectiveUri = $script:serverContext.Uri
        $headers = $script:serverContext.Headers
    }

    process {
        try {
            $resolvedId = $CollectionId
            $collectionInfo = $null

            if ($PSCmdlet.ParameterSetName -like 'ByName*') {
                # Only pass ServerUri if explicitly specified, otherwise let Get-PatCollection use default server with auth
                $getParams = @{
                    CollectionName = $CollectionName
                    ErrorAction    = 'Stop'
                }
                if ($script:serverContext.WasExplicitUri) { $getParams['ServerUri'] = $effectiveUri }
                if ($LibraryName) {
                    $getParams['LibraryName'] = $LibraryName
                }
                else {
                    $getParams['LibraryId'] = $LibraryId
                }

                $collection = Get-PatCollection @getParams
                if (-not $collection) {
                    $libDesc = if ($LibraryName) { "library '$LibraryName'" } else { "library $LibraryId" }
                    throw "No collection found with name '$CollectionName' in $libDesc"
                }
                $resolvedId = $collection.CollectionId
                $collectionInfo = $collection
            }
            else {
                try {
                    # Only pass ServerUri if explicitly specified, otherwise let Get-PatCollection use default server with auth
                    $getParams = @{ CollectionId = $CollectionId; ErrorAction = 'Stop' }
                    if ($script:serverContext.WasExplicitUri) { $getParams['ServerUri'] = $effectiveUri }
                    $collectionInfo = Get-PatCollection @getParams
                }
                catch {
                    Write-Verbose "Could not retrieve collection info for ID $CollectionId"
                }
            }

            $target = if ($collectionInfo) {
                "'$($collectionInfo.Title)' (ID: $resolvedId, $($collectionInfo.ItemCount) items)"
            }
            else {
                "Collection ID $resolvedId"
            }

            if ($PSCmdlet.ShouldProcess($target, 'Delete collection')) {
                $endpoint = "/library/collections/$resolvedId"
                $uri = Join-PatUri -BaseUri $effectiveUri -Endpoint $endpoint

                Write-Verbose "Deleting collection $resolvedId from $effectiveUri"

                $null = Invoke-PatApi -Uri $uri -Method 'DELETE' -Headers $headers -ErrorAction 'Stop'

                if ($PassThru -and $collectionInfo) {
                    $collectionInfo
                }
            }
        }
        catch {
            throw "Failed to remove collection: $($_.Exception.Message)"
        }
    }
}