lib/Events.ps1

function Get-TMEvent {
    <#
    .SYNOPSIS
    Gets one or more Events from TransitionManager
 
    .DESCRIPTION
    Queries TransitionManager for a list of Events and optionally sorts them by name or id
 
    .PARAMETER Name
    The name of one or more Events to retrieve
 
    .PARAMETER Id
    The id of one or more Events to retrieve
 
    .PARAMETER TMSession
    The name of the TM Session to use when retrieving the Events
 
    .PARAMETER ProjectId
    The id of the Project holdeng the Event(s)
 
    .PARAMETER ResetIDs
    Switch indicating that the IDs of the returned Events should be reset to 0/null
 
    .EXAMPLE
    $WaveFourEvent = Get-TMEvent -Name 'Wave 4'
 
    .EXAMPLE
    # Backup all Events to a json file
    Get-TMEvent -ResetIDs | ConvertTo-Json | Out-File 'C:\Temp\Events.json' -Force
 
    .EXAMPLE
    # Copy Events from one Project to another
    Get-TMEvent -ProjectId 123 | New-TMEvent -ProjectId 456
 
    .OUTPUTS
    One or more TMEvent objects
    #>


    [OutputType([TMEvent])]
    [CmdletBinding(DefaultParameterSetName = 'ByName')]
    param(
        [Parameter(Mandatory = $false,
            ParameterSetName = 'ByName',
            ValueFromPipelineByPropertyName = $true)]
        [String[]]$Name,

        [Parameter(Mandatory = $false,
            ParameterSetName = 'ById',
            ValueFromPipelineByPropertyName = $true)]
        [Int32[]]$Id,

        [Parameter(Mandatory = $false)]
        [Object]$TMSession = 'Default',

        [Parameter(Mandatory = $false)]
        [Int32]$ProjectId,

        [Parameter(Mandatory = $false)]
        [Switch]$ResetIDs,

        [Parameter(Mandatory = $false)]
        [Switch]$ResolveReferences
    )

    begin {
        # Get Session Configuration
        if ($TMSession -is [String]) {
            $TMSession = $global:TMSessions[$TMSession]
            if (-not $TMSession) {
                throw "TMSession '$TMSession' not found. Check name or provide a [TMSession] object."
            }
        }

        if (-not ($TMSession -is [TMSession])) {
            throw "The value for the TMSession parameter must be of type [String] or [TMSession]"
        }

        # Assume the Project ID if it wasn't provided
        if (-not $ProjectId) {
            $ProjectId = $TMSession.UserContext.Project.Id
        }
    }

    process {
        Write-Verbose "Forming web request"
        $WebRequestSplat = @{
            Method               = 'GET'
            Uri                  = "https://$($TMSession.TMServer)/tdstm/api/event"
            WebSession           = $TMSession.TMRestSession
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
            Body                 = (@{ project = $ProjectId } | ConvertTo-Json -Compress)
        }

        try {
            Write-Debug "Web Request Parameters:"
            Write-Debug ($WebRequestSplat | ConvertTo-Json -Depth 10)
            Write-Verbose "Invoking web request"
            $Response = Invoke-WebRequest @WebRequestSplat
            Write-Debug "Response status code: $($Response.StatusCode)"
            Write-Debug "Response Content: $($Response.Content | ConvertTo-Json)"
        } catch {
            throw $_
        }

        if ($Response.StatusCode -notin 200, 204) {
            throw "The response status code $($Response.StatusCode) does not indicate success"
        }

        # Determine how to filter the results
        $Filter = if ($Name) {
             [ScriptBlock]::Create("`$_.Name -in '$($Name -join "', '")'")
        } elseif ($Id) {
            [ScriptBlock]::Create("`$_.Id -in $($Id -join ', ')")
        } else {
            [ScriptBlock]::Create("`$_.Id -gt 0")
        }

        # Convert the results, filter and sort them
        $TMEvents = $Response.Content | ConvertFrom-Json -Depth 5 | Where-Object -FilterScript $Filter |
            ForEach-Object {
                $TMEvent = [TMEvent]::new($_)
                if ($ResetIDs) {
                    $TMEvent.Id = $null
                }
                if ($ResolveReferences) {
                    $TMEvent.ResolveEventGroups($TMSession.Name)
                }
                $TMEvent
            } | Sort-Object -Property 'Name'

        # Return appropriate results
        $TMEvents
    }
}


