pscodebeamer.psm1

class CBQL : System.Management.Automation.IValidateSetValuesGenerator {
    [String[]] GetValidValues() {
        $serverListWithLogPath = Join-Path -Path $env:appDATA -ChildPath \pscodebeamer\config.json
        $request = ([System.IO.File]::ReadAllText($serverListWithLogPath) | ConvertFrom-Json).CBQLQuery
        return $request
    }
}

function New-CBSession {
    <#
    .SYNOPSIS
        Creates a new session variable with the specified server using provided credentials which can be used acrossed other PSCodebeamer Fuctions
 
    .DESCRIPTION
        The `New-CBSession` function creates a Variable necessary for interacting with the specified server. By using the credentials provided (or prompting for them if not specified), it constructs an authorization header and other session-specific information required for subsequent requests to the server. Common use cases for this function include preparing session details for REST API requests or for applications requiring user authentication.
 
    .NOTES
        - This function is designed for environments where Basic Authentication over HTTPS is supported. Ensure your server is configured to handle authentication securely.
        - This function may not work on non-Windows environments due to differences in handling credentials and HTTP headers.
        - The function assumes the server requires JSON content-type for requests
 
    .EXAMPLE
        Value of -Server Parameter: if your company uses 'https://yourcompanydomain/cb/api/v3/users/groups
 
        PS> $session = New-CBSession -Server "yourcompanydomain" -Credential (Get-Credential)
 
        Result: Creates a session object with headers including Basic Authorization for use in API requests.
 
    .EXAMPLE
        PS> $session = New-CBSession -Server "yourcompanydomain"
 
        Explanation: Prompts for credentials if not provided and returns the session object configured for interactions with the specified server.
 
    .OUTPUTS
    pscustomobject
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$Server,

        [Parameter(ValueFromPipeline)]
        [pscredential]$Credential
    )
    $cred = if ($Credential) { $Credential } else { Get-Credential -Message "Please Enter Credentials for $Server" }

    $pass = $cred.GetNetworkCredential().Password
    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $cred.UserName, $pass)))

    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add('Authorization', ('Basic {0}' -f $base64AuthInfo))
    $headers.Add('content-type', 'application/json')

    try {
        $uri = "https://{0}/cb/api/v3/projects" -f $server

        Write-Debug "uri: $uri"

        Invoke-RestMethod -Uri $uri -Method Get -Headers $headers -ErrorAction Stop -SessionVariable codebeamerSession | Out-Null

        $codebeamerSession | Add-Member -NotePropertyName Server -NotePropertyValue $Server

        Write-Output -InputObject $codebeamerSession
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.." {
                Write-Error "Test Connection to Server failed. Please recheck your server parameter value: $Server"
                ; break
            }
            "*Not authenticated*" {
                Write-Error "Test Connection to Server: $server failed. User or Password is incorrect."
                ; break
            }
            default { Write-Error $fullError }
        }
    }
}
function Get-CBProject {
    <#
    .SYNOPSIS
    Retrieves project details from a CodeBeamer server, including optional Project details and tracker list if a ProjectID is specified.
 
    .DESCRIPTION
    The Get-CBProject function is designed to interact with a CodeBeamer server's API to fetch information about projects. You can specify a particular project by providing its ProjectID to retrieve detailed information about that specific project, including its trackers. If no ProjectID is supplied, the function returns a list of all available projects.
 
    .PARAMETER ProjectID
    An optional parameter that specifies the identifier for a particular project you want to fetch from the CB server. If omitted, the function retrieves all available projects.
 
    .PARAMETER CBSession
    A mandatory parameter, which is an alias `cbs`, representing the session object required for connection to the CB server. This must include server information and necessary headers for authentication.
 
    .INPUTS
    None.
 
    .OUTPUTS
    PSCustomObject. Returns the project details. If a ProjectID is specified, the output also includes trackers associated with the project.
 
    .EXAMPLE
    PS> Get-CBProject -CBSession $session
 
    .EXAMPLE
    PS> Get-CBProject -ProjectID '12345' -CBSession $session
 
    .NOTES
    Ensure that the CBSession object is valid, and the server and headers are correctly populated to authenticate against the CB API.
    This function uses Invoke-RestMethod, so make sure your environment is configured to allow outbound HTTP requests.
 
    .LINK
    More information about API Endpoint:
    https://codebeamer.com/cb/wiki/11375774#section-Getting+the+list+of+available+projects
#>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline, Position = 0)]
        [string]$ProjectID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    process {
        try {
            switch ($ProjectID) {
                { -not ([string]::IsNullOrEmpty($_)) } {
                    $uri = "https://{0}/cb/api/v3/projects/{1}" -f $CBSession.Server, $_
                    $uriProjectTrakcers = "https://{0}/cb/api/v3/projects/{1}/trackers" -f $CBSession.Server, $_

                    Write-Debug $uri
                    Write-Debug $uriProjectTrakcers

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    $projectTracker = Invoke-RestMethod -Uri $uriProjectTrakcers -Method Get -Headers $CBSession.headers -ErrorAction Stop

                    $result | Add-Member -NotePropertyName Trackers -NotePropertyValue $projectTracker
                    Write-Output $result
                    ; break
                }
                { [string]::IsNullOrEmpty($_) } {
                    $uri = "https://{0}/cb/api/v3/projects" -f $CBSession.Server

                    Write-Debug $uri

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    Write-Output $result
                    ; break
                }
            }
        }
        catch {
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Project is not found*" { Write-Error "Project with ID: $ProjectID does not exist on Server: $($CBSession.Server). Please Recheck Project ID" }
                default { Write-Error $_ }
            }
        }
    }
}
function Get-CBProjectTrackerList {
    <#
    .SYNOPSIS
    Retrieves the list of trackers for a specified project from a CB server.
 
    .DESCRIPTION
    The Get-CBProjectTrackerList function interacts with the CB server's API to fetch all trackers associated with a specific project. You must specify the ProjectID of the project whose trackers you wish to retrieve.
 
    .PARAMETER ProjectID
    The identifier for the specific project from which to retrieve trackers. This is a mandatory parameter.
 
    .PARAMETER CBSession
    A mandatory parameter that serves as an alias `cbs`, representing the session object required for connection to the CB server. This must include server information and necessary headers for authentication.
 
    .OUTPUTS
    System.Array. Returns a list of trackers associated with the specified project.
 
    .EXAMPLE
    Example 1: Retrieve trackers for a specific project
 
    PS> Get-CBProjectTrackerList -ProjectID '12345' -CBSession $session
 
        id name type
        -- ---- ----
    3346 Change Requests Tracker TrackerReference
    3348 Change Requests TrackerReference
    3348 Release TrackerReference
    3349 Releases TrackerReference
    3354 Receive TrackerReference
 
 
    .NOTES
    Ensure that the CBSession object is valid, and the server and headers are correctly populated to authenticate against the CB API.
    This function uses Invoke-RestMethod, so make sure your environment is configured to allow outbound HTTP requests.
 
    .LINK
    More information about API Endpoint:
    https://codebeamer.com/cb/wiki/11375774#section-Getting+the+list+of+trackers+in+a+specific+project
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [string]$ProjectID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/projects/{1}/trackers" -f $CBSession.Server, $ProjectID

            Write-Debug $uri

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
            Write-Output $result
        }
        catch {
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Project is not found*" { Write-Error "Project with ID: $ProjectID does not exist on Server: $($CBSession.Server). Please Recheck Project ID" }
                default { Write-Error $_ }
            }
        }
    }
}
function Get-CBProjectMemberList {
    <#
    .SYNOPSIS
    Retrieves the list of members for a specified project from a CodeBeamer server, with pagination options.
 
    .DESCRIPTION
    The Get-CBProjectMemberList function interacts with the CodeBeamer server's API to fetch all members associated with a specific project. It provides options for pagination through the Page and Size parameters.
 
    .PARAMETER ProjectID
    The identifier for the specific project from which to retrieve members. This is a mandatory parameter.
 
    .PARAMETER CBSession
    A mandatory parameter, which is an alias `cbs`, representing the session object required for connection to the CB server. This must include server information and necessary headers for authentication.
 
    .PARAMETER Page
    Optional parameter that sets the page number for pagination. Defaults to page 1.
 
    .PARAMETER Size
    Optional parameter that sets the size of the page for pagination. Defaults to a maximum of 500 members per page and accepts values between 1 and 500.
 
    .INPUTS
    None.
 
    .OUTPUTS
    PSCustomObject. Returns a list of members associated with the specified project.
 
    .EXAMPLE
    PS> Get-CBProjectMemberList -ProjectID '12345' -CBSession $session
 
    .EXAMPLE
    PS> Get-CBProjectMemberList -ProjectID '12345' -CBSession $session -InformationAction Continue
 
                Command Information:
                "Page: 1, Page Size: 500, Total: 18, Project ID: 3"
 
        id name type
        -- ---- ----
        1 user1 UserReference
        6 user2 UserReference
        7 user3 UserReference
        8 user4 UserReference
        9 user5 UserReference
 
    .NOTES
    Ensure that the CBSession object is valid, and the server and headers are correctly populated to authenticate against the CB API.
    This function uses Invoke-RestMethod, so make sure your environment is configured to allow outbound HTTP requests.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [int]$ProjectID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession,

        [Parameter()]
        [int]$Page = 1,

        [Parameter()]
        [ValidateRange(1, 500)]
        [int]$Size = 500
    )
    process {
        try {

            $uri = "https://{0}/cb/api/v3/projects/{1}/members?page={2}&pageSize={3}" -f $CBSession.Server, $ProjectID, $Page, $Size

            Write-Debug "Uri: $uri"

            $result = Invoke-RestMethod -uri $uri -Headers $CBSession.headers
            Write-Output $result.members

            $messageData = @"
            Command Information:
            "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), Project ID: $ProjectID"
 
"@

            Write-Information -MessageData $messageData
        }
        catch {
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Project is not found*" { Write-Error "Project with ID: $ProjectID does not exist on Server: $($CBSession.Server). Please Recheck Project ID" }
                default { Write-Error $_ }
            }
        }
    }
}
function Get-CBTrackerOutline {
    <#
    .SYNOPSIS
    Retrieves the outline (hierarchical structure) of items in a tracker from the Codebeamer server.
 
    .DESCRIPTION
    The `Get-CBTrackerOutline` function fetches the outline of items for a specified tracker. You can filter by parent item, depth. This is useful for visualizing or processing the hierarchical structure of tracker items.
 
    .PARAMETER TrackerID
    The ID of the tracker whose outline you want to retrieve. This parameter is mandatory.
 
    .PARAMETER ParentItemID
    (Optional) The ID of the parent item to start the outline from. If not specified, the outline starts from the root.
 
    .PARAMETER DepthFilter
    (Optional) Limits the depth of the outline returned.
 
    .PARAMETER CBSession
    The session object containing server URL and headers. This parameter is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
    Get-CBTrackerOutline -TrackerID 12345 -CBSession $cbSession
 
    Retrieves the full outline for tracker ID 12345.
 
    .EXAMPLE
    Get-CBTrackerOutline -TrackerID 12345 -ParentItemID 67890 -DepthFilter 2 -CBSession $cbSession
 
    Retrieves the outline for tracker ID 12345, starting from parent item 67890, limited to 2 levels deep.
 
    .NOTES
    - Returns the outline structure as provided by the Codebeamer REST API.
    - Handles errors for invalid tracker IDs or inaccessible items.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$TrackerID,

        [Parameter(Position = 1)]
        [int]$ParentItemID,

        [Parameter()]
        [int]$DepthFilter,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {

        $uri = switch ($true) {
            { $PSBoundParameters.ContainsKey('ParentItemID') -and (-not $PSBoundParameters.ContainsKey('DepthFilter')) } {
                "https://{0}/cb/api/v3/trackers/{1}/outline?parentItemId={2}" -f $CBSession.Server, $TrackerID, $ParentItemID
            }
            { $PSBoundParameters.ContainsKey('ParentItemID') -and $PSBoundParameters.ContainsKey('DepthFilter') } {

                "https://{0}/cb/api/v3/trackers/{1}/outline?parentItemId={2}&resultDepthFilter={3}" -f $CBSession.Server, $TrackerID, $ParentItemID, $DepthFilter
            }
            { $PSBoundParameters.ContainsKey('TrackerID') -and $PSBoundParameters.ContainsKey('DepthFilter') -and (-not $PSBoundParameters.ContainsKey('ParentItemID')) } {

                "https://{0}/cb/api/v3/trackers/{1}/outline?resultDepthFilter={2}" -f $CBSession.Server, $TrackerID, $DepthFilter
            }
            Default {
                "https://{0}/cb/api/v3/trackers/{1}/outline" -f $CBSession.Server, $TrackerID
            }
        }

        Write-Debug "uri: $uri"

        $result = Invoke-RestMethod -uri $uri -Headers $CBSession.headers -Method Get
        Write-Output $result
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "*Tracker is not found.*"  {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            "*Not accessible tracker item ids*"  {
                $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                Write-Error -Message $message
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBTrackerChild {
    <#
    .SYNOPSIS
    Retrieves child items for a specified tracker in a Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBTrackerChild` function fetches items associated with a specific tracker ID in the Codebeamer Server.
    Results are paged, allowing control over the amount of data returned at once.
 
    .PARAMETER TrackerID
    The unique identifier of the tracker whose child items are to be retrieved.
    This parameter is mandatory and accepts input from the pipeline.
 
    .PARAMETER Page
    Specifies the page number to retrieve from the query results.
    Defaults to the first page (i.e., 1). This parameter is optional.
 
    .PARAMETER Size
    Determines the number of items per page to retrieve.
    The default value is 500, accommodating efficient data retrieval.
    This parameter is optional.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session enables authentication and interaction with the CB API.
    It is mandatory and accessible via the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBTrackerChild -TrackerID 12344 -CBSession $cbSession
 
    This example fetches child items linked to the specified tracker ID on the server Codebeamer Server, starting from the first page with a default page size.
 
    .NOTES
    - The function outputs child item references retrieved from the tracker.
    - Error handling incorporates specific checks for tracker availability, enhancing reliability in usage.
    - Information messages provide details about the request's results and context.
 
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [string]$TrackerID,

        [Parameter()]
        [int]$Page = 1,

        [Parameter()]
        [int]$Size = 500,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession

    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/trackers/{1}/items?page={2}&pageSize={3}" -f $CBSession.Server, $TrackerID, $Page, $Size
            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers

            $result.itemRefs

            $messageData = @"
            Command Information:
            "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), Tricker Item ID: $($TrackerID)"
"@

            Write-Information -MessageData $messageData
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Tracker is not found.*" } {
                    Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBItem {
    <#
    .SYNOPSIS
    Retrieves configuration item details from a specified server using various parameter sets.
 
    .DESCRIPTION
    The `Get-CBItem` function fetches details of a configuration item from Codebeamer using different parameter sets: DefaultSet, BaseLine, or Version. Each set retrieves data based on distinct criteria using corresponding API calls.
 
    .PARAMETER ItemID
    Specifies the unique identifier of the item to be fetched. This parameter is required and must be provided from the pipeline.
 
    .PARAMETER CBSession
    Specifies the session object containing details like server URL and headers. This parameter is mandatory for all parameter sets.
 
    .PARAMETER BaselineID
    Specifies the baseline identifier for fetching item details in the BaseLine parameter set. This parameter is optional and only used in the BaseLine set.
 
    .PARAMETER Version
    Specifies the version of the item to retrieve in the Version parameter set. This parameter is optional and only used in the Version set.
 
    .PARAMETERSET DefaultSet
    Fetches details of the item using its ItemID without any additional filter criteria.
 
    .PARAMETERSET BaseLine
    Fetches item details using ItemID and filters based on the provided BaselineID.
 
    .PARAMETERSET Version
    Fetches item information using ItemID and filters based on the specified Version.
 
    .EXAMPLE
    Get-CBItem -ItemID "12345" -CBSession $session
 
    Fetches details of item with ID 12345 using the DefaultSet parameter set.
 
    .EXAMPLE
    Get-CBItem -ItemID "12345" -CBSession $session -BaselineID 123
 
    Retrieves details of item 12345 using the BaseLine set with BaselineID `123`.
 
    .EXAMPLE
    Get-CBItem -ItemID "12345" -CBSession $session -Version 1
 
    Fetches the version-specific details of item 12345 using Version set with version `1`.
 
    .EXAMPLE
    123,343,456 | Get-CBItem -CBSession $session -Version 1 | Select-Object id,typename,status
 
    id typeName status
    -- -------- ------
    123 Requirement @{id=1; name=New; type=ChoiceOptionReference}
    343 Requirement @{id=1; name=In Progress; type=ChoiceOptionReference}
    456 Requirement @{id=1; name=New; type=ChoiceOptionReference}
 
    .NOTES
    - Ensure that `$CBSession` contains correct server and headers data.
    - Debug messages indicate the process flow and constructed URIs.
    - Errors are handled to provide specific feedback based on the error conditions encountered.
#>

    [CmdletBinding(DefaultParameterSetName = 'DefaultSet')]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'DefaultSet')]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'BaseLine')]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'Version')]
        [int]$ItemID,

        [Parameter(Mandatory, ParameterSetName = 'DefaultSet')]
        [Parameter(Mandatory, ParameterSetName = 'BaseLine')]
        [Parameter(Mandatory, ParameterSetName = 'Version')]
        [Alias("cbs")]
        [pscustomobject]$CBSession,

        [Parameter(ParameterSetName = 'BaseLine')]
        [int]$BaselineID,

        [Parameter(ParameterSetName = 'Version')]
        [int]$Version
    )
    process {
        foreach ($header in $CBSession.headers.getEnumerator() ) {
            Write-Debug "Key: $($header.Key) Value: $($header.Value)"
        }
        try {
            switch ($PSCmdlet.ParameterSetName) {
                "DefaultSet" {
                    $uri = "https://{0}/cb/api/v3/items/{1}" -f $CBSession.Server, $ItemID

                    Write-Debug "uri: $uri"

                    Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    ; break
                }
                "BaseLine" {
                    $uriBaseline = "https://{0}/cb/api/v3/items/{1}?baselineId={2}" -f $CBSession.Server, $ItemID, $BaselineID

                    Write-Debug "uri: $uriBaseline"

                    Invoke-RestMethod -Uri $uriBaseline -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    ; break
                }
                "Version" {
                    $uriVersion = "https://{0}/cb/api/v3/items/{1}?version={2}" -f $CBSession.Server, $ItemID, $Version

                    Write-Debug "uri: $uriVersion"

                    Invoke-RestMethod -Uri $uriVersion -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    ; break
                }
            }
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Tracker item is not found.*" -and $PSCmdlet.ParameterSetName -eq "Version" } {
                    Write-Error "Version: $Version of Item $itemID most likely doesn't exist. Please recheck Version."
                }
                { $_ -like "*BaseLine*" } {
                    Write-Error "BaseLineID: $BaselineID of Item $itemID most likely doesn't exist. Please recheck BaseLine."
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBTrackerTransition {
    <#
    .SYNOPSIS
    Retrieves the transition details of a specified tracker from a CB server.
 
    .DESCRIPTION
    The Get-CBTrackerTransition function is designed to interact with a CB server's API to fetch transition information associated with a specific tracker. The transitions provide details on the status changes within the tracker.
 
    .PARAMETER TrackerID
    The identifier for the specific tracker whose transition details are to be retrieved. This is a mandatory parameter.
 
    .PARAMETER CBSession
    A mandatory parameter, which is an alias `cbs`, representing the session object required for connection to the CB server. This must include server information and necessary headers for authentication.
 
    .INPUTS
    None.
 
    .OUTPUTS
    PSCustomObject. Returns transition details associated with the specified tracker.
 
    .EXAMPLE
    Example: Retrieve transition details for a specific tracker
 
    Get-CBTrackerTransition -TrackerID 67890 -CBSession $session
 
    .NOTES
    Ensure that the CBSession object is valid, and the server and headers are correctly populated to authenticate against the CB API.
    This function uses Invoke-RestMethod, so make sure your environment is configured to allow outbound HTTP requests.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [int]$TrackerID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/trackers/{1}/transitions" -f $CBSession.Server, $TrackerID

            Write-Debug "uri: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -errorAction Stop
            Write-Output $result
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Tracker is not found*" } {
                    Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CbTrackerSchema {
    <#
    .SYNOPSIS
    Retrieves the schema for a specified tracker in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CbTrackerSchema` function is designed to obtain the schema associated with a particular tracker ID in the Codebeamer Server.
    The schema provides structural details of the tracker, including its fields and configurations.
 
    .PARAMETER TrackerID
    Represents the unique identifier of the tracker for which the schema is to be retrieved.
    This parameter is mandatory and accepts input directly from the pipeline.
 
    .PARAMETER CBSession
    A mandatory parameter that specifies the CB Session object, containing connection details such as server URL and headers.
    This object facilitates authentication and API communication with the server.
    It can be accessed using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CbTrackerSchema -TrackerID $trackerID -CBSession $cbSession
 
    id : 0
    name : ID
    type : IntegerField
    hidden : False
    valueModel : IntegerFieldValue
    mandatoryInStatuses : {}
    sharedFields : {}
    legacyRestName : id
    trackerItemField : id
 
    id : 1
    name : Tracker
    type : ReferenceField
    hidden : False
    valueModel : NotSupportedFieldValue
    mandatoryInStatuses : {}
    sharedFields : {}
    legacyRestName : tracker
    trackerItemField : tracker
 
    id : 2
    name : Business Value
    type : OptionChoiceField
    hidden : False
    valueModel : ChoiceFieldValue<ChoiceOptionReference>
    title : BV
    mandatoryInStatuses : {}
    multipleValues : False
    options : {@{id=0; name=Unset; type=ChoiceOptionReference}, @{id=1; name=Must have; type=ChoiceOptionReference}, @{id=3; name=Should have; type=ChoiceOptionReference}, @{id=5; name=Nice to have; type=ChoiceOptionReference}}
    sharedFields : {}
    legacyRestName : priority
    trackerItemField : priority
    referenceType : ChoiceOptionReference
    ....
    This example fetches the schema for the tracker with ID 'Tracker5678' from the server Codebeamer Server.
 
    .NOTES
    - The function outputs the schema structure of the specified tracker.
    - Debugging information provides insight into the request URI for troubleshooting.
    - Error management includes a specific check to verify tracker existence, guiding users on potential issues.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [string]$TrackerID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/trackers/{1}/schema" -f $CBSession.Server, $TrackerID

            Write-Debug "uri: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -errorAction Stop
            Write-Output $result
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Tracker is not found*" } {
                    Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBTrackerField {
    <#
    .SYNOPSIS
    Retrieves field information for a specific tracker from a Codebeamer server, with options for detailed output or filtering by field ID or field name.
 
    .DESCRIPTION
    The Get-CBTrackerField function interacts with a Codebeamer server's API to fetch field information associated with a specific tracker. It allows users to retrieve fields by specifying the field ID or name, request detailed information for all fields, or get all fields of the tracker.
 
    .PARAMETER TrackerID
    The identifier for the specific tracker whose field data is to be retrieved. This is a mandatory parameter for all parameter sets.
 
    .PARAMETER ID
    Used in the 'ByID' parameter set to specify the identifier of a particular field to retrieve.
 
    .PARAMETER Name
    Used in the 'ByName' parameter set to specify the name of a particular field to retrieve.
 
    .PARAMETER AllDetails
    Used in the 'DetailSet' parameter set to request detailed information for all fields within the specified tracker.
 
    .PARAMETER CBSession
    A mandatory parameter representing the session object required for connection to the CB server. This must include server information and headers necessary for authentication. This parameter is applicable across all parameter sets.
 
    .INPUTS
    None.
 
    .OUTPUTS
    PSCustomObject. Returns field details associated with the specified tracker, potentially filtered by field ID or name, or including all details.
 
    .EXAMPLE
    Example 1: Retrieve all fields for a tracker
    Get-CBTrackerField -TrackerID 12345 -CBSession $session
    .EXAMPLE
    Example 2: Retrieve a field by ID
    Get-CBTrackerField -TrackerID 12345 -ID 'fieldID123' -CBSession $session
    .EXAMPLE
    Example 3: Retrieve a field by name
    Get-CBTrackerField -TrackerID 12345 -Name 'FieldName' -CBSession $session
    .EXAMPLE
    Example 4: Retrieve detailed information for all fields
    Get-CBTrackerField -TrackerID 12345 -AllDetails -CBSession $session
 
    .NOTES
    Ensure the CBSession object is valid, and the server and headers are correctly populated to authenticate against the CB API.
    This function uses Invoke-RestMethod, so your environment must allow outbound HTTP requests.
 
    .LINK
    More information about API Endpoint:
    https://codebeamer.com/cb/wiki/11375774#section-Getting+detailed+information+about+a+field+in+a+specific+tracker
#>

    [CmdletBinding(DefaultParameterSetName = 'DefaultSet')]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'DefaultSet')]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'DetailSet')]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'ByID')]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = 'ByName')]
        [string]$TrackerID,

        [Parameter(ValueFromPipelineByPropertyName, ParameterSetName = 'ByID')]
        [string]$ID,

        [Parameter(ParameterSetName = 'ByName')]
        [string]$Name,

        [Parameter(ParameterSetName = 'DetailSet')]
        [switch]$AllDetails,

        [Parameter(Mandatory, ParameterSetName = 'DefaultSet')]
        [Parameter(Mandatory, ParameterSetName = 'DetailSet')]
        [Parameter(Mandatory, ParameterSetName = 'ByID')]
        [Parameter(Mandatory, ParameterSetName = 'ByName')]
        [pscustomobject]$CBSession
    )
    process {
        try {
            switch ($PSCmdlet.ParameterSetName) {
                'ByID' {
                    $uri = "https://{0}/cb/api/v3/trackers/{1}/fields/{2}" -f $CBSession.Server, $TrackerID , $ID

                    Write-Debug "URI: $uri"

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    $result
                }

                'ByName' {

                    $uri = "https://{0}/cb/api/v3/trackers/{1}/fields/{2}" -f $CBSession.Server, $TrackerID, $ID

                    Write-Debug "URI: $uri"

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    $ID = ($result | Where-Object { $_.name -eq $name }).id

                    if ($ID) {
                        $uriField = "https://{0}/cb/api/v3/trackers/{1}/fields/{2}" -f $CBSession.Server, $TrackerID, $ID

                        Write-Debug "URI: $uriField"

                        $result = Invoke-RestMethod -Uri $uriField -Method Get -Headers $CBSession.headers -ErrorAction Stop
                        $result
                    }
                    else {
                        $notExsisting = [PSCustomObject]@{
                            Name      = $name
                            TrackerID = $TrackerID
                            Exist     = $false
                        }
                        Write-Output $notExsisting
                    }
                }

                'DetailSet' {

                    $uri = "https://{0}/cb/api/v3/trackers/{1}/fields" -f $CBSession.Server, $TrackerID

                    Write-Debug "URI: $uri"

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

                    foreach ($id in $result.ID) {
                        $uri = "https://{0}/cb/api/v3/trackers/{1}/fields/{2}" -f $CBSession.Server, $TrackerID, $id
                        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                        $result  | Add-Member -NotePropertyName trackerid -NotePropertyValue $TrackerID
                        Write-Output $result
                    }
                }

                Default {

                    $uri = "https://{0}/cb/api/v3/trackers/{1}/fields" -f $CBSession.Server, $TrackerID

                    Write-Debug "uri: $uri"

                    $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
                    Write-Output $result
                }
            }
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Field is not found.*" } {
                    Write-Error "Field ID: $ID most likely doesn't exist. Please recheck Field ID or Server."
                }
                { $_ -like "*Tracker is not found.*" } {
                    Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBItemField {
    <#
    .SYNOPSIS
    Retrieves field information for a specified item in a Codebeamer server.
 
    .DESCRIPTION
    The `Get-CBItemField` function accesses and retrieves fields associated with a specific item from a Codebeamer server using the provided session. It supports fetching either all fields or specific fields based on the parameters specified.
 
    .PARAMETER ItemID
    The unique identifier for the item whose fields are to be retrieved. This parameter is mandatory and must be supplied. It is expected to be an integer.
 
    .PARAMETER Field
    Specifies one or more fields whose values you wish to retrieve for the item. This parameter is optional and should be used in conjunction with the `ItemID` parameter if you want to limit the results to specific fields.
 
    .PARAMETER ExcludeField
    It will exclude Fields and return any other field found on Tracker item
 
    .PARAMETER CBSession
    A custom object containing the connection session details for interacting with the Codebeamer server. This parameter is mandatory and should contain properties such as `Server` and headers required for API access.
 
    .EXAMPLE
    Get-CBItemField -ItemID 1234 -CBSession $session
 
    Retrieves all fields for the item with ID 1234 using the specified CB session.
 
    .EXAMPLE
    Get-CBItemField -ItemID 1234 -Field "Summary", "Description" -CBSession $session
 
    fieldId name sharedFieldNames type
    ------- ---- ---------------- ----
    10003 Summary {} TextFieldValue
       80 Description {} WikiTextFieldValue
 
    .NOTES
    This function requires appropriate permissions and a valid session to interact with the Codebeamer Server's API.
    Ensure the session object (`CBSession`) is correctly populated with necessary headers and server information prior to executing the function.
    Conversion of `DateFieldValue` types to a standard date format is handled internally.
 
#>

    [CmdletBinding(DefaultParameterSetName = "Default")]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = "Default")]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = "Field")]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = "ExcludeField")]
        [int]$ItemID,

        [Parameter(ParameterSetName = "Field")]
        [string[]]$Field,

        [Parameter(ParameterSetName = "ExcludeField")]
        [string[]]$ExcludeField,

        [Parameter(ParameterSetName = "Default")]
        [switch]$EditableFields,

        [Parameter(Mandatory, ParameterSetName = "Default")]
        [Parameter(Mandatory, ParameterSetName = "Field")]
        [Parameter(Mandatory, ParameterSetName = "ExcludeField")]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            $outputArr = New-Object -TypeName System.Collections.ArrayList
            $uri = "https://{0}/cb/api/v3/items/{1}/fields" -f $CBSession.Server, $ItemID

            Write-Debug "URI: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

            # Convert the date value to the specific format required by Codebeamer
            # Format: 'yyyy-MM-ddThh:mm:ss.fff' (e.g., 2023-08-15T14:30:00.123)
            $result.editableFields | ForEach-Object {
                if ($_.type -eq "DateFieldValue" -and $null -ne $_.value) {
                    $_.value = $_.value | Get-date -Format 'yyyy-MM-ddThh:mm:ss.fff'
                }
            }
            # Convert the date value to the specific format required by Codebeamer
            # Format: 'yyyy-MM-ddThh:mm:ss.fff' (e.g., 2023-08-15T14:30:00.123)
            $result.readOnlyFields | ForEach-Object {
                if ($_.type -eq "DateFieldValue" -and $null -ne $_.value) {
                    $_.value = $_.value | Get-date -Format 'yyyy-MM-ddThh:mm:ss.fff'
                }
            }

            Write-Debug "ParameterSetName: $($PSCmdlet.ParameterSetName)"

            switch ($PSCmdlet.ParameterSetName) {
                "Default" {
                    $outputFields = if ($editableFields.IsPresent) { $result.editableFields } else { $result }
                    Write-Output $outputFields
                }
                "Field" {
                    $outputArr.AddRange($result.editableFields)
                    $outputArr.AddRange($result.readOnlyFields)


                    Write-Debug "Field from Parameter: $fieldName"

                    $outputArr | Where-Object { $_.name -in $Field }

                }
                "ExcludeField" {
                    $outputArr.AddRange($result.editableFields)
                    $outputArr.AddRange($result.readOnlyFields)

                    Write-Debug "Exluded Field from Parameter: $ExcludeField"

                    $outputArr | Where-Object { $_.name -notin $ExcludeField }

                }
                Default { "Unknown Parameter Set Name $($PSCmdlet.ParameterSetName)" }
            }
        }
        catch {
            $fullError = $_
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Not accessible tracker item ids*" {

                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }
                default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBItemFieldOptions {
    <#
    .SYNOPSIS
    Retrieves options for fields of a specified item in the Codebeamer server.
 
    .DESCRIPTION
    The `Get-CBItemFieldOptions` function is designed to obtain available options for specified fields within an item in the Codebeamer server.
    The function supports both field name and field ID for querying field options, allowing for versatility and precision in data retrieval.
 
    .PARAMETER ItemID
    Specifies the item ID for which field options are to be retrieved.
    This parameter is mandatory and is available across all parameter sets.
 
    .PARAMETER FieldName
    Specifies the field name for which to retrieve options.
    This parameter is part of the 'FieldName' parameter set and is optional based on the parameter set being used.
 
    .PARAMETER FieldID
    Represents the field ID for which to retrieve options.
    This parameter is part of the 'FieldID' parameter set and is optional based on the parameter set being used.
 
    .PARAMETER Page
    Specifies the page number to retrieve for field options.
    Defaults to 1 for the first page. This parameter is optional across all parameter sets.
 
    .PARAMETER Size
    Determines the number of field options per page.
    The default value is 500, with a valid range between 1 and 500. This parameter is optional across all parameter sets.
 
    .PARAMETER CBSession
    A mandatory parameter representing the CB Session object, containing connection details such as server URL and headers.
    This session facilitates authentication and communication with the CB API.
    It is accessible using the alias 'cbs' and is mandatory in all parameter sets.
 
    .EXAMPLE
    get-CbitemFieldOptions -ItemID 7890 -FieldName Status -CBSession $session
 
    id name type
    -- ---- ----
    0 Unset ChoiceOptionReference
    1 To Do ChoiceOptionReference
    2 In Progress ChoiceOptionReference
    3 Implemented ChoiceOptionReference
    4 Done ChoiceOptionReference
    5 Draft ChoiceOptionReference
    6 Rejected ChoiceOptionReference
    7 Accepted ChoiceOptionReference
    8 Verified ChoiceOptionReference
 
    .EXAMPLE
    Get-CBItemFieldOptions -ItemID 7890 -FieldID 123 -CBSession $cbSession
 
    id name type
    -- ---- ----
    0 Unset ChoiceOptionReference
    1 To Do ChoiceOptionReference
    2 In Progress ChoiceOptionReference
    3 Implemented ChoiceOptionReference
    4 Done ChoiceOptionReference
    5 Draft ChoiceOptionReference
    6 Rejected ChoiceOptionReference
    7 Accepted ChoiceOptionReference
    8 Verified ChoiceOptionReference
 
    .NOTES
    - The function supports dynamic evaluation of fields, leveraging conditional logic based on input parameters.
    - URI requests are dynamically constructed, with debugging information assisting in troubleshooting processes.
    - Comprehensive error handling provides insight into common issues, including incorrect item IDs and inaccessible items.
 
#>

    [CmdletBinding(DefaultParameterSetName = "Default")]
    param (
        [Parameter(Mandatory, Position = 0, ParameterSetName = "Default")]
        [Parameter(Mandatory, Position = 0, ParameterSetName = "FieldName")]
        [Parameter(Mandatory, Position = 0, ParameterSetName = "FieldID")]
        [int]$ItemID,

        [Parameter(Position = 1, ParameterSetName = "FieldName")]
        [string]$FieldName,

        [Parameter(ParameterSetName = "FieldID")]
        [int]$FieldID,

        [Parameter(ParameterSetName = "Default")]
        [Parameter(ParameterSetName = "FieldName")]
        [Parameter(ParameterSetName = "FieldID")]
        [int]$Page = 1,

        [Parameter(ParameterSetName = "Default")]
        [Parameter(ParameterSetName = "FieldName")]
        [Parameter(ParameterSetName = "FieldID")]
        [ValidateRange(1, 500)]
        [int]$Size = 500,

        [Parameter(Mandatory, ParameterSetName = "Default")]
        [Parameter(Mandatory, ParameterSetName = "FieldName")]
        [Parameter(Mandatory, ParameterSetName = "FieldID")]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    try {
        switch ($PSCmdlet.ParameterSetName) {
            "FieldID" {
                $uri = "https://{0}/cb/api/v3/items/{1}/fields/{2}/options?Page={3}&pageSize={4}" -f $CBSession.Server, $ItemID, $FieldID, $Page, $Size

                Write-Debug "uri: $uri"

                $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers

                Write-Output $result.references

                $messageData = @"
            Command Information:
            "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), Field ID: $($FieldID)"
 
"@

                Write-Information -MessageData $messageData

            }
            "FieldName" {

                $uriFields = "https://{0}/cb/api/v3/items/{1}/fields" -f $CBSession.Server, $ItemID

                Write-Debug "URI: $uriFields"

                $fields = Invoke-RestMethod -Uri $uriFields -Method Get -Headers $CBSession.headers -ErrorAction Stop

                $allfields = New-Object -TypeName System.Collections.ArrayList

                $allfields.AddRange($fields.readOnlyFields)
                $allfields.AddRange($fields.editableFields)
                $fieldObject = $allfields | Where-Object { $_.name -eq $FieldName }

                if ($fieldObject) {

                    $uriId = "https://{0}/cb/api/v3/items/{1}/fields/{2}/options?Page={3}&pageSize={4}" -f $CBSession.Server, $ItemID, $fieldObject.fieldId, $Page, $Size

                    Write-Debug "uri: $uriId"

                    $result = Invoke-RestMethod -Uri $uriId -Method Get -Headers $CBSession.headers

                    $messageData = @"
            Command Information:
            "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), Field Name: $FieldName"
 
"@

                    Write-Information -MessageData $messageData

                    Write-Output $result.references
                }
                else {
                    throw "Field Name:$FieldName appears to not exist."
                }
            }
            Default { "Unknown Parameter Set Name $($PSCmdlet.ParameterSetName) " }
        }
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Not accessible tracker item*" } {
                Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
            }
            { $_ -like "*Tracker item is not found.*" } {
                Write-Error "Item ID is incorrect: Item $ItemID most likely doesn't exist. Please recheck ItemID"
            }
            Default { Write-Error $fullError }
        }
    }
}
function Export-CBAttachment {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$AttachmentID,

        [Parameter(Mandatory, Position = 1)]
        [string]$OutFile,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )

    try {
        $uri = "https://{0}/cb/api/v3/attachments/{1}/content" -f $CBSession.Server, $AttachmentID

        Write-Debug "URI: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop -OutFile $OutFile

        Write-Output $result
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "*Attachment*revision*is not found*" {
                Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
            }
            Default { Write-Error $fullError }
        }
    }
}
function Set-CBItem {
    <#
    .SYNOPSIS
    Updates fields of an item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Set-CBItem` function is designed to update specified fields of an item identified by its ID in a Codebeamer Server.
    It uses RESTful API calls to make the necessary updates and optionally provides verbose feedback.
 
    .PARAMETER ItemID
    Specifies the unique identifier of the item to be updated.
    This parameter is mandatory.
 
    .PARAMETER FieldValues
    Specifies an array of field values to be updated for the given item.
    Each field value should be a PSCustomObject containing the necessary fields and corresponding values.
    This parameter is mandatory.
 
    .PARAMETER QuietMode
    A switch parameter to enable or disable quiet mode.
    When enabled, updates might not trigger certain notifications or callbacks.
    This parameter is optional.
 
    .PARAMETER CBSession
    Specifies the CB Session object that includes necessary connection details such as server URL and headers.
    This object should contain the Server and headers properties.
    This parameter is mandatory and can be accessed through the alias 'cbs'.
 
    .EXAMPLE
        $fields = Get-CBItemField -ItemID 90812 -CBSession $cbSession -Field "Name","Action"
 
        Set-CBItem -ItemID 1234 -FieldValues $fieldValues -CBSession $cbSession
 
        Result will be updated Item Objects
 
    .NOTES
    - The function supports confirmation with the ShouldProcess method, allowing for simulation of operation before execution.
    - Error handling in this function checks specifically for locking issues, providing user information about who currently holds the lock.
    - Ensure the CBSession object is properly constructed to allow successful API communication.
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$ItemID,

        [Parameter(Mandatory)]
        [pscustomobject[]]$FieldValues,

        [Parameter()]
        [switch]$QuietMode,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession

    )
    begin {
        $body = [PSCustomObject]@{}
        $arrayList = New-Object System.Collections.ArrayList
        $FieldValues | ForEach-Object { $arrayList.Add($_) | Out-Null }
        $body | Add-Member -NotePropertyName fieldValues -NotePropertyValue $arrayList
    }

    process {
        try {
            $json = $body | ConvertTo-Json -Depth 20

            $uri = "https://{0}/cb/api/v3/items/{1}/fields?quietMode={2}" -f $CBSession.Server, $ItemID , $QuietMode

            Write-Debug "uri: $uri"
            Write-Debug "body: $json"

            if ($PSCmdlet.ShouldProcess($ItemID, "You will edit Fields $(($FieldValues.name -join ","))")) {
                $result = Invoke-RestMethod -Uri $uri -Method Put -Body $json -Headers $CBSession.headers -ErrorAction Stop
                Write-Output $result
            }

        }
        catch {
            $fullError = $_
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*currently locked by*" {
                    $user = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message -split "by "

                    $message = "Item ID: $ItemID is currently locked by $($user[1])"

                    Write-Error -Message $message
                }

                "*is not found in tracker*" {
                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }

                "*Not accessible tracker item ids*" {

                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }
                default { Write-Error $fullError }
            }
        }
    }
}
function Invoke-CBQL {
    <#
    .SYNOPSIS
    Executes a CBQL query against a Codebeamer Server and retrieves item information.
 
    .DESCRIPTION
    The `Invoke-CBQL` function allows users to perform CBQL queries, optionally using an established baseline ID for reference.
    Results are paged, and the function supports dynamic query construction using passed parameters.
 
 
    .PARAMETER cbQLString
    Represents the CBQL query string to execute.
    This parameter is optional, and if not supplied, the function will default to retrieving information based on other parameters.
 
    .PARAMETER BaseLineID
    Specifies the baseline ID to use for the query.
    This can influence what items are retrieved based on this baseline.
    This parameter is optional.
 
    .PARAMETER Page
    Indicates the page number to retrieve from the query results.
    Defaults to the first page (i.e., 1). This parameter is optional.
 
    .PARAMETER Size
    Defines the number of items per page to retrieve.
    The default value is set to 500, and the range is restricted from 1 to 500 for efficiency.
    This parameter is optional.
 
    .PARAMETER CBSession
    A mandatory parameter representing the CB Session object containing connection details such as server URL and headers.
    This session provides authentication and server details necessary for API interaction.
    This can be accessed through the alias 'cbs'.
 
    .EXAMPLE
 
    Invoke-CBQL -cbQLString "tracker.id=130673 AND modifiedby ='youusername'" -CBSession $cbSession
 
    This example executes a CBQL query to find items containing 'Test' in their name, using the specified baseline ID, on page 1 with a default page size.
 
    .EXAMPLE
    IT is possible to run query with Baseline Parameter
    Invoke-CBQL -cbQLString "tracker.id=130673 AND modifiedby ='youusername'" -BaseLineID 13047 -CBSession $cbSession
 
    WARNING!!! Ensure Baseline ID is correct Codebeamer will return head revision if wrong Basline is used. Yes there will be no error.
 
    .NOTES
    - Queries are URL-encoded to ensure proper transmission across web requests.
    - Error handling captures and returns API-related issues that may arise during execution.
    - Debug logs are available for internal tracking of URI and CBQL parameters.
    - For complete output information including page and size, use the Write-Information output.
    .LINK
    Every Query from official Codebeamer Site can be used https://codebeamer.com/cb/wiki/871101#section-Current+Item+Placeholder
#>

    [CmdletBinding()]
    param (
        [Parameter()]
        [string]$cbQLString,

        [Parameter()]
        [string]$BaseLineID,

        [Parameter()]
        [int]$Page = 1,

        [Parameter()]
        [ValidateRange(1, 500)]
        [int]$Size = 500,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    try {
        $urlEncoded = [System.Web.HttpUtility]::UrlEncode($cbqlString)

        $uri = if ($BaseLineID) {
            "https://{0}/cb/api/v3/items/query?baselineId={1}&page={2}&pageSize={3}&queryString={4}" -f $CBSession.Server, $BaseLineID, $Page, $Size, $urlEncoded
        }
        else {
            "https://{0}/cb/api/v3/items/query?page={1}&pageSize={2}&queryString={3}" -f $CBSession.Server, $Page, $Size, $urlEncoded
        }

        Write-Debug "CBQL: $urlEncoded"
        Write-Debug "URI: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers
        Write-Output $result.items
        $messageData = @"
 
        Command Information:
        "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), CBQL String: $cbqlString"
 
"@

        Write-Information -MessageData $messageData
    }
    catch {
        Write-Error $_
    }
}
function Find-CBUser {
    <#
    .SYNOPSIS
    Searches for users in the Codebeamer Server based on various criteria.
 
    .DESCRIPTION
    The `Find-CBUser` function allows users to search for specific users within the Codebeamer Server by utilizing different attributes such as name, email, first name, last name, user status, and project ID.
    Results are pageable, providing flexible navigation through large data sets.
 
    .PARAMETER Name
    Specifies the user's name for search criteria.
    This parameter is optional.
 
    .PARAMETER Email
    Defines the user's email address for search criteria.
    This parameter is optional.
 
    .PARAMETER FirstName
    Filters users by their first name.
    This parameter is optional.
 
    .PARAMETER LastName
    Filters users based on their last name.
    This parameter is optional.
 
    .PARAMETER UserStatus
    Filters users by their status, which can be 'ACTIVATED', 'DISABLED', or 'INACTIVATION'.
    This parameter is optional.
 
    .PARAMETER ProjectId
    Matches users associated with a specific project ID.
    This parameter is optional.
 
    .PARAMETER Page
    Indicates the page number to retrieve from the query results.
    The default is 1 for the first page.
    This parameter is optional.
 
    .PARAMETER Size
    Determines the number of users per page to retrieve.
    The default is 500, with a valid range between 1 and 500.
    This parameter is optional.
 
    .PARAMETER CBSession
    A mandatory parameter, representing the CB Session object, containing server URL and headers for API interaction.
    This object is accessed using the alias 'cbs'.
 
    .EXAMPLE
    Find-CBUser -Name "John Doe" -CBSession $searchSession
 
    .NOTES
    - The function constructs a dynamic JSON payload based on the provided parameters to query the Codebeamer Server.
    - Debugging information includes URI and payload details for troubleshooting.
    - Error handling ensures smooth execution, reporting issues encountered during API requests.
 
#>

    [CmdletBinding()]
    param (
        [Parameter()]
        [string]$name,

        [Parameter()]
        [string]$email,

        [Parameter()]
        [string]$firstName,

        [Parameter()]
        [string]$lastName,

        [Parameter()]
        [ValidateSet("ACTIVATED", "DISABLED", "INACTIVATION")]
        [string]$userStatus,

        [Parameter()]
        [int]$projectId,

        [Parameter()]
        [int]$Page = 1,

        [Parameter()]
        [ValidateRange(1, 500)]
        [int]$Size = 500,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    try {

        $valuesToRemove = "Page", "Size", "Server", "Debug", "asAdmin", "InformationAction", "CBSession"

        foreach ($removeValue in $valuesToRemove) {
            $PSBoundParameters.Remove($removeValue) | Out-Null
        }

        $body = $PSBoundParameters | ConvertTo-Json

        $uri = "https://{0}/cb/api/v3/users/search?page={1}&pageSize={2}" -f $CBSession.Server, $Page, $Size
        Write-Debug "URI:$uri"
        Write-Debug "Json Payload:$body"

        $result = Invoke-RestMethod -Uri $uri -Method Post -Headers $CBSession.headers -Body $body

        Write-Output $result.users

        $messageData = @"
 
        Command Information:
        "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total)"
 
"@

        Write-Information $messageData
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "*At least one filtering criteria must be provided*" {

                $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                Write-Error -Message $message
            }
            default { Write-Error $fullError }
        }
    }
}
function Get-CBItemReference {
    <#
    .SYNOPSIS
    Retrieves reference information for a specified item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBItemReference` function provides detailed reference data for a given item ID in the Codebeamer Server.
    Users can optionally provide a baseline ID, and the function supports paginated results for efficient data retrieval.
 
    .PARAMETER ItemID
    Represents the unique identifier of the item for which reference data is to be retrieved.
    This parameter is mandatory and accepts input from the pipeline.
 
    .PARAMETER BaseLineID
    Specifies the baseline ID to refine the reference data fetched.
    This parameter is optional and can alter the scope of the returned reference information.
 
    .PARAMETER Page
    Indicates the page number to retrieve in the query results.
    Defaults to the first page (i.e., 1). This parameter is optional.
 
    .PARAMETER Size
    Defines the number of references per page to retrieve.
    The default value is set to 500, with a range constraint between 1 and 500.
    This parameter is optional.
 
    .PARAMETER CBSession
    A mandatory parameter representing the CB Session object containing server URL and headers for API interaction.
    This session manages authentication and communication with the Codebeamer Server.
    It is accessible through the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBItemReference -ItemID 3885071 -CBSession $cbSession
 
    ItemID : 3885071
    DownstreamReferences : {}
    UpstreamReferences : {@{id=13111092; itemRevision=; type=UpstreamTrackerItemReference}, @{id=13111091; itemRevision=; type=UpstreamTrackerItemReference}}
    IncomingAssociations : {}
    OutgoingAssociations : {}
    ItemCount : 2
    IsLastPage : True
 
    .EXAMPLE
    Get-CBItemReference -ItemID 4567 -BaseLineID 123 -CBSession $cbSession
 
    This example fetches reference information using a specific baseline ID
 
    .NOTES
    - The function constructs an ordered dictionary to standardize output, encapsulating various reference aspects.
    - Debugging information includes the constructed URI for better traceability.
    - Error handling caters specifically to accessibility and baseline specification issues, guiding users on potential resolutions.
 
#>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline, Mandatory, Position = 0)]
        [int]$ItemID,

        [Parameter()]
        [int]$BaseLineID,

        [Parameter()]
        [int]$Page = 1,

        [Parameter()]
        [ValidateRange(1, 500)]
        [int]$Size = 500,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            $uri = if ($BaseLineID) {
                "https://{0}/cb/api/v3/items/{1}/relations?baselineId={2}&page={3}&pageSize={4}" -f $CBSession.Server, $ItemID, $BaseLineID, $Page, $Size
            }
            else {
                "https://{0}/cb/api/v3/items/{1}/relations?page={2}&pageSize={3}" -f $CBSession.Server, $ItemID, $Page, $Size
            }

            Write-Debug "Uri: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers

            $referenceItem = [ordered]@{
                ItemID               = $ItemID
                DownstreamReferences = $result.downstreamReferences
                UpstreamReferences   = $result.upstreamReferences
                IncomingAssociations = $result.incomingAssociations
                OutgoingAssociations = $result.outgoingAssociations
                ItemCount            = $result.itemCount
                IsLastPage           = $result.isLastPage
            }

            $output = New-Object -TypeName psobject -Property $referenceItem

            Write-Output $output

        }
        catch {
            $fullError = $_
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Not accessible tracker item ids*" {

                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }
                "*Baseline*" {

                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }
                default { Write-Error $fullError }
            }
        }
    }
}
function Open-Codebeamer {
    <#
    .SYNOPSIS
    Opens Codebeamer URLs based on specified parameters.
 
    .DESCRIPTION
    The `Open-Codebeamer` function facilitates the opening of Codebeamer links directly from the command line based on given item ID or tracker ID.
    It defaults to opening the main Codebeamer page if neither item nor tracker ID is specified.
 
    .PARAMETER Server
    Specifies the Codebeamer server to connect to.
    This parameter is mandatory and must be a valid CBServer name.
 
    .PARAMETER ItemID
    Represents the item ID within Codebeamer that should be opened.
    If provided, the function navigates directly to the specified item. This parameter is optional.
 
    .PARAMETER TrackerID
    Indicates the tracker ID within Codebeamer that should be opened.
    If provided, the function navigates directly to the specified tracker view. This parameter is optional.
 
    .EXAMPLE
    Open-Codebeamer -Server my-codebeamer.com:8080" -ItemID "12345"
 
    This example opens the specified item with ID "12345" on the Codebeamer server my-codebeamer.com:8080".
 
    .EXAMPLE
    Open-Codebeamer -Server my-codebeamer.com:8080" -TrackerID "6789"
 
    This example opens the tracker view with ID "6789" on the Codebeamer server my-codebeamer.com:8080".
 
    .EXAMPLE
    Open-Codebeamer -Server my-codebeamer.com:8080"
 
    This example opens the main page of the Codebeamer server my-codebeamer.com:8080" as no specific item or tracker ID was provided.
 
    .NOTES
    - The function utilizes Start-Process to open URLs directly in the default web browser.
    - Ensure valid Server is specified from the set of allowed CBServer names to prevent navigation errors.
    - The ValidateSet attribute should include appropriate values for CBServer which are predefined externally.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$Server,

        [Parameter()]
        [string]$ItemID,

        [Parameter()]
        [string]$TrackerID
    )
    switch ($true) {

        { -not [string]::IsNullOrEmpty($ItemID) } { start-Process ("https://{0}/cb/issue/{1}" -f $server, $ItemID) ; break }
        { -not [string]::IsNullOrEmpty($TrackerID) } { start-Process ("https://{0}/cb/tracker/{1}?workingSetId=-1&layout_name=document&view_id=-11" -f $server, $TrackerID) ; break }
        Default {
            Start-Process  "https://$Server/cb/"; break
        }
    }
}
function New-CBItem {
    <#
    .SYNOPSIS
    Creates a new item in a specified tracker from a CodeBeamer server
 
    .DESCRIPTION
    The New-CBItem function allows you to create a new item within a given tracker. It requires a Tracker ID and an active session (`CBSession`). You can specify field values, including default fields like Summary and Description, as well as custom fields.
 
    .PARAMETER TrackerID
    Mandatory parameter specifying the ID of the tracker where the item will be created.
 
    .PARAMETER FieldValues
    Optional array of PSCustomObjects representing fields and their values for the new item. Each object should have 'name' and 'value' properties. Default fields are 'Summary' and 'Description'.
 
    .PARAMETER CBSession
    Mandatory parameter, a PSCustomObject representing the session context. It should contain properties like 'Server' and 'headers' necessary for making API requests.
 
    .EXAMPLE
    #Creating a new item with a summary and description
 
    $fieldValues = @(
        [PSCustomObject]@{ name = "Summary"; value = "New Item Summary" },
        [PSCustomObject]@{ name = "Description"; value = "Detailed description of the new item." }
    )
    New-CBItem -TrackerID "12345" -FieldValues $fieldValues -CBSession $cbSession
    .EXAMPLE
    # Creating a new item with custom fields
 
    $fields = get-cbitemField -ItemID 388408 -CBSession $test -Field Name,description 12:13:33
    $fields
    fieldId : 3
    name : Name
    value : Default TextFieldValue Generated on: 2025-05-19T10:13:08.378
    sharedFieldNames : {}
    type : TextFieldValue
 
    fieldId : 80
    name : Description
    value : Test of tracker Item
    sharedFieldNames : {}
    type : WikiTextFieldValue
 
    You can Edit the object "Value" with further script or in Terminal
 
    $fields[0].value = "NEW VALUE"
    $fields[1].value = "NEW VALUE of description"
 
    New-CBItem -TrackerID "67890" -FieldValues $fields -CBSession $cbSession
 
    .NOTES
    You must have appropriate permissions in the CBSession context to successfully create items.
 
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$TrackerID,

        [Parameter()]
        [PSCustomObject[]]$FieldValues,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {

        if ($FieldValues) {
            $defaultFields = @("Summary", "Description")
            $arrayList = New-Object System.Collections.ArrayList
            $payload = [pscustomobject]@{}

            $payload | Add-member -NotePropertyName name -NotePropertyValue ($FieldValues | Where-Object { $_.name -eq "Summary" } | Select-Object -ExpandProperty value)
            $payload | Add-member -NotePropertyName description -NotePropertyValue ($FieldValues | Where-Object { $_.name -eq "Description" } | Select-Object -ExpandProperty value)

            $FieldValues | ForEach-Object { if ($_.name -notin $defaultFields) { $arrayList.Add($_) | Out-Null } }

            $payload | Add-Member -NotePropertyName customFields -NotePropertyValue $arrayList
        }
        else {
            $payload = @{}
        }


        $body = $payload | ConvertTo-Json -Depth 100

        Write-Debug -Message "Body: $body"

        $uri = "https://{0}/cb/api/v3/trackers/{1}/items" -f $CBSession.Server, $TrackerID

        Write-Debug -Message "uri: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method POST -Headers $CBSession.headers -Body $body -erroraction Stop
        Write-Output $result
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker is not found.*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBItemHistory {
    <#
    .SYNOPSIS
    Retrieves the version history for a specified item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBItemHistory` function fetches the version history of a given item ID from the Codebeamer Server.
    It utilizes a RESTful API call to acquire all historical versions of the specified item.
 
    .PARAMETER ItemID
    Represents the unique identifier of the item whose history is to be retrieved.
    This parameter is mandatory and accepts input from the pipeline.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session facilitates authentication and interaction with the Codebeamer Server's API.
    It is mandatory and accessible using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBItemHistory -ItemID 1234 -CBSession $cbSession
 
    itemRevision changes modifiedBy modifiedAt
    ------------ ------- ---------- ----------
    @{id=1234; version=1} {} @{id=4911; name=user; type=UserReference; email=user@company.com} 5/22/2025 12:06:44 PM
 
    (...)
 
    .NOTES
    - The function outputs the version data, allowing users to track changes over time.
    - Debugging information includes the constructed URI for transparency and troubleshooting.
    - Error handling manages accessibility issues specifically, providing user-friendly messages when failures occur.
 
#>

    [CmdletBinding()]
    param(
        [parameter(Mandatory, ValueFromPipeline, Position = 0)]
        [int]$ItemID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/items/{1}/history" -f $CBSession.Server, $ItemID

            Write-Debug "uri: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
            Write-Output $result.versions
        }
        catch {
            $fullError = $_
            switch -Wildcard ($_.ErrorDetails.Message) {
                "*Not accessible tracker item ids*" {

                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error -Message $message
                }
                default { Write-Error $fullError }
            }
        }
    }
}
function Copy-CBItem {
    <#
    .SYNOPSIS
    Copies specified fields from one item to another within the Codebeamer Server.
 
    .DESCRIPTION
    The `Copy-CBItem` function is engineered to copy fields from a source item to a destination item within the Codebeamer Server.
    It supports selective field copying and utilizes a REST API to perform the operation, with options for quiet mode execution.
 
    .PARAMETER ItemID
    Specifies the ID of the source item from which fields are to be copied.
    This parameter is mandatory.
 
    .PARAMETER DestinationItemID
    Indicates the ID of the destination item to which fields are to be copied.
    This parameter is mandatory.
 
    .PARAMETER Fields
    An optional parameter that contains an array of field names to copy from the source to the destination item.
    If not specified, all editable fields are copied.
 
    .PARAMETER QuietMode
    A switch parameter that, when specified, minimizes notifications and callbacks during the copy process.
    This parameter is optional.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session facilitates authentication and API interaction.
    It is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
 
    This will copy all editable fields from item 1234 to 5678
 
    Copy-CBItem -ItemID 1234 -DestinationItemID 5678 -CBSession $cbSession
 
    .EXAMPLE
 
    Copy-CBItem -ItemID 1234 -DestinationItemID 5678 -Fields "Field1", "Field2" -CBSession $cbSession
 
    This example copies "Field1" and "Field2" from the item with ID 1234 to the item with ID 5678 on the server
 
    .EXAMPLE
    Copy-CBItem -ItemID 1234 -DestinationItemID 5678 -QuietMode -CBSession $cbSession
 
    This example copies all editable fields from item 1234 to item 5678, executing the operation in quiet mode.
 
    .NOTES
    - The function handles date field values specifically to ensure correct format during transfer.
    - Error handling includes checks for access issues and item existence, reporting meaningful errors where applicable.
    - Debug logs provide insights into URI construction and JSON payloads for improved traceability.
 
#>

    [CmdletBinding()]
    param(
        [parameter(Mandatory, Position = 0)]
        [int]$ItemID,

        [parameter(Mandatory, Position = 1)]
        [int]$DestinationItemID,

        [Parameter()]
        [string[]]$Fields,

        [Parameter()]
        [switch]$QuietMode,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $uri = "https://{0}/cb/api/v3/items/{1}/fields" -f $CBSession.Server, $ItemID

        Write-Debug "URI: $uri"

        $valueToCopy = (Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop).editableFields

        if ($Fields) {
            $valueToCopy = foreach ($field in $Fields) {
                $valueToCopy | Where-Object { $_.name -eq $field }
            }
        }

        foreach ($copyValue in $valueToCopy) {
            if ($copyValue.type -eq "DateFieldValue" -and $null -ne $copyValue.value) {
                $copyValue.value = $copyValue.value | Get-date -Format 'yyyy-MM-ddThh:mm:ss.fff'
            }
        }

        $body = [PSCustomObject]@{}
        $arrayList = New-Object System.Collections.ArrayList
        $valueToCopy | ForEach-Object { $arrayList.Add($_) | Out-Null }
        $body | Add-Member -NotePropertyName fieldValues -NotePropertyValue $arrayList

        $json = $body | ConvertTo-Json -Depth 10

        Write-Debug "$json"

        $uriCopy = "https://{0}/cb/api/v3/items/{1}/fields?quietMode={2}" -f $CBSession.Server, $DestinationItemID, $QuietMode

        Write-Debug "URI: $uriCopy"

        Invoke-RestMethod -Uri $uriCopy -Method PUT -Body $json -Headers $CBSession.headers -ErrorAction Stop
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Not accessible tracker item ids*" } {
                $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                Write-Error $message
            }
            { $_ -like "*Tracker item is not found.*" } {
                Write-Error "Item $itemID most likely doesn't exist. Please recheck Item ID."
            }
            Default { Write-Error $fullError }
        }
    }
}
function Find-CBUserRole {
    <#
    .SYNOPSIS
    Retrieves the roles of a specified user across projects in the Codebeamer Server.
 
    .DESCRIPTION
    The `Find-CBUserRole` function searches for a user's roles in all projects within the Codebeamer Server.
    It operates by first retrieving the user's ID and then querying each project to list roles associated with the user.
 
    .PARAMETER UserName
    Specifies the name of the user whose roles are to be retrieved.
    This parameter is mandatory.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers for API interaction.
    This session manages authentication and communication with the Codebeamer Server.
    It is mandatory and accessible through the alias 'cbs'.
 
    .EXAMPLE
    Find-CBUserRole -UserName "john.doe" -CBSession $cbSession
 
    ProjectID Project Roles UserName
    --------- ------- ----- --------
            2 Sandbox Agile Scrum Project Admin john.doe
           41 Project Planning Project Admin john.doe
           42 Software Development Project Admin john.doe
           43 Project Management Project Admin john.doe
 
    This example searches for the roles of user "john.doe" across all projects on the Codebeamer server
 
    .NOTES
    - The function loops through all projects, reporting each found role for the given user and displaying progress.
    - User names are converted to lowercase to standardize search queries, ensuring case-insensitive matches.
    - Error handling gracefully manages any API-related issues and provides meaningful error messages when failures occur.
    - Progress is displayed using the Write-Progress cmdlet, giving real-time updates on the search operation.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$UserName,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $UserName = $UserName.ToLower()

        $userIDuri = "https://{0}/cb/api/v3/users/findByName?name={1}" -f $CBSession.Server, $UserName

        $userID = (Invoke-RestMethod  -Uri $userIDuri -Method Get -Headers $CBSession.headers -ErrorAction Stop).id

        $getProjectsIDuri = "https://{0}/cb/api/v3/projects" -f $CBSession.Server

        $projectInfo = Invoke-RestMethod -Uri $getProjectsIDuri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        $percentage = (100 / $projectInfo.length)
        $percentage = [Math]::Floor($percentage)

        foreach ($project in $projectInfo) {
            $OuterLoopProgressParameters = @{
                Activity        = 'Searching in Projects...'
                Status          = " Progress... -> $($_.Name)"
                PercentComplete = $percent += $percentage
            }

            $uri = "https://{0}/cb/api/v3/projects/{1}/members/{2}/permissions" -f $CBSession.Server, $project.id, $userID
            Write-Progress @OuterLoopProgressParameters
            $projects = (Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers).roles

            $roles = [ordered]@{
                ProjectID = $project.ID
                Project   = $project.Name
                Roles     = $projects.name
                UserName  = $UserName
            }
            $userRole = New-Object -TypeName psobject -Property $roles

            Write-Output $userRole
        }
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*User is not found by name*" } {
                $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                Write-Error $message
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBGroup {
    <#
    .SYNOPSIS
    Retrieves all user groups from the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBGroup` function accesses the Codebeamer Server to fetch a list of user groups.
    It utilizes REST API calls to obtain the group information from the specified server.
 
    .PARAMETER CBSession
    Represents the CB Session object containing the necessary connection details such as server URL and headers.
    This facilitates the authentication process and enables communication with the CB API.
    It is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
 
    PS > Get-CBGroup -CBSession $cbSession
 
    id name type
    -- ---- ----
    1000 sysadmin UserGroupReference
    1004 Support User UserGroupReference
    4882 New User UserGroupReference
    26511 Team UserGroupReference
    28470 Project Admin UserGroupReference
    34114 Rest API User UserGroupReference
 
    .NOTES
    - The function simply fetches and outputs the group data as returned by the API, providing quick access to group information.
    - Error handling is in place to manage API-related issues, ensuring meaningful error messages are relayed to the user.
    - The function utilizes `Invoke-RestMethod` for API interaction, expecting headers containing authentication details.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $uri = "https://{0}/cb/api/v3/users/groups" -f $CBSession.Server

        $groups = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        Write-Output $groups
    }
    catch {
        Write-Error $_
    }
}
function Get-CBItemAcessibility {
    <#
    .SYNOPSIS
    Retrieves accessibility information for fields of a specified item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBItemAccessibility` function fetches information about field accessibility for a given item ID in the Codebeamer Server.
    The output includes field IDs, names, and their accessibility attributes such as visibility, mandatory status, and editability.
    Users can filter the result to show only mandatory fields.
 
    .PARAMETER ItemID
    Specifies the ID of the item from which field accessibility details are to be retrieved.
    This parameter is mandatory.
 
    .PARAMETER Mandatory
    A switch parameter that, when specified, filters the output to include only fields marked as mandatory.
    This parameter is optional.
 
    .PARAMETER CBSession
    Represents the CB Session object containing the necessary connection details such as server URL and headers.
    This session facilitates authentication and API communication.
    It is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBItemAccessibility -ItemID 1234 -CBSession $cbSession
 
    FieldID : 0
    FieldName : ID
    visible : True
    mandatory : False
    editable : False
 
    FieldID : 76
    FieldName : Parent
    visible : True
    mandatory : False
    editable : True
 
    FieldID : 1
    FieldName : Tracker
    visible : True
    mandatory : False
    editable : False
 
    FieldID : 2
    FieldName : Business Value
    visible : True
    mandatory : False
    editable : True
 
    (...)
 
    .EXAMPLE
    This Exmaple retrives only Mandatory Fields of Tracker Item
 
    Get-CBItemAccessibility -ItemID 1234 -Mandatory -CBSession $cbSession
 
    FieldID : 3
    FieldName : Summary
    visible : True
    mandatory : True
    editable : True
 
    FieldID : 80
    FieldName : Description
    visible : True
    mandatory : True
    editable : True
 
    .NOTES
    - The function processes and outputs selected field properties, including visibility and editability status.
    - Error handling accommodates specific checks for item existence and returns meaningful error messages in case of issues.
    - The switch parameter allows flexibility, enabling selective filtering of output results.
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$ItemID,

        [Parameter()]
        [switch]$Mandatory,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession

    )
    try {
        $uri = "https://{0}/cb/api/v3/items/{1}/fields/accessibility" -f $CBSession.Server, $ItemID

        $result = (Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers).fields
        | Select-Object @{N = "FieldID"; E = { $_.field.ID } }, @{N = "FieldName"; E = { $_.field.name } }, visible, mandatory, editable

        $output = switch ($true) {
            $Mandatory.IsPresent {
                $result | Where-Object { $_.Mandatory -eq $true }
            }
            Default { $result }
        }

        Write-Output $output
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker item is not found.*" } {
                Write-Error "Item ID is incorrect: Item $itemID most likely doesn't exist. Please recheck ItemID"
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBTrackerTree {
    <#
    .SYNOPSIS
    Retrieves the tracker tree structure for a specified project in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBTrackerTree` function accesses the Codebeamer Server to fetch the hierarchical structure of trackers within a given project.
    It utilizes RESTful API calls to obtain detailed tracker information associated with the project ID.
 
    .PARAMETER ProjectID
    Specifies the ID of the project for which the tracker tree is to be retrieved.
    This parameter is mandatory.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers for API interaction.
    This session manages authentication and communication with the Codebeamer Server.
    It is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBTrackerTree -ProjectID 5678 -CBSession $cbSession
 
    isFolder text children
    -------- ---- --------
    True Work Items {@{trackerId=3521503}, @{trackerId=3541396}, @{trackerId=3542177}}
    True Tasks {@{trackerId=3531966}}
    True Config Items {@{trackerId=3521502}, @{trackerId=3525112}, @{trackerId=3521511}, @{trackerId=11661406}…}
                          {@{trackerId=13010422},@{trackerId=12919923},@{trackerId=12991240},@{trackerId=12919184}…}
 
    .NOTES
    - The function outputs the hierarchical tracker structure associated with the given project.
    - Debugging information includes the constructed URI for increased transparency and troubleshooting.
    - Proper error handling ensures informative messages are provided in case of API-related issues.
 
#>

    [CmdletBinding()]
    param(
        [parameter(Mandatory, Position = 0)]
        [int]$ProjectID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )

    try {
        $uri = "https://{0}/cb/api/v3/trackers/tree?projectId={1}" -f $CBSession.Server, $ProjectID

        Write-Debug "uri: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        Write-Output $result
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "*Project not found*" {
                $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                $errorMEssage = "{0} Please recheck Project ID: {1}" -f $message, $ProjectID
                Write-Error $errorMEssage
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBTrackerConfiguration {
    <#
    .SYNOPSIS
    Retrieves the configuration details for a specified tracker in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBTrackerConfiguration` function accesses the Codebeamer Server to fetch configuration information for a given tracker ID.
    Users can opt to filter results to return only mandatory fields associated with the tracker.
 
    .PARAMETER TrackerID
    Specifies the unique identifier of the tracker for which configuration details are to be retrieved.
    This parameter is mandatory.
 
    .PARAMETER MandatoryFields
    A switch parameter that, when specified, filters the output to include only fields marked as mandatory within the tracker.
    This parameter is optional.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers for API interaction.
    This session facilitates authentication and API communication.
    It is mandatory and accessible using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBTrackerConfiguration -TrackerID 1234 -CBSession $cbSession
 
    This example retrieves the configuration details for tracker ID 1234 on the Codebeamer server
 
    .EXAMPLE
    Get-CBTrackerConfiguration -TrackerID 1234 -MandatoryFields -CBSession $cbSession
 
    This example fetches only mandatory field configurations for tracker ID 1234.
 
    .NOTES
    - The function provides comprehensive configuration data unless filtered by the `MandatoryFields` switch.
    - Debug information includes the URI utilized for the API request, aiding in troubleshooting.
    - Error handling manages common issues like invalid Tracker IDs, ensuring meaningful error messages are relayed to the user.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$TrackerID,

        [Parameter()]
        [switch]$MandatoryFields,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $uri = "https://{0}/cb/api/v3/tracker/{1}/configuration" -f $CBSession.Server, $TrackerID

        Write-Debug "uri: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        switch ($true) {
            $MandatoryFields.IsPresent {
                $mandatory = ($result.fields | Where-Object { $_.Mandatory -eq $true })
                Write-Output $mandatory

                if (-not $mandatory) {
                    $message = "Tracker: $TrackerID does not have Mandatory Fields!"

                    Write-Information $message
                }
            }
            Default { Write-Output $result }
        }
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker not found*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}
function Update-CBTrackerConfiguration {
    <#
    .SYNOPSIS
    Updates the configuration for a specified tracker in the Codebeamer Server.
 
    .DESCRIPTION
    The `Update-CBTrackerConfiguration` function updates the configuration of a tracker within the Codebeamer Server.
    It accepts a tracker configuration object and utilizes a RESTful API call to submit the changes, providing confirmation before executing the operation.
 
    .PARAMETER TrackerConfiguration
    Represents the configuration object containing details to update the specified tracker.
    This parameter is mandatory.
 
    .PARAMETER CBSession
    Specifies the CB Session object containing necessary connection details such as server URL and headers.
    This session facilitates authentication and API communication.
    It is mandatory and accessible using the alias 'cbs'.
 
    .EXAMPLE
 
    $config = get-cbTrackerConfiguration -TrackerID 13127411 -CBSession $cbSession
 
    # Clear Tracker ID
    $config.basicInformation.trackerId = ""
 
    # Change Project ID where you want to have tracker
    $config.basicInformation.projectId = 46
 
    Update-CBTrackerConfiguration -TrackerConfiguration 4Config -CBSession $cbSession
 
    This example updates the configuration for tracker ID 1234 in project ID 5678 on the Codebeamer server
 
    .NOTES
    - The function supports `ShouldProcess`, allowing for confirmation before the update operation is executed.
    - Error handling ensures any execution issues are captured and meaningful error messages are provided.
    - Ensure the configuration object is constructed correctly to avoid JSON serialization issues during API submission.
 
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory, Position = 0)]
        [PSCustomObject]$TrackerConfiguration,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        if ($PSCmdlet.ShouldProcess($CBSession.Server, ("You will updated Project id {1} and Tracker ID {0} " -f $TrackerConfiguration.basicInformation.ID, $TrackerConfiguration.basicInformation.projectID))) {
            $body = $TrackerConfiguration | ConvertTo-Json -Depth 100

            $uri = "https://{0}/cb/api/v3/tracker/configuration" -f $CBSession.Server

            Invoke-RestMethod -Uri $uri -Method Post -Body $body -Headers $CBSession.headers
        }
    }
    catch {
        Write-Error $_
    }
}
function Remove-CBItem {
    <#
    .SYNOPSIS
    Removes an item from a specified tracker using the CBSession context.
 
    .DESCRIPTION
    The Remove-CBItem function allows you to delete an item from a tracker by specifying its Item ID and an active session (`CBSession`). It supports pipeline input for Item IDs and includes functionality to confirm the deletion action.
 
    .PARAMETER ItemID
    The ID of the item to be removed. This parameter supports pipeline input.
 
    .PARAMETER CBSession
    A mandatory PSCustomObject representing the session context. It should contain properties like 'Server' and 'headers' necessary for making API requests.
 
    .EXAMPLE
    #Removing an item using an ItemID
 
    Remove-CBItem -ItemID 54321 -CBSession $cbSession
 
    .NOTES
    Ensure the CBSession is valid and has appropriate permissions to delete items from the specified tracker.
 
#>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(ValueFromPipeline, Position = 0)]
        [string]$ItemID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            if ($PSCmdlet.ShouldProcess($CBSession.Server, ("Item {0} will be deleted" -f $ItemID))) {
                $uri = "https://{0}/cb/api/v3/items/{1}" -f $CBSession.Server, $ItemID
                Invoke-RestMethod -Uri $uri -Method Delete -Body $body -Headers $CBSession.headers
            }
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Not accessible tracker item ids*" } {
                    $message = ($fullError.ErrorDetails.Message | ConvertFrom-Json).message

                    Write-Error $message
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBItemLock {
    <#
    .SYNOPSIS
    Retrieves lock information for a specified item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBItemLock` function queries the Codebeamer Server to check and retrieve lock status information for a given item ID.
    This can be useful for understanding if the item is locked, and if so, by whom.
 
    .PARAMETER ItemID
    Represents the unique identifier of the item whose lock status is to be retrieved.
    This parameter can accept input from the pipeline.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session enables authentication and communication with the CB API.
    It is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
    get-CBItemLock -ItemID 12345 -cbsession $cbSession
 
    user expires
    ---- -------
    @{id=41; name=idOfUserWhoLockedItem; type=UserReference; email=emailOfUserWhoLockedItem} True
 
    .NOTES
    - Debugging information includes the constructed URI for enhanced troubleshooting.
    - Error handling provides specific checks for item accessibility and existence, ensuring meaningful feedback when issues are encountered.
    - Make sure the `CBSession` object is correctly formed to enable API communication without errors.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline, Position = 0)]
        [string]$ItemID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            $uri = "https://{0}/cb/api/v3/items/{1}/lock" -f $CBSession.Server, $ItemID

            Write-Debug "URI: $uri"

            Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Not accessible tracker item*" } {
                    Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                }
                { $_ -like "*Tracker item is not found.*" } {
                    Write-Error "Item ID is incorrect: Item $itemID most likely doesn't exist. Please recheck ItemID"
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Set-CBItemLock {
    <#
    .SYNOPSIS
    Manages the lock state of a specified item in the Codebeamer Server.
 
    .DESCRIPTION
    The `Set-CBItemLock` function allows users to either lock or unlock an item in the Codebeamer Server.
    Locking an item can be done for a specific duration, and unlocking removes any existing locks on the item.
    The function uses RESTful API calls to perform the actions specified by the user.
 
    .PARAMETER ItemID
    Specifies the ID of the item for which the lock state is to be managed.
    This parameter is mandatory in both parameter sets: 'Lock' and 'Unlock'.
 
    .PARAMETER Lock
    A switch parameter used to set the lock on an item.
    This parameter is part of the 'Lock' parameter set.
 
    .PARAMETER Duration
    Indicates the duration for which the item should be locked.
    Accepted formats are '1:30h' for one and a half hours and '1d' for one day.
    This parameter is optional and part of the 'Lock' parameter set.
 
    .PARAMETER Unlock
    A switch parameter used to remove the lock from an item.
    This parameter is part of the 'Unlock' parameter set.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session facilitates authentication and communication with the CB API.
    It is mandatory and accessible using the alias 'cbs'.
 
    .EXAMPLE
 
    Set-CBItemLock -ItemID 1234 -Lock -Duration '1d' -CBSession $cbSession
 
    1234 Locked
 
    .EXAMPLE
    Set-CBItemLock -ItemID 1234 -Unlock -CBSession $cbSession
 
    1234 Unlocked
 
    .NOTES
    - The function employs multiple parameter sets to distinguish lock and unlock operations, ensuring clear command execution.
    - Debugging information includes constructed URIs and JSON payloads for monitoring API requests.
    - Error handling addresses item accessibility and existence as well as duration validity, providing informative error messages.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'Lock')]
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'Unlock')]
        [int]$ItemID,

        [Parameter(ParameterSetName = 'Lock')]
        [switch]$Lock,

        [Parameter(ParameterSetName = 'Lock')]
        [ArgumentCompletions('1:30h', '1d')]
        [String]$Duration,

        [Parameter(ParameterSetName = 'Unlock')]
        [switch]$Unlock,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    process {
        try {
            switch ($PSCmdlet.ParameterSetName) {
                "Lock" {
                    $lockDetails = [PSCustomObject]@{
                        duration = $Duration
                        hard     = $false
                    }
                    $uri = "https://{0}/cb/api/v3/items/{1}/lock" -f $CBSession.Server, $ItemID

                    Write-Debug $uri

                    $json = $lockDetails | ConvertTo-Json

                    Write-Debug $json

                    Invoke-RestMethod -Uri $uri -Method Put -Headers $CBSession.headers -Body $json -ErrorAction Stop

                    Write-Output "$ItemID Locked"

                }
                "Unlock" {

                    $uri = "https://{0}/cb/api/v3/items/{1}/lock" -f $CBSession.Server, $ItemID

                    Write-Debug $uri

                    Invoke-RestMethod -Uri $uri -Method Delete -Headers $CBSession.headers -ErrorAction Stop

                    Write-Output "$ItemID Unlocked"

                }
                Default { throw "Unknown Parameter Set: $($PSCmdlet.ParameterSetName))" }
            }
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Not accessible tracker item*" } {
                    Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                }
                { $_ -like "*Tracker item is not found.*" } {
                    Write-Error "Item ID is incorrect: Item $itemID most likely doesn't exist. Please recheck Version or ItemID"
                }
                { $_ -like "*Tracker item lock duration*" } {
                    Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                }
                Default { Write-Error $fullError }
            }
        }
    }
}
function Get-CBReport {
    <#
    .SYNOPSIS
    Retrieves the results of a specified report from the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBReport` function accesses the Codebeamer Server to fetch results for a given report ID.
    It employs RESTful API calls to acquire the report data, which is then outputted for user review.
 
    .PARAMETER ReportID
    Specifies the unique identifier for the report whose results are to be retrieved.
    This parameter is mandatory.
 
    .PARAMETER CBSession
    Represents the CB Session object containing necessary connection details such as server URL and headers.
    This session facilitates authentication and communication with the CB API.
    It is mandatory and accessible using the alias 'cbs'.
 
    .EXAMPLE
 
    Get-CBReport -ReportID 789 -CBSession $cbSession
 
    report : @{id=789; name=Administrator TEST; type=ReportReference}
    cbQL : project.id IN (436) AND tracker.id IN (3539166,3525013) AND workItemStatus NOT IN ('Resolved','Closed') AND '46.352503.status' NOT IN ('Done','Rejected') ORDER BY modifiedAt ASC
    columns : {@{columnRef=0-3; field=; name=Summary; type=text; columnWidthPercentage=50; columnIndex=0}, @{columnRef=0-7; field=; name=Status; type=choice; columnWidthPercentage=50; columnIndex=1}}
    pagingInformation : @{page=1; pageSize=25; pageCount=2}
    data : @{type=ReportGroupWithRows; header=Grand Total; count=25; rows=System.Object[]}
    showAllChildren : False
 
    This example retrieves the results for report ID 789 from the Codebeamer server.
 
    .NOTES
    - The function outputs the report data retrieved from the API, allowing users to analyze the report's contents.
    - Debug information includes the constructed URI to assist in troubleshooting and understanding API interactions.
    - Error handling manages common issues such as incorrect report IDs, ensuring informative feedback is provided in case of errors.
 
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$ReportID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    try {
        $uri = "https://{0}/cb/api/v3/reports/{1}/results" -f $CBSession.Server, $ReportID

        Write-Debug "uri: $uri"

        $report = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        Write-Output $report
    }
    catch {
        $fullError = $_
        switch -Wildcard ($_.ErrorDetails.Message) {
            "*Couldn\u0027t find report*" {
                Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
            }
            Default { Write-Error $fullError }
        }
    }
}
function Get-CBRole {
    <#
    .SYNOPSIS
    Retrieves role information from the Codebeamer Server.
 
    .DESCRIPTION
    The `Get-CBRole` function fetches all roles, a specific role by ID, or searches for a role by name from the Codebeamer Server using the provided session.
 
    .PARAMETER RoleID
    The ID of the role to retrieve. Optional.
 
    .PARAMETER RoleName
    The name of the role to search for. Optional.
 
    .PARAMETER CBSession
    The session object containing server URL and headers. Mandatory.
 
    .EXAMPLE
    Get-CBRole -CBSession $cbSession
 
    Retrieves all roles from the server.
 
    .EXAMPLE
    Get-CBRole -RoleID 123 -CBSession $cbSession
 
    Retrieves the role with ID 123.
 
    .EXAMPLE
    Get-CBRole -RoleName "Admin" -CBSession $cbSession
 
    Searches for roles with "Admin" in the name.
 
    .NOTES
    - Requires a valid CBSession object.
    - Returns role objects as provided by the Codebeamer REST API.
#>

    [CmdletBinding(DefaultParameterSetName = "Default")]
    param (
        [Parameter(Position = 0, ParameterSetName = "RoleID")]
        [int]$RoleID,

        [Parameter(ParameterSetName = "RoleName")]
        [string]$RoleName,

        [Parameter(Mandatory, ParameterSetName = "Default")]
        [Parameter(Mandatory, ParameterSetName = "RoleID")]
        [Parameter(Mandatory, ParameterSetName = "RoleName")]
        [Alias("cbs")]
        [pscustomobject]$CBSession

    )
    try {
        $output = switch ($PSCmdlet.ParameterSetName) {
            "Default" {
                $uri = "https://{0}/cb/api/v3/roles" -f $CBSession.Server

                Write-Debug $uri

                Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
            }

            "RoleID" {

                $uri = "https://{0}/cb/api/v3/roles/{1}" -f $CBSession.Server, $RoleID

                Write-Debug $uri

                Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop
            }

            "RoleName" {

                $uri = "https://{0}/cb/api/v3/roles" -f $CBSession.Server

                Write-Debug $uri

                (Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop) | Where-Object { $_.name -like "*$RoleName*" }
            }
            Default { "Unknown Parameter Set $($PSCmdlet.ParameterSetName)" }
        }

        Write-Output $output
    }
    catch {
        Write-Error $_
    }
}
function Get-CBTrackerPermission {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$TrackerID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )

    try {
        $uri = "https://{0}/cb/api/v3/trackers/{1}/permissions" -f $CBSession.Server, $TrackerID

        Write-debug "uri: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        Write-Output $result
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker*is not found*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}
function Reset-CBItem {
<#
    .SYNOPSIS
    Resets fields of one or more tracker items in Codebeamer to a specified baseline or version.
 
    .DESCRIPTION
    The `Reset-CBItem` function restores selected fields of one or more tracker items to their values from a given baseline or version. You can specify which fields to reset, or reset all editable fields except for a set of uneditable fields. The function supports both baseline and version-based resets and handles computed fields appropriately.
 
    .PARAMETER ItemID
    The ID(s) of the item(s) to reset. Accepts an array of integers and supports pipeline input.
 
    .PARAMETER TrackerID
    The ID of the tracker containing the items to reset. Mandatory for both parameter sets.
 
    .PARAMETER ToBaseline
    The baseline ID to which the item(s) should be reset. Mandatory for the 'ToBaseLine' parameter set.
 
    .PARAMETER ToVersion
    The version number to which the item(s) should be reset. Mandatory for the 'ToVersion' parameter set.
 
    .PARAMETER Fields
    (Optional) An array of field names to reset. If not specified, all editable fields (except uneditable ones) are reset.
 
    .PARAMETER CBSession
    The session object containing server URL and headers. Mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
    Reset-CBItem -ItemID 12345 -TrackerID 67890 -ToBaseline 111 -CBSession $cbSession
 
    Resets all editable fields of item 12345 in tracker 67890 to their values from baseline 111.
 
    .EXAMPLE
    Reset-CBItem -ItemID 12345,12346 -TrackerID 67890 -ToVersion 2 -Fields "Summary","Status" -CBSession $cbSession
 
    Resets the "Summary" and "Status" fields of items 12345 and 12346 in tracker 67890 to their values from version 2.
 
    .NOTES
    - Computed fields are not reset and will be recalculated by Codebeamer.
    - Error handling provides feedback for missing fields, invalid tracker/item IDs, or inaccessible items.
    - Progress is displayed for long-running operations.
#>

    [CmdletBinding(DefaultParameterSetName = "ToBaseLine")]
    param (
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = "ToBaseLine")]
        [Parameter(Mandatory, ValueFromPipeline, Position = 0, ParameterSetName = "ToVersion")]
        [int[]]$ItemID,

        [Parameter(Mandatory, ParameterSetName = "ToBaseLine")]
        [Parameter(Mandatory, ParameterSetName = "ToVersion")]
        [int]$TrackerID,

        [Parameter(Mandatory, ParameterSetName = "ToBaseLine")]
        [int]$ToBaseline,

        [Parameter(Mandatory, ParameterSetName = "ToVersion")]
        [int]$ToVersion,

        [Parameter(ParameterSetName = "ToBaseLine")]
        [Parameter(ParameterSetName = "ToVersion")]
        [String[]]$Fields,

        [Parameter(Mandatory, ParameterSetName = "ToBaseLine")]
        [Parameter(Mandatory, ParameterSetName = "ToVersion")]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    begin {
        $uneditableFields = @("ID", "Tracker", "Submitted at", "Submitted by", "Modified at", "Closed at", "Modified by", "Attachments")

        try {
            $rawObjectList = New-Object 'System.Collections.Generic.List[psobject]'

            $ItemTemplate = (Get-CBTrackerChild -TrackerID $TrackerID -Size 1 -CBSession $CBSession).id

            Write-Debug "Template item ID: $ItemTemplate"

            $uriCopyTemplate = "https://{0}/cb/api/v3/items/{1}/fields" -f $CBSession.Server, $ItemTemplate
            Write-Debug "uriCopyTemplate: $uriCopyTemplate"
            $copyTemplate = Invoke-RestMethod -Uri $uriCopyTemplate -Method Get -Headers $CBSession.headers -ErrorAction Stop

            $uriTrackerfieldList = "https://{0}/cb/api/v3/trackers/{1}/fields" -f $CBSession.Server, $TrackerID
            Write-Debug "uriTrackerfieldList: $uriTrackerfieldList"
            $trackerFields = Invoke-RestMethod -Uri $uriTrackerfieldList -Method Get -Headers $CBSession.headers -ErrorAction Stop

            $listoftrackerFields = $trackerFields | Where-Object { $_.name -notin $uneditableFields }

            $listoftrackerFields = if ($Fields) {
                foreach ($field in $Fields) {
                    $listoftrackerFields | Where-Object { $_.name -eq $field }
                }
            }
            else {
                $listoftrackerFields
            }

            $percentage = (100 / $listoftrackerFields.length)
            $percentage = [Math]::Floor($percentage)
            $percent = 0

            $trackerFieldsMapping = foreach ($field in $listoftrackerFields) {

                $OuterLoopProgressParameters = @{
                    Activity        = 'Gathering Information about tracker {0}...' -f $TrackerID
                    Status          = " About... -> $($field.Name)"
                    PercentComplete = $percent += $percentage
                }

                Write-Progress @OuterLoopProgressParameters

                $uriFieldProperties = "https://{0}/cb/api/v3/trackers/{1}/fields/{2}" -f $CBSession.Server, $TrackerID, $field.id

                Write-Debug "uriFieldPropertie: $uriFieldProperties"

                Invoke-RestMethod -Uri $uriFieldProperties -Method Get -Headers $CBSession.headers -ErrorAction Stop
            }

            $computedFields = $trackerFieldsMapping | Where-Object { $_.formula }

            if ($computedFields) {

                $Message = "Computed Fields Found: $($computedFields.Name -join ", "). Value will be recalculated according to field Formula by Codebeamer"

                Write-Warning $message
            }

            $rawObject = @{
                trackerFieldsMapping = $trackerFieldsMapping
                versionedItem        = $null
                copyTemplate         = $copyTemplate
                ItemID               = 0
                computedFields       = $computedFields
                chosenFields         = $Fields
            }
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Field is not found.*" } {
                    Write-Error "Field ID: $ID most likely doesn't exist. Please recheck Field ID or Server."
                }
                { $_ -like "*Tracker is not found.*" } {
                    Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
                }
                Default { Write-Error $fullError }
            }
        }
    }

    process {
        try {
            $versionedItem = foreach ($item in $ItemID) {
                $messageActivity = 'Analyzing Item {0}...' -f $item
                Write-Progress -Activity $messageActivity

                Write-Debug "ParameterSetName: $($PSCmdlet.ParameterSetName)"

                $uriVersioned = switch ($PSCmdlet.ParameterSetName) {
                    "ToBaseLine" {
                        "https://{0}/cb/api/v3/items/{1}?{2}={3}" -f $CBSession.Server, $item, "baselineId", $ToBaseline
                        ; break
                    }
                    "ToVersion" {
                        "https://{0}/cb/api/v3/items/{1}?{2}={3}" -f $CBSession.Server, $item, "version", $ToVersion
                        ; break
                    }
                    default { Throw "Something Wrong with ParameterSetName $_" }
                }
                Write-Debug "uriVersioned: $uriVersioned"

                Invoke-RestMethod -Uri $uriVersioned -Method Get -Headers $CBSession.headers -ErrorAction Stop

            }

            $rawObject["versionedItem"] = $versionedItem
            $rawObject["ItemID"] = $item

            $rawObjectList.Add((New-Object -TypeName pscustomobject -Property $rawObject))
        }
        catch {
            $fullError = $_
            switch ($_.ErrorDetails.Message) {
                { $_ -like "*Not accessible tracker item*" } {
                    Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                }
                { $_ -like "*Tracker item is not found.*" } {
                    Write-Error "Version, Baseline or Item ID is incorrect: Item $itemID most likely doesn't exist. Please recheck Version or ItemID"
                }
                { $_ -like "*BaseLine*" } {
                    Write-Error ($fullError.ErrorDetails.Message | ConvertFrom-Json).message
                    exit 1
                }
                Default { Write-Error $fullError }
            }
        }
    }

    end {
        Write-Progress -Completed
        # updating Items
        foreach ($object in $rawObjectList) {

            $fieldValues = Convertto-CBObjectFieldList -ItemObject $object

            $body = [PSCustomObject]@{}
            $arrayList = New-Object System.Collections.ArrayList

            foreach ($fieldValue in $fieldValues) {
                if ($null -ne $fieldValue) {
                    $arrayList.Add($fieldValue) | Out-Null
                }
            }

            $body | Add-Member -NotePropertyName fieldValues -NotePropertyValue $arrayList
            $json = $body | ConvertTo-Json -Depth 20

            Write-Debug "body: $json"

            $uri = "https://{0}/cb/api/v3/items/{1}/fields?quietMode=false" -f $CBSession.Server, $object.ItemID

            Write-Debug "uri: $uri"

            $result = Invoke-RestMethod -Uri $uri -Method Put -Body $json -Headers $CBSession.headers -errorAction Stop

            Write-Output $result
        }
    }
}
function Convertto-CBObjectFieldList {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [PSCustomObject]$ItemObject
    )
    $result = New-Object 'System.Collections.Generic.List[psobject]'
    $legacyObject = foreach ($editableField in $ItemObject.Copytemplate.editableFields) {
        $ItemObject.trackerFieldsMapping | Where-Object { $_.name -eq $editableField.name } | Select-Object id, legacyRestName, name, trackerItemField
    }

    foreach ($legacy in $legacyObject) {

        foreach ($property in $ItemObject.versionedItem.psobject.Properties) {

            if ($legacy.legacyRestName -eq $property.name -or $legacy.trackerItemField -eq $property.name) {

                $field = $ItemObject.Copytemplate.editableFields | Where-Object { $_.name -eq $legacy.name }

                if ($field.psobject.Properties.name -contains "values") {
                    [array]$field.values = $property.value
                }

                if ($field.psobject.Properties.name -contains "value") {
                    $field.value = $property.value
                }

                if ($field.psobject.Properties.name -notcontains "value" -and $field.psobject.Properties.name -notcontains "values" -and $property.value ) {
                    Write-Debug "No Value Property on Field Object: $($field.name) but versioned Item has value $($property.value)"

                    $field | Add-member -NotePropertyName value -NotePropertyValue $property.value
                }

                Write-Debug "versioned field: $($field.name)"

                $result.add($field)
            }
        }
    }

    # powershell is wrongly parsing date so we need to iterate of custom fields to format it correctly
    foreach ($editableField in $ItemObject.versionedItem.customFields) {
        if ($editableField.type -eq "DateFieldValue" -and $null -ne $editableField.value) {
            $editableField.value = $editableField.value | Get-date -Format 'yyyy-MM-ddThh:mm:ss.fff'
        }

        Write-Debug "Custom Fields in Versioned editableField.name: $($editableField.name)"
        Write-Debug "Custom Fields in Versioned editableField.id: $($editableField.fieldId)"
        Write-Debug "Custom Fields in ItemObject.computedFields.id: $($ItemObject.computedFields.id)"
        #computed Fields cannot be edited so it has to be removed
        if ($editableField.fieldId -in $ItemObject.computedFields.id) {
            Write-Debug "Computed Field Found $($editableField.name)"

            $editableField = $null
        }
        $result.add($editableField)
    }

    # need to fake a field if on versioned item there are no significant change for me it means all needs to be reset,
    if ($result.Count -eq 0) {

        $fakeField = [PSCustomObject]@{
            Name = "Fake Field"
        }
        $result.add($fakeField)
    }

    if ($result.name) {

        $fieldsNotFound = (compare-Object -ReferenceObject $result.name -DifferenceObject $ItemObject.Copytemplate.editableFields.name).InputObject

        foreach ($notFound in $fieldsNotFound) {

            $notfoundfield = $ItemObject.Copytemplate.editableFields | Where-Object { $_.name -eq $notFound }

            if ($notfoundfield.psobject.Properties.name -contains "values") {
                [array]$notfoundfield.values = @()
            }

            if ($notfoundfield.psobject.Properties.name -contains "value") {
                $notfoundfield.value = ""

                if ($notfoundfield.type -eq "DateFieldValue") {
                    $notfoundfield = $notfoundfield | Select-Object -ExcludeProperty value
                }
            }
            Write-Debug "notfound : $($notfoundfield.name)"

            $result.add($notfoundfield)
        }
    }

    if ($ItemObject.chosenFields) {
        $chosenfieldlist = New-Object 'System.Collections.Generic.List[psobject]'

        Write-debug "Fields Choosen by User: $($ItemObject.chosenFields)"

        foreach ($fieldObject in $result) {
            if ($fieldObject.name -in $ItemObject.chosenFields) {
                Write-Debug "fieldObject: $fieldObject"

                $chosenfieldlist.Add($fieldObject )
            }
        }
        $result = $chosenfieldlist
    }

    Write-Output -InputObject $result
}
function Get-CBTrackerBaseLine {
    <#
    .SYNOPSIS
    Retrieves all baselines for a specified tracker from the Codebeamer server.
 
    .DESCRIPTION
    The `Get-CBTrackerBaseLine` function fetches the list of baselines associated with a given tracker ID in Codebeamer.
    It returns references to each baseline and provides information about the result set, such as page, page size, and total count.
 
    .PARAMETER TrackerID
    The ID of the tracker for which to retrieve baselines. This parameter is mandatory.
 
    .PARAMETER CBSession
    The session object containing server URL and headers. This parameter is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
    Get-CBTrackerBaseLine -TrackerID 12345 -CBSession $cbSession
 
    Retrieves all baselines for tracker ID 12345.
 
    .NOTES
    - Returns baseline references as provided by the Codebeamer REST API.
    - Writes informational output about the result set.
    - Handles errors for invalid tracker IDs.
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]$TrackerID,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [pscustomobject]$CBSession
    )
    try {
        $uri = "https://{0}/cb/api/v3/trackers/{1}/baselines" -f $CBSession.Server, $TrackerID

        Write-Debug -Message "uri: $uri"

        $result = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -ErrorAction Stop

        $result.references
        $messageData = @"
        Command Information:
        "Page: $($result.page), Page Size: $($result.pageSize), Total: $($result.total), Tricker Item ID: $($TrackerID)"
 
"@

        Write-Information -MessageData $messageData
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker is not found.*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}
function New-CBBaseline {
    <#
    .SYNOPSIS
    Creates a new baseline in the Codebeamer Server within a specified project and tracker.
 
    .DESCRIPTION
    The `New-CBBaseline` function establishes a new baseline within a given project, optionally associated with a tracker, in the Codebeamer Server.
    It leverages a RESTful API call to perform the operation, allowing users to specify various attributes for the baseline.
 
    .PARAMETER ProjectID
    Specifies the ID of the project where the baseline will be created.
    This parameter is mandatory.
 
    .PARAMETER TrackerID
    Indicates the ID of the tracker linked to the baseline, if applicable.
    This parameter is optional.
 
    .PARAMETER Name
    Represents the name of the new baseline.
    This parameter is mandatory.
 
    .PARAMETER Description
    Provides a description for the new baseline.
    This parameter is mandatory.
 
    .PARAMETER CBSession
    Represents the CB Session object that includes necessary connection details such as server URL and headers.
    This parameter is mandatory and can be accessed using the alias 'cbs'.
 
    .EXAMPLE
    Creates Basline for whole Project
 
    New-CBBaseline -ProjectID 5678 -Name "NewBaseline" -Description "Initial Baseline for Project" -CBSession $cbSession
 
    .EXAMPLE
    This example creates a baseline linked to tracker ID 1234 in project ID 5678, facilitating focused management within the tracker context.
 
    New-CBBaseline -ProjectID 5678 -TrackerID 1234 -Name "NewBaselineWithTracker" -Description "Baseline linked to a tracker" -CBSession $cbSession
 
    .NOTES
    - The function supports ShouldProcess, providing confirmation before the creation operation.
    - Debug information provides insights into URI construction and JSON payload for transparency and troubleshooting.
    - Error handling accommodates common issues like duplicate baselines, invalid tracker IDs, and project existence, ensuring clear feedback.
 
#>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory, Position = 0)]
        [int]$ProjectID,

        [Parameter(Position = 1)]
        [int]$TrackerID,

        [Parameter(Mandatory)]
        [string]$name,

        [Parameter(Mandatory)]
        [string]$Description,

        [Parameter(Mandatory)]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $basicinfo = @{
            description = $Description
            name        = $name
            project     = [PSCustomObject]@{ id = $ProjectID }
        }
        if ($TrackerID) {
            $tracker = [PSCustomObject]@{ id = $TrackerID }
            $basicinfo.add("tracker", $tracker)
        }
        $body = $basicinfo | ConvertTo-Json -Depth 10

        if ($PSCmdlet.ShouldProcess($CBSession.Server, "New Baseline will be created in Project ID: $ProjectID")) {
            $uri = "https://{0}/cb/api/v3/baselines" -f $CBSession.Server

            Write-Debug "uri: $uri"
            Write-Debug "body: $body"

            Invoke-RestMethod -Uri $uri -Method POST -Headers $CBSession.headers -Body $body -ErrorAction Stop
        }
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker is not found.*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            { $_ -like "*Baseline already exists*" } {

                $message = "{0} Please change the name: {1}" -f ($fullError.ErrorDetails.Message | ConvertFrom-Json).message, $name
                Write-Error $message
            }
            { $_ -like "*Project is not found*" } {
                Write-Error "Project ID: $ProjectID most likely doesn't exist. Please recheck Project ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}
function Register-CBSecretVault {
    <#
    .SYNOPSIS
    Registers and stores Codebeamer credentials in a secret vault within the local file system.
 
    .DESCRIPTION
    The `Register-CBSecretVault` function prompts users to input credentials for Codebeamer production and administrative access.
    These credentials are securely stored as JSON objects in the user's application data directory, facilitating future access while maintaining confidentiality.
 
    .PARAMETER None
    The function does not accept any input parameters. It relies on user interaction for credential collection.
 
    .EXAMPLE
    Register-CBSecretVault
 
    This example initiates the registration process, prompting the user to input credentials for Codebeamer production and administrative accounts, storing them securely.
 
    .NOTES
    - The function utilizes `Get-Credential` to prompt for and securely collect username and password information.
    - Secure strings are converted before storage, ensuring the passwords are not stored in plaintext.
    - Stored credentials are accessible from the JSON file created in the `%APPDATA%\pscodebeamer\cbVault.json` path.
    - The directory and file are created if they do not exist, ensuring a safe location for credential storage.
    - Future enhancements may include additional security measures, such as encryption for the storage file itself.
 
#>


    $info = Get-Credential -Message "Codebeamer Production"
    $production = $info | Select-Object UserName, @{name = "Password"; Expression = { ConvertFrom-SecureString $_.Password } }

    $info = Get-Credential -Message "Codebeamer Administrator"
    $Administration = $info | Select-Object UserName, @{name = "Password"; Expression = { ConvertFrom-SecureString $_.Password } }

    $Vault = @{
        CodebeamerProduction    = $production
        CodebeamerAdministrator = $Administration
    }

    $path = Split-Path -Path $env:APPDATA\pscodebeamer\cbVault.json

    switch (Test-path -Path $path) {
        $true {
            $Vault | ConvertTo-Json | Out-File -FilePath $path\cbVault.json -Force
            ; break
        }
        $false {
            $path = New-Item -Path $env:APPDATA -Name pscodebeamer -ItemType Directory | Resolve-Path
            $Vault | ConvertTo-Json | Out-File -FilePath $path\cbVault.json
            ; break
        }
    }
    Write-Output "Vault registered under $($path)\cbVault.json"
}
function Use-CBCredential {
<#
    .SYNOPSIS
    Retrieves stored Codebeamer credentials from the local secret vault.
 
    .DESCRIPTION
    The `Use-CBCredential` function loads Codebeamer credentials (production or administrator) from a secure vault stored in the user's AppData directory. It returns a PSCredential object for use in authentication with Codebeamer APIs. If the vault does not exist, it prompts the user for credentials.
 
    .PARAMETER CodebeamerAdministrator
    Retrieves the administrator credentials from the vault.
 
    .PARAMETER CodebeamerProduction
    Retrieves the production credentials from the vault.
 
    .PARAMETER asPlainText
    Returns the password as plain text instead of a secure string.
 
    .EXAMPLE
    Use-CBCredential -CodebeamerProduction
 
    Retrieves the production credentials as a PSCredential object.
 
    .EXAMPLE
    Use-CBCredential -CodebeamerAdministrator -asPlainText
 
    Retrieves the administrator credentials and returns the password as plain text.
 
    .NOTES
    - The function expects the credential vault to be registered using Register-CBSecretVault.
    - If the vault is missing, the user will be prompted for credentials.
    - Credentials are stored in `%APPDATA%\pscodebeamer\cbVault.json`.
#>

    param (
        [Parameter(ParameterSetName = "CodebeamerAdministrator")]
        [switch]$CodebeamerAdministrator,

        [Parameter(ParameterSetName = "CodebeamerProduction")]
        [switch]$CodebeamerProduction,

        [Parameter()]
        [switch]$asPlainText
    )
    $secretVault = Join-Path -Path $env:APPDATA -ChildPath pscodebeamer\cbVault.json

    Write-Debug "Vault:$($secretVault)"

    $credentials = Switch ((Test-Path -Path $secretVault) -eq $false ) {
        $true {
            Get-Credential -Message "please Enter Credentials"
        }
        $False {
            switch ($true) {
                {
                    $CodebeamerAdministrator.IsPresent
                } {
                    $credentials = Get-Content -Path $secretVault
                    | ConvertFrom-Json | Select-Object -ExpandProperty CodebeamerAdministrator
                    | Select-Object UserName, @{name = "Password" ; Expression = { Convertto-SecureString $_.Password } }
                    New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $credentials.UserName, $credentials.Password
                }
                {
                    $CodebeamerProduction.IsPresent
                } {
                    $credentials = Get-Content -Path $secretVault
                    | ConvertFrom-Json | Select-Object -ExpandProperty CodebeamerProduction
                    | Select-Object UserName, @{name = "Password"; Expression = { Convertto-SecureString $_.Password } }
                    New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $credentials.UserName, $credentials.Password
                }
            }
        }
    }
    if ($asPlainText.IsPresent) {
        $credentials | Select-Object UserName, @{Name = "Password"; Expression = { ConvertFrom-SecureString $_.Password -AsPlainText } }
    }
    else { $credentials }
}
function ConvertTo-CBChoiceField {
    [CmdletBinding(DefaultParameterSetName = "Field")]
    param (
        [Parameter(ParameterSetName = "Field")]
        [string[]]$Fields,

        [Parameter(ParameterSetName = "FieldWithValue")]
        [hashtable]$FieldWithValue,

        [Parameter(Mandatory, ParameterSetName = "Field")]
        [Parameter(Mandatory, ParameterSetName = "FieldWithValue")]
        [int]$TrackerID,

        [Parameter(ParameterSetName = "Field")]
        [Parameter(ParameterSetName = "FieldWithValue")]
        [switch]$DefaultValues,

        [Parameter(Mandatory, ParameterSetName = "Field")]
        [Parameter(Mandatory, ParameterSetName = "FieldWithValue")]
        [Alias("cbs")]
        [PSCustomObject]$CBSession
    )
    try {
        $fieldNames = [ordered]@{}
        $valueList = New-Object 'System.Collections.Generic.List[psobject]'
        $uri = "https://{0}/cb/api/v3/trackers/{1}/schema" -f $CBSession.Server, $TrackerID

        Write-Debug "uri: $uri"

        $trackerSchema = Invoke-RestMethod -Uri $uri -Method Get -Headers $CBSession.headers -errorAction Stop

        $fieldLabels = switch ($PSCmdlet.ParameterSetName) {
            "Field" { $Fields }
            "FieldWithValue" { $FieldWithValue.Keys }
            default { "Well something went worng" }
        }

        $result = foreach ($field in $fieldLabels) {

            $fieldProperties = $trackerSchema | Where-Object { $_.name -eq $field }

            if (-not $fieldProperties) {
                throw "Field $field does not exist in Tracker: $TrackerID"
            }

            switch ($fieldProperties) {
                { $_.valueModel -eq "NotSupportedFieldValue" } {

                    Write-Debug $_.name
                    Write-Debug $_.id

                    if ($_.name -eq "Parent") {
                        $type = "TrackerItemReference"
                    }
                    else {
                        $message = "Fields $($fieldProperties.name) value model is type of NotSupportedFieldValue and it will be skipped"
                        Write-Warning -Message $message
                    }
                    continue
                }

                { $_.valueModel -notlike "ChoiceFieldValue*" } {
                    $message = "Fields $($fieldProperties.name) value model is type of $($fieldProperties.valueModel) and it will be skipped"
                    Write-Warning -Message $message
                    continue
                }

                { $fieldProperties.type -eq "MemberField" } { $type = "UserReference" }
                Default { $type = $_.referenceType }
            }

            $valueList = if ($FieldWithValue) {
                foreach ($value in $FieldWithValue[$field]) {
                    [pscustomobject]@{
                        id   = $value
                        type = $type
                    }
                }
            }
            else {
                [array]@([pscustomobject]@{
                        id   = $value
                        type = $type
                    }
                )
            }

            $fieldNames["fieldId"] = $fieldProperties.id
            $fieldNames["name"] = $fieldProperties.name
            $fieldNames["values"] = $valueList
            $fieldNames["sharedFieldName"] = ""
            $fieldNames["type"] = "ChoiceFieldValue"

            New-Object -TypeName psobject -Property $fieldNames
        }
        Write-Output $result
    }
    catch {
        $fullError = $_
        switch ($_.ErrorDetails.Message) {
            { $_ -like "*Tracker is not found*" } {
                Write-Error "Tracker ID: $TrackerID most likely doesn't exist. Please recheck Tracker ID or Server."
            }
            Default { Write-Error $fullError }
        }
    }
}

$scriptBlock = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

    $config = Join-Path -Path $env:appDATA -ChildPath \pscodebeamer\config.json
    $request = ([System.IO.File]::ReadAllText($config) | ConvertFrom-Json).CBQLQuery | Where-Object -FilterScript { $_ -match $wordToComplete }

    foreach ( $Project in $request ) { New-CompletionResult -CompletionText $Project -ListItemText $Project }
}
Register-ArgumentCompleter -CommandName Invoke-CBQL -ParameterName cbQLString -ScriptBlock $scriptBlock