JSM.Insight.psm1

#region Private functions
function New-InsightHeaders {
    param (
        [string]$InsightCreds = $InsightCreds,
        [switch]$ExperimentalApi
    )
    Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

    $Headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
    $Headers.Add('content-type' , 'application/json')
    $Headers.Add('Authorization', 'Basic ' + $InsightCreds)

    if ($ExperimentalApi -eq $true) {
        $Headers.Add('X-ExperimentalApi', 'opt-in')
    }

    $Headers
}
#endregion

#region Public functions
function Find-InsightObject {
    [CmdletBinding()]
    param (
        [string]$IQL,
        [string]$objectTypeId,
        [int]$page = 1,
        [int]$resultsPerPage = 2000,
        [int]$orderByTypeAttrId,
        [ValidateSet(0,1)]
        [int]$asc = 1,
        [string]$objectId,
        [string]$objectSchemaId,
        [bool]$includeAttributes,
        [array]$attributesToDisplay,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {

        $RequestBody = @{
            'iql' = $iql
            'objectTypeId'   = $objectTypeId
            'resultsPerPage' = $resultsPerPage
            }
            if ($page) {
                $RequestBody.Add('page', $page)
            }
            if ($orderByTypeAttrId) {
                $RequestBody.Add('orderByTypeAttrId', $orderByTypeAttrId)
            }
            if ($asc) {
                $RequestBody.Add('asc', $asc)
            }
            if ($objectId) {
                $RequestBody.Add('objectId', $objectId)
            }
            if ($objectSchemaId) {
                $RequestBody.Add('objectSchemaId', $objectSchemaId)
            }
            if ($includeAttributes) {
                $RequestBody.Add('includeAttributes', $includeAttributes)
            }
            if ($attributesToDisplay ) {
                $RequestBody.Add('attributesToDisplay', $attributesToDisplay)
            }

        $RequestBody = $RequestBody | ConvertTo-Json -Depth 5

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/navlist/iql"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

Function Get-InsightCreds {
    [CmdletBinding()]
    [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')]
    param(
        [Parameter( Mandatory )]
        [ValidateNotNullOrEmpty()]
        [Alias('user')]
        [string]$Username,
        
        [Parameter( Mandatory )]
        [ValidateNotNullOrEmpty()]
        [Alias('pass')]
        [string]$Password
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
    }

    process {
        #Encode Creds
        $auth = $username + ':' + $password
        $Encoded = [System.Text.Encoding]::UTF8.GetBytes($auth)
        $authorizationInfo = [System.Convert]::ToBase64String($Encoded)
        $Script:InsightCreds = $authorizationInfo
    }

    end {
        $authorizationInfo
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# Custom Function to Get Object Type, Attributes, and All Objects
function Get-InsightFullObjectType {
    [CmdletBinding()]
    param (
        [string]$ObjectSchemaName,
        [string]$ObjectTypeName,
        [switch]$NoObjects
    )
    
    begin {
        Write-PSFMessage -Level Host -Message "Starting 'Get-InsightFullObjectType'" -Tag 'Get-InsightFullObjectType'

        $ObjectSchema = (Get-InsightObjectSchemaList).values | Where-Object { $_.name -eq $ObjectSchemaName }
        $ObjectSchemaObjectTypes = Get-InsightObjectSchemaObjectTypes -ID $ObjectSchema.id

        $JSMObjects = @()
        $objs = @()
        $page = 0

        class JSMexport {
            [string]$name
            [Object]$objectType
            [Object]$attributes
            [Object]$objects
        }
    }
    
    process {
        $e = [JSMexport]::New()
        $e.objectType = Get-InsightObjectType -ID $($ObjectSchemaObjectTypes | Where-Object { $_.name -eq $ObjectTypeName }).id
        $e.attributes = Get-InsightObjectTypeAttributes -ID $($ObjectSchemaObjectTypes | Where-Object { $_.name -eq $ObjectTypeName }).id
        #Loop through and return all objects. IncludeAttributes to get 'attributes and values' for the objects themselves
        
        if ($NoObjects -eq $false) {
            do {
                $page++
                Write-PSFMessage -Level Host -Message "Preforming 'Find-InsightObject' on page: $page" -Tag 'Get-InsightFullObjectType'
                $results = Find-InsightObject -objectSchemaId $ObjectSchema.id -objectTypeId $e.objectType.id -resultsPerPage 2000 -page $page -IQL ${objectType = "$ObjectTypeName"} -includeAttributes $true
                $objs += $results.objectEntries
            } until ( ( $page -eq $results.pageSize ) -or ( !($results.objectEntries) ) )
            $e.objects = $objs
        }
        
        $e.name = $e.objectType.name
        $JSMObjects += $e
    }
    
    end {
        Write-PSFMessage -Level Host -Message "Completed 'Get-InsightFullObjectType'" -Tag 'Get-InsightFullObjectType'
        $JSMObjects
    }
} 

# https://developer.atlassian.com/cloud/insight/rest/api-group-icon/#api-icon-id-get
function Get-InsightIcon {
    [CmdletBinding()]
    param (
        [String]$Version = "1",
        [string]$IconID = "global",
        [switch]$Full,
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        # Default is Global which will show all icons.
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/icon/$IconID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        if ($Full -eq $true) {
            $response
        }
        else {
            $response | Select id,name
        }

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-object/#api-object-id-get
function Get-InsightObject {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = '1',
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-object/#api-object-id-attributes-get
function Get-InsightObjectAttributes {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id/attributes"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-icon/#api-icon-id-get
function Get-InsightObjectByIQL {
    [CmdletBinding()]
    param (
        [String]$Version = "1",
        [string]$IQL,
        [int]$page,
        [int]$resultsPerPage = 25,
        [bool]$includeAttributes,
        [int]$includeAttributesDeep = 1,
        [bool]$includeTypeAttributes,
        [bool]$includeExtendedInfo,
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        $RequestBody = @{
            'resultsPerPage' = $resultsPerPage
            }
        if ($IQL) {
            $RequestBody.Add("iql",$iql )
        }
        if ($page) {
            $RequestBody.Add("page",$page )
        }
        if ($includeAttributes) {
            $RequestBody.Add("includeAttributes",$includeAttributes )
        }
        if ($includeAttributesDeep) {
            $RequestBody.Add("includeAttributesDeep",$includeAttributesDeep )
        }
        if ($includeTypeAttributes) {
            $RequestBody.Add("includeTypeAttributes",$includeTypeAttributes )
        }
        if ($includeExtendedInfo) {
            $RequestBody.Add("includeExtendedInfo",$includeExtendedInfo )
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
        Write-Verbose $RequestBody
    }
    
    process {
        # Default is Global which will show all icons.
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/iql/objects"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-objectconnectedtickets/#api-objectconnectedtickets-objectid-tickets-get
function Get-InsightObjectConnectedTickets {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectconnectedtickets/$id/tickets"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-object/#api-object-id-history-get
function Get-InsightObjectHistory {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id/history"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-object/#api-object-id-referenceinfo-get
function Get-InsightObjectReferenceInfo {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id/referenceinfo"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-objectschema/#api-objectschema-id-get
function Get-InsightObjectSchema {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = '1',
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Get-InsightObjectSchemaAttributes {
    [CmdletBinding()]
    param (
        [string]$ID,
        [bool]$onlyValueEditable = $False,
        [bool]$extended = $False,
        [string]$Query,
        [String]$Version = '1',
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $RequestBody = @{
            }
            if ($onlyValueEditable) {
                $RequestBody.Add('onlyValueEditable',$onlyValueEditable)
            }
            if ($extended) {
                $RequestBody.Add('extended',$extended)
            }
            if ($Query) {
                $RequestBody.Add('query',$Query)
            }
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/$id/attributes"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Get-InsightObjectSchemaList {
    [CmdletBinding()]
    param (
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/list"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Get-InsightObjectSchemaObjectTypes {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = '1',
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/$id/objecttypes/flat"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Get-InsightObjectType {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}



# API Docs need info on how to add Query parameters.
# https://developer.atlassian.com/cloud/insight/rest/api-group-objecttype/#api-objecttype-id-attributes-get

function Get-InsightObjectTypeAttributes {
    [CmdletBinding()]
    param (
        [string]$ID,
        [switch]$onlyValueEditable,
        [switch]$orderByName,
        [string]$query,
        [switch]$includeValuesExist,
        [switch]$excludeParentAttributes,
        [switch]$includeChildren,
        [switch]$orderByRequired,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/$id/attributes"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

#https://developer.atlassian.com/cloud/insight/rest/api-group-progress/#api-progress-category-imports-id-get
function Get-InsightProgressCatagoryImports {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/progress/category/imports/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-config/#api-config-statustype-get
function Get-InsightStatusTypeByID {
    [CmdletBinding()]
    param (
        [String]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype/$ID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-config/#api-config-statustype-get
function Get-InsightStatusTypes {
    [CmdletBinding()]
    param (
        [string]$objectSchemaId,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        if ($objectSchemaId) {
            $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype/?objectSchemaId=$objectSchemaId"
        }
        else {
            $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype/"
        }
    }
    
    end {
        Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
    }
}


function Get-InsightWorkspaceID {
    [CmdletBinding()]
    param (
        [string]$InsightServerUrl,
        [string]$InsightCreds = $InsightCreds
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders -ExperimentalApi
    }
    
    process {
        $Request = [System.UriBuilder]"$InsightServerUrl/rest/servicedeskapi/insight/workspace"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET

            $script:InsightWorkspaceID = $response.values.workspaceId
            $response.values.workspaceId
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
        } 
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Get-ObjectHash {
    param (
        [Parameter(ValueFromPipeline, mandatory = $true)]
        [object]$inputObject,

        [Parameter(ValueFromPipeline, mandatory = $false)]
        [ValidateSet(1, 2, 3, 4, 5)]
        [int]$Depth = 2
    )

    # Convert Object to JSON then String (string is required to get Hash)
    $inputObject = $inputObject | ConvertTo-Json -Depth $Depth | Out-String

    $stringAsStream = [System.IO.MemoryStream]::new()
    $writer = [System.IO.StreamWriter]::new($stringAsStream)
    $writer.write($inputObject)
    $writer.Flush()
    $stringAsStream.Position = 0
    $result = Get-FileHash -InputStream $stringAsStream -Algorithm MD5
    
    return $result.Hash
}

function Get-HostExternalMonitors {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        $Monitors = Get-CimInstance WmiMonitorID -Namespace root\wmi

        class Monitor {
            [string]$ManufacturerName
            [string]$UserFriendlyName
            [string]$SerialNumberID
            [string]$ObjectHash
        }
    }
    
    process {

        $ExternalMonitors = foreach ($Device in $Monitors) {

            if ($Device.UserFriendlyName) {
                $Monitor = [Monitor]::New()

                $Monitor.ManufacturerName = [String]::new($Device.ManufacturerName -ne 0)
                $Monitor.UserFriendlyName = [String]::new($Device.UserFriendlyName -ne 0)
                $Monitor.SerialNumberID = [String]::new($Device.SerialNumberID -ne 0) 
                $Monitor.ObjectHash = Get-ObjectHash -inputObject $Monitor -Depth 2

                $Monitor
            }
        }
    }
    
    end {
        return $ExternalMonitors
    }
}

function Get-HostOS {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class OS {
            [string]$Name
            [string]$Manufacturer
            [string]$OSArchitecture
            [string]$Version
            [string]$BuildNumber
            [string]$Codename
            [string]$Kernel
            [string]$ServicePackMajorVersion
            [string]$ServicePackMinorVersion
            [string]$ObjectHash
        }

        $Win32_OperatingSystem = Get-CimInstance Win32_OperatingSystem

    }
    
    process {
        
        $OS = [OS]::New()

        $OS.Name = $Win32_OperatingSystem.Caption
        $OS.Manufacturer = $Win32_OperatingSystem.Manufacturer
        $OS.OSArchitecture = $Win32_OperatingSystem.OSArchitecture
        $OS.BuildNumber = $Win32_OperatingSystem.BuildNumber
        #$OS.Codename =
        #$OS.Kernel =
        $OS.ServicePackMajorVersion = $Win32_OperatingSystem.ServicePackMajorVersion
        $OS.ServicePackMinorVersion = $Win32_OperatingSystem.ServicePackMinorVersion

        $OS.ObjectHash = Get-ObjectHash -inputObject $OS
    }
    
    end {
        return $OS
    }
}

function Get-HostCPUs {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class CPU {
            [string]$CPUType
            [string]$DeviceID
            [string]$NumberOfCores
            [string]$MaxClockSpeed
            [string]$ObjectHash
        }

        $Processors = Get-CimInstance Win32_Processor | Select-Object *
    }
    
    process {
        
        $CPUs = foreach ($Win32_Processor in $Processors) {
            
            $CPU = [CPU]::New()

            $CPU.CPUType = $Win32_Processor.Name
            $CPU.DeviceID = $Win32_Processor.DeviceID
            $CPU.NumberOfCores = $Win32_Processor.NumberOfCores
            $CPU.MaxClockSpeed = "$($Win32_Processor.MaxClockSpeed) MHz"

            $CPU.ObjectHash = (Get-ObjectHash -inputObject $CPU)

            $CPU
        }

    }
    
    end {
        $CPUs
    }
}

function Get-HostNetworkInterface {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class NetworkAdaptor {
            [string]$Name
            [string]$DeviceID
            [string]$MACaddress
            [string]$IP4
            [string]$IP6
            [string]$Subnet4
            [string]$Subnet6
            [string]$Gateway
            [string]$DHCP
            [string]$AddressSpace
            [string]$ObjectHash
            [string]$HostObjectHash
            [string]$DeviceObjectHash
            [string]$VirtualGuestObjectHash
        }

        $NetworkAdapterConfiguration = Get-CimInstance Win32_NetworkAdapterConfiguration -Property * | Where-Object { ( $_.IPEnabled -eq 'true' ) -and ( $_.Description -notlike '*Virtual*' ) }
    }
    
    process {

        $NetworkAdaptors = foreach ($Adaptor in $NetworkAdapterConfiguration) {

            $NetworkAdaptor = [NetworkAdaptor]::New()

            $NetworkAdaptor.Name = ($Adaptor.IPAddress[0])
            #$NetworkAdaptor.DeviceID =
            $NetworkAdaptor.MACaddress = ($Adaptor.MACAddress)
            $NetworkAdaptor.IP4 = ($Adaptor.IPAddress[0])
            $NetworkAdaptor.IP6 = ($Adaptor.IPAddress[1])
            $NetworkAdaptor.Subnet4 = ($Adaptor.IPSubnet)
            #$NetworkAdaptor.Subnet6 = $Adaptor.IPSubnet
            $NetworkAdaptor.Gateway = ($Adaptor.DefaultIPGateway)
            $NetworkAdaptor.DHCP = ($Adaptor.DHCPServer)
            # $NetworkAdaptor.AddressSpace = $Adaptor


            $NetworkAdaptor.ObjectHash = (Get-ObjectHash -inputObject $NetworkAdaptor)

            #$NetworkAdaptor.HostObjectHash = $Adaptor
            #$NetworkAdaptor.DeviceObjectHash = $Adaptor
            #$NINetworkAdaptorC.VirtualGuestObjectHash = $Adaptor

            $NetworkAdaptor
        }
    }
    
    end {
        $NetworkAdaptors
    }
}

function Get-HostStorageDevices {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class Storage {
            [string]$Name
            [string]$Status
            [string]$DeviceID
            [string]$SizeGB
            [string]$SerialNumber
            [string]$FirmwareRevision
            [string]$InterfaceType
            [string]$Manufacturer
            [string]$MediaType
            [string]$Model
            [string]$ReferencedFileSystems
            [string]$ObjectHash
        }

        # $Win32_DiskDrive = Get-CimInstance Win32_DiskDrive | Where-Object { $_.InterfaceType -ne 'USB' } | Select-Object *
        $AllDisks = Get-Disk | Where-Object { $_.BusType -ne 'USB' } | Select-Object *
    }

    process {
        
        $Disks = foreach ($DiskDrive in $AllDisks) {
            
            $Storage = [Storage]::New()

            $Storage.name = $DiskDrive.FriendlyName
            $Storage.status = $DiskDrive.OperationalStatus
            $Storage.DeviceID = $DiskDrive.UniqueId
            #$Storage.Description = $DiskDrive.Caption
            $Storage.SizeGB = [Math]::Round($DiskDrive.Size / 1GB)
            $Storage.SerialNumber = $DiskDrive.SerialNumber
            $Storage.FirmwareRevision = $DiskDrive.FirmwareVersion
            $Storage.InterfaceType = $DiskDrive.BusType
            $Storage.Manufacturer = $DiskDrive.Manufacturer
            $Storage.MediaType = $DiskDrive.MediaType
            $Storage.Model = $DiskDrive.Model
            #$Storage.ReferencedFileSystems = $DiskDrive.
            $Storage.ObjectHash = Get-ObjectHash -inputObject $Storage

            $Storage

        }

    }
    
    end {
        return $Disks
    }
}

function Get-Hypervisor {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class HyperV {
            [string]$PhysicalHostName
            [string]$PhysicalHostNameFullyQualified
            [string]$HostingSystemOsMajor
            [string]$VirtualMachineName
            #[array]$VMs
        }
    }
    
    process {

        $HyperV = [HyperV]::New()

        if (Test-Path 'HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters') {
            
            $Guest_Parameters = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters\' -ErrorAction SilentlyContinue

            $HyperV.VirtualMachineName = $Guest_Parameters | Select-Object VirtualMachineName
            $HyperV.PhysicalHostName = $Guest_Parameters | Select-Object PhysicalHostName
            $HyperV.PhysicalHostNameFullyQualified = $Guest_Parameters | Select-Object PhysicalHostNameFullyQualified
            $HyperV.HostingSystemOsMajor = $Guest_Parameters | Select-Object HostingSystemOsMajor

        }
    }
    
    end {
        $HyperV
    }
}

function Get-HostPrinter {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class Printer {
            [string]$name
            [string]$ServerName
            [string]$PortName
            [string]$Location
            [string]$ObjectHash
        }

        $Win32_Printer = Get-CimInstance Win32_Printer | Select-Object * | Where-Object { $_.name -notlike '*Onenote*' }
    }
    
    process {

        $Printers = foreach ($p in $Win32_Printer) {
            
            $Printer = [Printer]::New()

            if ($p.name -like '\\*') {
                $Printer.Name = $p.name.split('\') | Select-Object -l 1
            }
            else {
                $Printer.Name = $p.name
            }

            if ($p.ServerName -like '\\*') {
                $Printer.ServerName = $p.ServerName.split('\') | Select-Object -l 1
            }
            else {
                $Printer.ServerName = $p.ServerName
            }

            $Printer.Location = $p.Location
            $Printer.PortName = $p.PortName

            $Printer.ObjectHash = Get-ObjectHash -inputObject $Printer
            $Printer
        }
    }
    
    end {
        $Printers
    }
}

function Get-HostInfo {
    [CmdletBinding()]
    param (
        
    )
    
    begin {
        class HostInfo {
            [string]$Hostname
            [string]$SAMAccountName
            [string]$Domain
            [string]$Status
            [string]$FQDN
            [datetime]$LastBootUpTime
            [array]$Hypervisor
            [string]$SystemUpTime
            [string]$Timezone
            [string]$RamGB
            [string]$Model
            [string]$SerialNumber
            [string]$UUID
            [string]$Vendor
            [array]$ExternalMonitors
            [string]$LastLoggedOnUserSID
            [array]$Windows_OS
            [array]$Printer
            [array]$Storage
            [string]$Windows_ProductKey
            [string]$CPUcount
            [array]$CPUs
            [array]$NetworkInterfaces
            [array]$FileSystemsLink
            [string]$VM_Host
            [string]$VM_name
            [string]$ObjectHash
        }
    }
    
    process {

        $HostInfo = [HostInfo]::New()

        # WMI calls (once only). Maybe this could be moved to it's own function..
        $Win32_OperatingSystem = Get-CimInstance Win32_OperatingSystem
        $Win32_ComputerSystem = Get-CimInstance Win32_ComputerSystem
        $Win32_TimeZone = Get-CimInstance Win32_TimeZone
        
        $SoftwareLicensingService = Get-CimInstance SoftwareLicensingService
        $Win32_PhysicalMemory = Get-CimInstance Win32_PhysicalMemory
        $Win32_ComputerSystemProduct = Get-CimInstance Win32_ComputerSystemProduct
        $win32_bios = Get-CimInstance win32_bios

        # Build HostInfo Object
        $Hostinfo.Hostname = $env:computername
        $HostInfo.FQDN = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname
        $HostInfo.Model = $Win32_ComputerSystem.Model
        $HostInfo.Vendor = $win32_bios.Manufacturer
        $HostInfo.SerialNumber = $win32_bios.SerialNumber
        $HostInfo.LastBootUpTime = $Win32_OperatingSystem.LastBootUpTime
        $systemUpTime = (Get-Date) - (Get-Date $Win32_OperatingSystem.LastBootUpTime) 
        $HostInfo.SystemUpTime = "$($systemUpTime.Days):$($systemUpTime.Hours):$($systemUpTime.Minutes):$($systemUpTime.Seconds)"
        $Hostinfo.SAMAccountName = $Win32_ComputerSystem.username
        $HostInfo.LastLoggedOnUserSID = (Get-ItemProperty -Path 'HKLM:\Software\Microsoft\windows\currentVersion\Authentication\LogonUI' -Name LastLoggedOnUserSid | Select-Object -ExpandProperty LastLoggedOnUserSid)
        $Hostinfo.domain = $Win32_ComputerSystem.domain
        $Hostinfo.Timezone = $Win32_TimeZone.StandardName
        $HostInfo.RamGB = "$(($Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb) GB"
        $HostInfo.UUID = $Win32_ComputerSystemProduct.UUID
        #Links
        
        $HostInfo.CPUs = Get-HostCPUs
        $HostInfo.CPUcount = $($HostInfo.CPUs).count
        $HostInfo.Storage = Get-HostStorageDevices
        $Hostinfo.Hypervisor = Get-Hypervisor
        $Hostinfo.NetworkInterfaces = Get-HostNetworkInterface
        $Hostinfo.Windows_OS = Get-HostOS
        # Embedded Windows Key (uefi) may not match one in windows.
        $Hostinfo.Windows_ProductKey = $SoftwareLicensingService.OA3xOriginalProductKey
        
        # Only run if workstation (1 = Workstation, 2 = Domain Controller, 3 = Server)
        if ($Win32_OperatingSystem.ProductType -eq 1) {
            $Hostinfo.Printer = Get-HostPrinter
            $HostInfo.ExternalMonitors = Get-HostExternalMonitors
        }

        $HostInfo.ObjectHash = Get-ObjectHash -inputObject $HostInfo
    }
    
    end {
        $HostInfo | ConvertTo-Json -Depth 20
    }
}

# Suggest writing to JSON and using another script to use main module and push in to jira.

function New-InsightAttributeArray {
    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true,valuefrompipelinebypropertyname = $true)]
        [int]$AttributeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true,valuefrompipelinebypropertyname = $true)]
        [String[]]$AttributeValues
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

        $values = New-Object System.Collections.ArrayList 
    }
    
    process {
        $AttributeValues | ForEach-Object {
            $values.Add(@{'value' = $_}) | Out-Null
        }        
        $Attribute = @{
            'objectTypeAttributeId' = $AttributeId
            'objectAttributeValues'   = @($values)
            }
    }

    end {
        Write-Output $Attribute
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
        }
}



function New-InsightObject {
    [CmdletBinding()]
    param (
        [string]$objectTypeId,
        [array]$attributesArray,
        [Bool]$hasAvatar,
        [string]$avatarUUID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            'attributes'   = @($attributesArray)
            }

        $RequestBody = $RequestBody | ConvertTo-Json -Depth 5

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/create"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function New-InsightObjectSchema {
    [CmdletBinding()]
    param (
        [string]$Name,
        [string]$objectSchemaKey,
        [string]$Description,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $RequestBody = @{
            'name' = $Name
            'objectSchemaKey'   = $objectSchemaKey
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/create"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function New-InsightObjectType {
    [CmdletBinding()]
    param (
        [string]$name,
        [string]$description,
        [string]$iconID,
        [string]$ObjectSchemaID,
        [string]$ParentObjectTypeID,
        [bool]$Inherited,
        [bool]$AbstractObjectType,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"

        $Headers = New-InsightHeaders

        $RequestBody = @{
            'name' = $Name
            'iconId'   = $iconID
            'objectSchemaId'   = $objectSchemaId
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($parentObjectTypeId) {
                $RequestBody.Add('parentObjectTypeId', $parentObjectTypeId)
            }
            if ($Inherited -eq $true) {
                $RequestBody.Add('inherited', $Inherited)
            }
            if ($AbstractObjectType -eq $true) {
                $RequestBody.Add('abstractObjectType', $AbstractObjectType)
            }

        $RequestBody = ConvertTo-Json $RequestBody -Depth 1

    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/create"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function New-InsightObjectTypeAttribute {
    [CmdletBinding()]
    param (
        [string]$ObjectTypeId,
        [string]$Name,
        [string]$Label,
        [string]$Description,
        [ValidateSet("Default","Object Reference","User","Group","Status")]
        [string]$Type,
        [ValidateSet("None","Text","Integer","Boolean","Double","Date","Time","DateTime","URL","Email","TextArea","Select","IP Address")]
        [string]$defaultTypeId,
        [string]$typeValue,
        [array]$typeValueMulti,
        [string]$additionalValue,
        [int]$minimumCardinality,
        [int]$maximumCardinality,
        [string]$suffix,
        [bool]$includeChildObjectTypes,
        [bool]$hidden,
        [bool]$uniqueAttribute,
        [bool]$summable,
        [string]$regexValidation,
        [string]$iql,
        [string]$options,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        $ConvertedTypeID = switch ($Type) {
            "Default" { 0 }
            "Object Reference" { 1 }
            "User" { 2 }
            "Group" { 4 }
            "Status" { 7 }
        }

        $ConvertedDefaultTypeID = switch ($defaultTypeId) {
            "None" { -1 }
            "Text" { 0 }
            "Integer" { 1 }
            "Boolean" { 2 }
            "Double" { 3 }
            "Date" { 4 }
            "Time" { 5 }
            "DateTime" { 6 }
            "URL" { 7 }
            "Email" { 8 }
            "TextArea" { 9 }
            "Select" { 10 }
            "IP Address" { 11 }
        }


        $RequestBody = @{
            'name' = $Name
            'type'   = $ConvertedTypeID
            }
            if ($Label) {
                $RequestBody.Add('label', [System.Convert]::ToBoolean($Label) )
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($defaultTypeId) {
                $RequestBody.Add('defaultTypeId', $ConvertedDefaultTypeID)
            }
            if ($typeValue) {
                $RequestBody.Add('typeValue', $typeValue)
            }
            if ($typeValueMulti) {
                $RequestBody.Add('typeValueMulti', $typeValueMulti)
            }
            if ($additionalValue) {
                $RequestBody.Add('additionalValue', $additionalValue)
            }
            if ($minimumCardinality) {
                $RequestBody.Add('minimumCardinality', $minimumCardinality)
            }
            if ($maximumCardinality) {
                $RequestBody.Add('maximumCardinality', $maximumCardinality)
            }
            if ($suffix) {
                $RequestBody.Add('suffix', $suffix)
            }
            if ($includeChildObjectTypes  -eq $true) {
                $RequestBody.Add('includeChildObjectTypes', [System.Convert]::ToBoolean($includeChildObjectTypes) )
            }
            if ($hidden -eq $true) {
                $RequestBody.Add('hidden', [System.Convert]::ToBoolean($hidden) )
            }
            if ($uniqueAttribute -eq $true) {
                $RequestBody.Add('uniqueAttribute', [System.Convert]::ToBoolean($uniqueAttribute) )
            }
            if ($summable -eq $true) {
                $RequestBody.Add('summable', [System.Convert]::ToBoolean($summable) )
            }
            if ($regexValidation) {
                $RequestBody.Add('regexValidation', $regexValidation)
            }
            if ($iql) {
                $RequestBody.Add('iql', $iql)
            }
            if ($options) {
                $RequestBody.Add('options', $options)
            }

        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
        $RequestBody
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttypeattribute/$ObjectTypeId"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-config/#api-config-statustype-post
function New-InsightStatusType {
    [CmdletBinding()]
    param (
        [String]$Name,
        [String]$Description,
        [ValidateSet("InActive\Red","Active\Green","Pending\Yellow")]
        [String]$Category,
        [String]$objectSchemaId,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        switch ($Category) {
            "InActive\Red" { $CategoryID = 0 }
            "Active\Green" { $CategoryID = 1 }
            "Pending\Yellow" { $CategoryID = 2 }
        }

        $RequestBody = @{
            'name' = $Name
            'category'   = $CategoryID
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($objectSchemaId) {
                $RequestBody.Add('objectSchemaId', $objectSchemaId)
            }
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Remove-InsightObject {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Remove-InsightObjectSchema {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = '1',
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method DELETE
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Remove-InsightObjectType {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Remove-InsightObjectTypeAttribute {
    [CmdletBinding()]
    param (
        [string]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttypeattribute/$ID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-config/#api-config-statustype-get
function Remove-InsightStatusType {
    [CmdletBinding()]
    param (
        [String]$ID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype/$ID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Set-InsightObject {
    [CmdletBinding()]
    param (
        [string]$ID,
        [string]$objectTypeId,
        [array]$attributesArray,
        [Bool]$hasAvatar,
        [string]$avatarUUID,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            'attributes'   = @($attributesArray)
            }

        $RequestBody = $RequestBody | ConvertTo-Json -Depth 5

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/object/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method PUT
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Set-InsightObjectPosition {
    [CmdletBinding()]
    param (
        [string]$ID,
        [string]$toObjectTypeId,
        [int]$position,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {

        $RequestBody = @{
            'position' = $position
            }
            if ($toObjectTypeId) {
                $RequestBody.Add('toObjectTypeId', $toObjectTypeId)
            }

        $RequestBody = ConvertTo-Json $RequestBody -Depth 1

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/$id/position"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Set-InsightObjectSchema {
    [CmdletBinding()]
    param (
        [string]$ID,
        [string]$Name,
        [string]$objectSchemaKey,
        [string]$Description,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders
    }
    
    process {
        $RequestBody = @{
            'name' = $Name
            'objectSchemaKey'   = $objectSchemaKey
            }
            if ($Description) {
                $RequestBody.Add('description',$Description)
            }
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1

        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objectschema/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method POST
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response
        
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Set-InsightObjectType {
    [CmdletBinding()]
    param (
        [string]$ID,
        [string]$name,
        [string]$description,
        [string]$iconID,
        [string]$ObjectSchemaID,
        [string]$ParentObjectTypeID,
        [bool]$Inherited,
        [string]$AbstractObjectType,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        $RequestBody = @{
            'name' = $Name
            'iconID'   = $iconID
            'objectSchemaId'   = $objectSchemaId
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($parentObjectTypeId) {
                $RequestBody.Add('parentObjectTypeId', $parentObjectTypeId)
            }
            if ($Inherited) {
                $RequestBody.Add('inherited', $Inherited)
            }
            if ($AbstractObjectType) {
                $RequestBody.Add('abstractObjectType', $AbstractObjectType)
            }

        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttype/$id"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method PUT
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}


function Set-InsightObjectTypeAttribute {
    [CmdletBinding()]
    param (
        [string]$ID,
        [string]$ObjectTypeId,
        [string]$Name,
        [string]$Label,
        [string]$Description,
        [ValidateSet("Default","Object Reference","User","Group","Status")]
        [string]$Type,
        [ValidateSet("None","Text","Integer","Boolean","Double","Date","Time","DateTime","URL","Email","TextArea","Select","IP Address")]
        [string]$defaultTypeId,
        [string]$typeValue,
        [array]$typeValueMulti,
        [string]$additionalValue,
        [int]$minimumCardinality,
        [int]$maximumCardinality,
        [string]$suffix,
        [bool]$includeChildObjectTypes,
        [bool]$hidden,
        [bool]$uniqueAttribute,
        [bool]$summable,
        [string]$regexValidation,
        [string]$iql,
        [string]$options,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        $ConvertedType = switch ($Type) {
            "Default" { 0 }
            "Object Reference" { 1 }
            "User" { 2 }
            "Group" { 4 }
            "Status" { 7 }
        }

        $ConvertedTypeID = switch ($defaultTypeId) {
            "None" { -1 }
            "Text" { 0 }
            "Integer" { 1 }
            "Boolean" { 2 }
            "Double" { 3 }
            "Date" { 4 }
            "Time" { 5 }
            "DateTime" { 6 }
            "URL" { 7 }
            "Email" { 8 }
            "TextArea" { 9 }
            "Select" { 10 }
            "IP Address" { 11 }
        }


        $RequestBody = @{
            'name' = $Name
            'type'   = $ConvertedType
            }
            if ($Label) {
                $RequestBody.Add('label', $Label)
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($ConvertedTypeID) {
                $RequestBody.Add('defaultTypeId', $ConvertedTypeID)
            }
            if ($typeValue) {
                $RequestBody.Add('typeValue', $typeValue)
            }
            if ($typeValueMulti) {
                $RequestBody.Add('typeValueMulti', $typeValueMulti)
            }
            if ($additionalValue) {
                $RequestBody.Add('additionalValue', $additionalValue)
            }
            if ($minimumCardinality) {
                $RequestBody.Add('minimumCardinality', $minimumCardinality)
            }
            if ($maximumCardinality) {
                $RequestBody.Add('maximumCardinality', $maximumCardinality)
            }
            if ($suffix) {
                $RequestBody.Add('suffix', $suffix)
            }
            if ($includeChildObjectTypes  -eq $true) {
                $RequestBody.Add('includeChildObjectTypes', $includeChildObjectTypes)
            }
            if ($hidden -eq $true) {
                $RequestBody.Add('hidden', $hidden)
            }
            if ($uniqueAttribute -eq $true) {
                $RequestBody.Add('uniqueAttribute', $uniqueAttribute)
            }
            if ($summable -eq $true) {
                $RequestBody.Add('summable', $summable)
            }
            if ($regexValidation) {
                $RequestBody.Add('regexValidation', $regexValidation)
            }
            if ($iql) {
                $RequestBody.Add('iql', $iql)
            }
            if ($options) {
                $RequestBody.Add('options', $options)
            }

        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/objecttypeattribute/$ObjectTypeId/$ID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -body $RequestBody -Headers $headers -Method PUT
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}

# https://developer.atlassian.com/cloud/insight/rest/api-group-config/#api-config-statustype-id-put
function Set-InsightStatusType {
    [CmdletBinding()]
    param (
        [String]$ID,
        [String]$Name,
        [String]$Description,
        [ValidateSet("InActive\Red","Active\Green","Pending\Yellow")]
        [String]$Category,
        [String]$objectSchemaId,
        [String]$Version = "1",
        [string]$InsightCreds = $InsightCreds,
        [string]$InsightWorkspaceID = $InsightWorkspaceID
    )
    
    begin {
        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function started"
        $Headers = New-InsightHeaders

        switch ($Category) {
            "InActive\Red" { $CategoryID = 0 }
            "Active\Green" { $CategoryID = 1 }
            "Pending\Yellow" { $CategoryID = 2 }
        }

        $RequestBody = @{
            'name' = $Name
            'category'   = $CategoryID
            }
            if ($Description) {
                $RequestBody.Add('description', $Description)
            }
            if ($objectSchemaId) {
                $RequestBody.Add('objectSchemaId', $objectSchemaId)
            }
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    process {
        $Request = [System.UriBuilder]"https://api.atlassian.com/jsm/insight/workspace/$InsightWorkspaceID/v$Version/config/statustype/$ID"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Body $RequestBody -Headers $headers -Method PUT
        }
        catch {
            Write-Verbose "[$($MyInvocation.MyCommand.Name)] Failed"
            Write-Error -ErrorRecord $_
        } 

        $response

        Write-Verbose "[$($MyInvocation.MyCommand.Name)] Complete"
    }
}
#endregion