Public/Schedules/Remove-JIMScheduleStep.ps1

# Copyright (c) Tetron Limited. All rights reserved.
# Licensed under the Tetron Commercial License. See LICENSE file in the project root.

function Remove-JIMScheduleStep {
    <#
    .SYNOPSIS
        Removes a step from a Schedule in JIM.
 
    .DESCRIPTION
        Removes a step from an existing Schedule by its index position.
        Step indices are 0-based.
 
    .PARAMETER ScheduleId
        The unique identifier (GUID) of the Schedule to remove the step from.
 
    .PARAMETER StepIndex
        The position of the step to remove, counting from 0.
 
    .PARAMETER ChangeReason
        An optional reason for the change, recorded against this Schedule's change history.
 
    .PARAMETER Force
        Suppresses the confirmation prompt.
 
    .PARAMETER PassThru
        Returns the updated Schedule.
 
    .OUTPUTS
        With -PassThru, the updated Schedule in full; otherwise nothing. The remaining steps are renumbered, and
        each keeps its Id and its failure setting.
 
    .EXAMPLE
        Remove-JIMScheduleStep -ScheduleId "12345678-..." -StepIndex 0
 
        Removes the first step from the schedule.
 
    .EXAMPLE
        Remove-JIMScheduleStep -ScheduleId "12345678-..." -StepIndex 2 -Force -PassThru
 
        Removes the third step without confirmation and returns the updated schedule.
 
    .LINK
        Get-JIMSchedule
        Add-JIMScheduleStep
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType('JIM.ScheduleDetailDto')]
    param(
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [Alias('Id')]
        [guid]$ScheduleId,

        [Parameter(Mandatory)]
        [ValidateRange(0, [int]::MaxValue)]
        [int]$StepIndex,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ChangeReason,

        [switch]$Force,

        [switch]$PassThru
    )

    process {
        # Check connection first
        if (-not $script:JIMConnection) {
            Write-Error "You are not connected to JIM. Run Connect-JIM -Url <your JIM URL> to authenticate, then try again."
            return
        }

        if (Confirm-JIMAction -Cmdlet $PSCmdlet -Target "Step $StepIndex from Schedule $ScheduleId" -Action "Remove Schedule Step" -Force:$Force) {
            Write-Verbose "Removing step $StepIndex from Schedule: $ScheduleId"

            try {
                # Get existing schedule with steps
                $schedule = Invoke-JIMApi -Endpoint "/api/v1/schedules/$ScheduleId"

                if (-not $schedule) {
                    Write-Error "Schedule not found: $ScheduleId"
                    return
                }

                $existingSteps = if ($schedule.steps) { @($schedule.steps) } else { @() }

                # Find the step(s) to remove by stepIndex
                $stepsToKeep = $existingSteps | Where-Object { $_.stepIndex -ne $StepIndex }

                if ($stepsToKeep.Count -eq $existingSteps.Count) {
                    Write-Warning "No step found at index $StepIndex"
                    return
                }

                # Renumber remaining steps to be sequential
                $renumberedSteps = @()
                $currentIndex = 0
                $lastOriginalIndex = -1

                foreach ($step in ($stepsToKeep | Sort-Object stepIndex)) {
                    if ($step.stepIndex -ne $lastOriginalIndex) {
                        $currentIndex = $renumberedSteps.Count
                        $lastOriginalIndex = $step.stepIndex
                    }

                    # Each remaining step goes back with its id and failure setting (ConvertTo-JIMScheduleStepRequest),
                    # so the API updates it in place rather than deleting and recreating it; only its index changes.
                    $renumberedSteps += ConvertTo-JIMScheduleStepRequest -Step $step -StepIndex $currentIndex
                }

                # Build update body
                $body = @{
                    name = $schedule.name
                    description = $schedule.description
                    triggerType = $schedule.triggerType
                    patternType = $schedule.patternType
                    isEnabled = $schedule.isEnabled
                    daysOfWeek = $schedule.daysOfWeek
                    runTimes = $schedule.runTimes
                    intervalValue = $schedule.intervalValue
                    intervalUnit = $schedule.intervalUnit
                    intervalWindowStart = $schedule.intervalWindowStart
                    intervalWindowEnd = $schedule.intervalWindowEnd
                    cronExpression = $schedule.cronExpression
                    steps = $renumberedSteps
                }

                if ($PSBoundParameters.ContainsKey('ChangeReason')) {
                    $body.changeReason = $ChangeReason
                }

                $result = Invoke-JIMApi -Endpoint "/api/v1/schedules/$ScheduleId" -Method 'PUT' -Body $body

                Write-Verbose "Removed step from Schedule: $ScheduleId"

                if ($PassThru) {
                    Invoke-JIMApi -Endpoint "/api/v1/schedules/$ScheduleId"
                }
            }
            catch {
                Write-Error "Failed to remove Schedule step: $_"
            }
        }
    }
}