function New-TMEvent {
    <#
    .SYNOPSIS
    Creates a new Event in TransitionManager
 
    .DESCRIPTION
    This function creates a new Event in TransitionManager and optionally sets
    the associated Tags and Bundles
 
    .PARAMETER InputObject
    An object representing the Event to create.
 
    .PARAMETER Name
    The name of the Event
 
    .PARAMETER Description
    The description of the Event
 
    .PARAMETER Tags
    The Tags to associate with the Event
 
    .PARAMETER Bundles
    The Bundles to assign to the Event
 
    .PARAMETER Status
    The Runbook Status of the Event
 
    .PARAMETER StartTime
    The Estimated Start Time of the Event
 
    .PARAMETER CompletionTime
    The Estimated Completion Time of the Event
 
    .PARAMETER BypassActions
    Switch indicating that the Event should be in Action Bypass mode
 
    .PARAMETER TMSession
    The TMSession to use when creating the Event
 
    .PARAMETER ProjectId
    The ID of the Project in which the Event will be created
 
    .PARAMETER Passthru
    Switch indicating that the created event should be returned by the function
 
    .PARAMETER Api
    Should the REST API be used?
 
    .EXAMPLE
    New-TMEvent -InputObject @{name = 'Event name'; description = 'Event Description'}
 
    .EXAMPLE
    [TMEvent]::new('First Event') | New-TMEvent -Passthru
 
    .EXAMPLE
    # Get an already existing Event as a starting point
    $TMEvent = Get-TMEvent -Name 'Starting Event'
 
    # Edit different properties of the original Event
    $TMEvent.Name = 'Cloned Event'
    $TMEvent.Description = 'This is a cloned Event'
    $TMEvent.RunbookStatus = 'Draft'
 
    # Add extra Tags and Bundles to the Event to be created
    $TMEvent.Tags += [TMReference]::new('HIPPA')
    $TMEvent.Bundles += [TMReference]::new('Wave 1')
 
    # Change the completion time to 15 days from now
    $TMEvent.EstCompletionTime = $TMEvent.EstCompletionTime.AddDays(15)
 
    # Create the new Event and return the result
    $NewEvent = $TMEvent | New-TMEvent -Passthru
 
    .OUTPUTS
    If the Passthru switch was passed, a TMEvent object representing the created Event
    #>

    [CmdletBinding(DefaultParameterSetName = 'ByProperties')]
    [OutputType([TMEvent])]
    param(
        [Parameter(Mandatory = $true,
            ParameterSetName = 'ByObject')]
        [Object]$InputObject,

        [Parameter(Mandatory = $true,
            Position = 0,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [String]$Name,

        [Parameter(Mandatory = $false,
            Position = 1,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [String]$Description,

        [Parameter(Mandatory = $false,
            Position = 2,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Object[]]$Tags,

        [Parameter(Mandatory = $false,
            Position = 3,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Object[]]$Bundles,

        [Parameter(Mandatory = $false,
            Position = 4,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Alias('RunbookStatus')]
        [Nullable[TMRunbookStatus]]$Status,

        [Parameter(Mandatory = $false,
            Position = 4,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Alias('EstStartTime')]
        [Nullable[DateTime]]$StartTime,

        [Parameter(Mandatory = $false,
            Position = 4,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Alias('EstCompletionTime')]
        [Nullable[DateTime]]$CompletionTime,

        [Parameter(Mandatory = $false,
            Position = 3,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ByProperties')]
        [Alias('ApiActionBypass')]
        [Switch]$BypassActions,

        [Parameter(Mandatory = $false)]
        [Object]$TMSession = 'Default',

        [Parameter(Mandatory = $false)]
        [Int32]$ProjectId,

        [Parameter(Mandatory = $false)]
        [Switch]$Passthru,

        [Parameter(Mandatory = $false)]
        [Boolean]$Api = $true
    )

    begin {
        # Get Session Configuration
        if ($TMSession -is [String]) {
            $TMSession = $global:TMSessions[$TMSession]
            if (-not $TMSession) {
                throw "TMSession '$TMSession' not found. Check name or provide a [TMSession] object."
            }
        }

        if (-not ($TMSession -is [TMSession])) {
            throw "The value for the TMSession parameter must be of type [String] or [TMSession]"
        }

        # Assume the Project ID if it wasn't provided
        if (-not $ProjectId) {
            $ProjectId = $TMSession.UserContext.Project.Id
        } elseif ($TMSession.UserContext.Project.Id -ne $ProjectId) {
            Write-Verbose "Switching project"
            Enter-TMProject -ProjectID $ProjectId -TMSession $TMSession.Name
        }

        # Update the Content Type to JSON
        Set-TMHeaderContentType -ContentType 'JSON' -TMSession $TMSession.Name
    }

    process {
        Write-Verbose "ParameterSet: $($PSCmdlet.ParameterSetName)"

        if ($PSCmdlet.ParameterSetName -eq 'ByProperties') {
            # Create a case insensitive hashtable that will be passed to the constructor of TMEvent
            $InputObject = [Hashtable]::new($PSCmdlet.MyInvocation.BoundParameters, [System.StringComparer]::OrdinalIgnoreCase)

            # Make sure Bundles are formatted properly as TMReference objects and add them to the InputObject
            $InputObject.Bundles = [TMReference]::Resolve($Bundles, [TMReferenceType]::Bundle, $TMSession.Name)

            # Make sure Tags are formatted properly as TMReference objects and add them to the InputObject
            $InputObject.Tags = [TMReference]::Resolve($Tags, [TMReferenceType]::Tag, $TMSession.Name)
        }

        # Create the initial TMEvent object
        $TMEvent = [TMEvent]::new($InputObject)

        Write-Debug "Initial TMEvent:"
        Write-Debug ($TMEvent | ConvertTo-Json -Depth 3)

        # Check for an existing Event
        Write-Verbose "Checking for existing Event"
        $CheckEvent = Get-TMEvent -Name $Name -TMSession $TMSession
        if ($CheckEvent) {
            if ($Passthru) { $CheckEvent }
            return
        }

        # Create a Request Splat
        Write-Verbose "Forming web request"
        $WebRequestSplat = @{
            Uri                  = "https://$($TMSession.TMServer)/tdstm/$($Api ? 'api/event' : 'ws/moveEvent/save/null')"
            Method               = 'POST'
            WebSession           = $Api ? $TMSession.TMRestSession : $TMSession.TMWebSession
            Body                 = $TMEvent.GetWebRequestBody(($Api ? $ProjectId : $null))
            SkipCertificateCheck = $TMSession.AllowInsecureSSL
        }

        try {
            Write-Debug "Web Request Parameters:"
            Write-Debug ($WebRequestSplat | ConvertTo-Json -Depth 3)
            Write-Verbose "Invoking web request"
            $Response = Invoke-WebRequest @WebRequestSplat
            Write-Debug "Response status code: $($Response.StatusCode)"
            Write-Debug "Response Content: $($Response.Content | ConvertTo-Json)"
        } catch {
            throw $_
        }

        if ($Response.StatusCode -notin 200, 204) {
            throw "The response status code $($Response.StatusCode) does not indicate success"
        }

        # Parse the response content
        $Result = $Response.Content | ConvertFrom-Json -Depth 5
        if (-not $Api -and $Result.status -ne 'success') {
            throw "Could not create Event: $($Result.errors -join ', ')"
        } elseif ($Passthru) {
            if ($Api) {
                [TMEvent]::new($Result)
            } else {
                $NewEvent = [TMEvent]::new($Result.data)
                $NewEvent.ResolveEventGroups($TMSession.Name)
                $NewEvent
            }
        }
    }
}