PSInsight.psm1

#region Private functions
function New-InsightHeaders {
<#

.SYNOPSIS
Generate Insight headers.
.EXAMPLE
$Headers = New-InsightHeaders -InsightApiKey $InsightApiKey
.OUTPUTS
Generic dictionary.

#>

    param (
        [Alias('ApiKey')]
        [string]$InsightApiKey
    )

    Write-Verbose 'Generating Headers'
    $Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $Headers.Add('content-type' , 'application/json')
    $Headers.Add('authorization', 'bearer ' + $InsightApiKey)

    Write-Output $Headers
}
#endregion

#region Public functions
function Get-InsightObjectSchema {
    <#

.SYNOPSIS
Resource to find object schemas in Insight for a specific object schema. The object schemas are responded in a list.

.DESCRIPTION
Resource to find object schemas in Insight for a specific object schema. The object schemas are responded in a list.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 3
name : MyObjectSchema
objectSchemaKey : MOS
status : Ok
description : Object Schema
created : 2020-09-16T00:50:30.919Z
updated : 2020-09-16T01:56:33.430Z
objectCount : 0
objectTypeCount : 1

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+schema

.EXAMPLE
Get-InsightObjectSchema -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objectschema/list"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }        

        If (!($response.objectschemas)) {
            # Throw error so that catch block in script is triggered
            throw "API call successful but no object schemas found on server"
        }
        Else {
            If($response.objectschemas){
                #Returns multiple schemas
                $response.objectschemas
            }
            else{
                #Returns single schema
                $response
            }
        }
    }
}

function New-InsightObjectSchema {
    <#

.SYNOPSIS
Resource to create an object schema in Insight.

.DESCRIPTION
Resource to create an object schema in Insight.

.PARAMETER Name
The object schema name.

.PARAMETER ObjectSchemaKey
The object schema key.

.PARAMETER Description
The object schema description.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : CMDB
objectSchemaKey : ABC
status : Ok
description : My Object Schema
created : 2020-09-16T00:22:31.948Z
updated : 2020-09-16T00:22:31.963Z
objectCount : 0
objectTypeCount : 0

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+schema

.EXAMPLE
New-InsightObjectSchema -Name "MyObjectSchema" -ObjectSchemaKey "NAS" -Description "My New Object Schema" -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ObjectSchemaKey,

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

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objectschema/create"

        $RequestBody = @{
            'name'              = $Name
            'objectSchemaKey'   = $ObjectSchemaKey
            }
            $RequestBody.Add('description',$Description)
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method POST
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}

function Remove-InsightObjectSchema {
    <#

.SYNOPSIS
Resource to delete an object schema in Insight.

.DESCRIPTION
Resource to delete an object schema in Insight.

.PARAMETER ID
The object schema ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : CMDB
objectSchemaKey : ABC
status : Ok
description : My Object Schema
created : 2020-09-16T00:22:31.948Z
updated : 2020-09-16T00:22:31.963Z
objectCount : 0
objectTypeCount : 0

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+schema

.EXAMPLE
Remove-InsightObjectSchema -ID 1 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objectschema/$($ID)"

    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method Delete
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}

function Set-InsightObjectSchema {
    <#

.SYNOPSIS
Resource to update an object schema in Insight.

.DESCRIPTION
Resource to update an object schema in Insight.

.PARAMETER ID
The id of the schema.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : MyObjectSchema
objectSchemaKey : MOS
status : Ok
description : My New Object Schema - Updated
created : 2020-09-16T00:22:31.948Z
updated : 2020-09-16T00:22:31.963Z
objectCount : 0
objectTypeCount : 0

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+schema

.EXAMPLE
Set-InsightObjectSchema -ID 3 -Name "MyObjectSchema" -ObjectSchemaKey "MOS" -Description "My New Object Schema - Updated" -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ObjectSchemaKey,

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

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objectschema/$($ID)"

        $RequestBody = @{
            'name'              = $Name
            'objectSchemaKey'   = $ObjectSchemaKey
            }
            If($Description){
            $RequestBody.Add('description',$Description)
            }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method PUT
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}

function Get-InsightStatuses {
<#

.SYNOPSIS
Resource to load a status in Insight.

.DESCRIPTION
Resource to load a status in Insight.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id name description category
-- ---- ----------- --------
 1 Action Needed 2
 2 Active 1
 3 Closed 0
 4 In Service 2
 5 Running 1
 6 Stopped 0
 7 Support Requested 2

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Statuses

.EXAMPLE
Get-InsightObjectTypes -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/config/statustype"
    }
    
    end {
        try {
                $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
            }
            catch {
                Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
            } 

            $response
    }
}

function New-InsightStatuses {
    <#

.SYNOPSIS
Resource to create a status in Insight.

.DESCRIPTION
Resource to create a status in Insight.

.PARAMETER Name
The Status Name.

.PARAMETER Description
The Status Description.

.PARAMETER Category
The status Category.

.PARAMETER InsightApiKey
The Api Secret.

.OUTPUTS
id name description category
-- ---- ----------- --------
 8 My New Status Sample Status 1

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Statuses

.EXAMPLE
New-InsightStatuses -Name "My New Status" -Description "Sample Status" -category Active -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Description,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [Validateset("Inactive","Active","Pending")]
        [String]$category,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey

        switch ($category) {
            "Inactive" { $CategoryID = 0 }
            "Active" { $CategoryID = 1 }
            "Pending" { $CategoryID = 2 }
}
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/config/statustype"

        $RequestBody = @{
            'name'           = $Name
            'description'    = $Description
            'category'       = $CategoryID
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method POST
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

function Remove-InsightObjectTypes {
    <#

.SYNOPSIS
Resource to delete a status in Insight.

.DESCRIPTION
Resource to delete a status in Insight.

.PARAMETER ID
The status ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
No output from API

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Statuses

.EXAMPLE
Remove-InsightObjectTypes -ID 8 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/config/statustype/$($ID)"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}


function Set-InsightStatuses {
    <#

.SYNOPSIS
Resource to update a status in Insight.

.DESCRIPTION
Resource to update a status in Insight.

.PARAMETER ID
The status ID.

.PARAMETER Name
The status name.

.PARAMETER Description
The status description

.PARAMETER Category
The status category.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id name description category
-- ---- ----------- --------
 8 My New Status Sample Status - Updated 1

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Statuses

.EXAMPLE
Set-InsightStatuses -ID 8 -Name "My New Status" -Description "Sample Status - Updated" -category Active -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Description,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [Validateset("Inactive","Active","Pending")]
        [String]$Category,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey

        switch ($category) {
            "Inactive" { $CategoryID = 0 }
            "Active" { $CategoryID = 1 }
            "Pending" { $CategoryID = 2 }
}
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/config/statustype/$($ID)"

        $RequestBody = @{
            'name'           = $Name
            'description'    = $Description
            'category'       = $CategoryID
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method PUT
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

function Get-InsightObjectTypeAttributes {
    <#

.SYNOPSIS
Resource to find Object Type Attributes for a specified Object Type in Insight.

.DESCRIPTION
Resource to find Object Type Attributes for a specified Object Type in Insight.

.PARAMETER ID
The Object Type ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 7
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z; updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False;
                          abstractObjectType=False; parentObjectTypeInherited=False}
name : Key
label : False
type : 0
defaultType : @{id=0; name=Text}
editable : False
system : True
sortable : True
summable : False
indexed : True
minimumCardinality : 1
maximumCardinality : 1
removable : False
hidden : False
includeChildObjectTypes : False
uniqueAttribute : False
options :
position : 0

id : 8
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z; updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False;
                          abstractObjectType=False; parentObjectTypeInherited=False}
name : Name
label : True
type : 0
description : The name of the object
defaultType : @{id=0; name=Text}
editable : True
system : False
sortable : True
summable : False
indexed : True
minimumCardinality : 1
maximumCardinality : 1
removable : False
hidden : False
includeChildObjectTypes : False
uniqueAttribute : False
options :
position : 1

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+type+attributes

.EXAMPLE
Get-InsightObjectTypeAttributes -ID 2 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttype/$($ID)/attributes"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}


function New-InsightObjectTypeAttributes {
    <#

.SYNOPSIS
Resource to create an object type attribute in Insight.

.DESCRIPTION
Resource to create an object type attribute in Insight.

.PARAMETER Name
The name.

.PARAMETER Description
The Description for the Attribute.

.PARAMETER Type
The type. ["Default", "Object", "User", "Confluence", "Group", "Status"]

.PARAMETER ParentObjectTypeId
The Object type ID of the Parent

.PARAMETER defaultType
The default type id. Dynamic Parameter if 'Type' is 'Default' ["Text", "Integer", "Boolean", "Double", "Date", "Time", "Date_Time", "URL", "Email", "TextArea", "Select", "IP_Address"]

.PARAMETER typeValue
The referenced object type id. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER typeValueMulti
The JIRA groups to restrict selection. Dynamic Parameter if 'Type' is 'User'

.PARAMETER additionalValue. Dynamic Parameter if 'Type' is 'Object','URL' or 'Confluence'
URL: DISABLED, ENABLED
OBJECT: Reference Type Id
User: SHOW_PROFILE, HIDE_PROFILE
Confluence: Confluence Space Id

.PARAMETER minimumCardinality. Dynamic Parameter if 'Type' is 'Email','Select','Object','User','Group','Version','Project'
The minimum cardinality (default 0)

.PARAMETER maximumCardinality. Dynamic Parameter if 'Type' is 'Email','Select','Object','User','Group','Version','Project'
The maximum cardinality (default 1)

.PARAMETER suffix
If suffix on value types (Integer, Float). Dynamic Parameter if 'Default Type' is 'Integer' or 'Float'

.PARAMETER includeChildObjectTypes
If objects should be valid for object type children. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER iql
If objects should be filtered by IQL. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER uniqueAttribute
If the attribute should be unique (true, false)

.PARAMETER summable
If a sum should be shown in list view (true, false). Dynamic Parameter if 'Default Type' is 'Integer' or 'Float'

.PARAMETER regexValidation. Dynamic Parameter if 'Type' is 'Text' or 'Email'
If a regex validation should apply

.PARAMETER options. Dynamic Parameter if 'Type' is 'Options'
The options for the attribute in comma separate list

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 6
name : Test Attribute
label : False
type : 0
defaultType : @{id=0; name=Text}
editable : True
system : False
sortable : True
summable : False
indexed : True
minimumCardinality : 0
maximumCardinality : 1
removable : True
hidden : False
includeChildObjectTypes : False
uniqueAttribute : False
options :
position : 4

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+type+attributes

.EXAMPLE
New-InsightObjectTypeAttributes -Name "Test Attribute" -Type Default -DefaultType Text -ObjectTypeId 1 -InsightApiKey $InsightApiKey
New-InsightObjectTypeAttributes -Name "Email Address" -Type Default -DefaultType Email -ParentObjectTypeId 1 -InsightApiKey $InsightApiKey
New-InsightObjectTypeAttributes -Name "Link to Parent" -Type Object -typeValue 2 -ParentObjectTypeId 1 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [string]$Description,

        [Parameter(Mandatory = $true)]
        [ValidateSet("Default", "Object", "User", "Confluence", "Group", "Status")]
        [string]$Type,

        [Parameter(Mandatory = $false)]
        [Alias('ObjectTypeId')]
        [int]$ParentObjectTypeId,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    DynamicParam {
        # Create a new dictionary to contain all the dynamic parameters
        $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()

        if ($Type -like "Default") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'DefaultType',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $true; Position = 1 }
                            [ValidateSet]::new("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date_Time", "URL", "Email", "TextArea", "Select", "IP_Address")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($DefaultType -in "Integer","Float") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'suffix',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $true; Position = 1 }
                            #[ValidateSet]::new("Start", "Stop", "Create", "Delete")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'summable',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $true; Position = 1 }
                            [ValidateSet]::new("True", "False")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -in "Object") {

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'typeValue',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $true; Position = 1 }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'includeChildObjectTypes',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                            #[ValidateSet]::new("Start", "Stop", "Create", "Delete")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'iql',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                            #[ValidateSet]::new("Start", "Stop", "Create", "Delete")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -in "User") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'typeValueMulti',
                        [array],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -in "Object","URL","Confluence","User") {

            if ($Type -like "Object") {
                $Mandatory =  $true
            }
            else {
                $Mandatory = $false
            }

            if ($Type -like "URL") {
                $ValidatedSet = "DISABLED","ENABLED"
            }
            if ($Type -like "User") {
                $ValidatedSet = "SHOW_PROFILE","HIDE_PROFILE"
            }

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'additionalValue',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $Mandatory; Position = 1 }
                                if ($type -in "URL","User") {
                                    [ValidateSet]::new($ValidatedSet)
                                }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -in "Email","Select","Object","User","Group","Version","Project") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'minimumCardinality',
                        [int],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)

            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'maximumCardinality',
                        [int],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -in "Text","Email") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'regexValidation',
                        [string],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }

        if ($Type -like "Options") {
            $parameter = [System.Management.Automation.RuntimeDefinedParameter]::new(
                        'options',
                        [array],
                        [Attribute[]]@(
                            [Parameter]@{ Mandatory = $false; Position = 1 }
                            #[ValidateSet]::new("Start", "Stop", "Create", "Delete")
                        )
                    )
                    $paramDictionary.Add($parameter.Name, $parameter)
        }
        
        $paramDictionary
    }

    begin {
        
        # Translate the Object Type Name to the Object Type ID
        switch ($Type) {
            "Default" { $objectTypeID = "0" }
            "Object" { $objectTypeID = "1" }
            "User" { $objectTypeID = "2" }
            "Confluence" { $objectTypeID = "3" }
            "Group" { $objectTypeID = "4" }
            "Status" { $objectTypeID = "7" }
        }

        # Translate the Default Object Type Name to the Default Object Type ID
        switch ($PSBoundParameters["DefaultType"]) {
            "Text" { $DefaultTypeID = 0 }
            "Integer" { $DefaultTypeID = "1" }
            "Boolean" { $DefaultTypeID = "2" }
            "Double" { $DefaultTypeID = "3" }
            "Date" { $DefaultTypeID = "4" }
            "Time" { $DefaultTypeID = "5" }
            "Date Time" { $DefaultTypeID = "6" }
            "URL" { $DefaultTypeID = "7" }
            "Email" { $DefaultTypeID = "8" }
            "Textarea" { $DefaultTypeID = "9" }
            "Select" { $DefaultTypeID = "10" }
            "IP Address" { $DefaultTypeID = "11" }
        } 
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {

        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttypeattribute/$($ParentObjectTypeId)"

        #Create default Hash
        $RequestBody = @{
            name = $Name
        }

        #Add required attributes to the hash for all Object Types except Default
        switch ($Type) {
            { @("Object", "Confluence") -contains $_ } {
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValue", $PSBoundParameters["typeValue"])
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "User" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValue", $PSBoundParameters["typeValue"])
                $RequestBody.Add("typeValueMulti", $PSBoundParameters["typeValueMulti"])
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Group" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Status" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValueMulti", $PSBoundParameters["typeValueMulti"])
            }
        }

        #Add required attributes to the hash for all Object Type "Default"
        switch ($PSBoundParameters["DefaultType"]) {
            { @("Text", "Integer", "Boolean", "Double", "Date", "Date_Time", "Email", "TextArea", "IP_Address") -contains $_ } {
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
            }
            "URL" { 
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Select" { 
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
                $RequestBody.Add("options", $PSBoundParameters["options"])
            }
        }

        # Add all the aditional Attributes.
        if ($uniqueAttribute) {
            $RequestBody.Add("uniqueAttribute", $UniqueAttribute)
        }
        if ($Description) {
            $RequestBody.Add("Description", $Description)
        }
        if ($PSBoundParameters["minimumCardinality"]) {
            $RequestBody.Add("minimumCardinality", $PSBoundParameters["minimumCardinality"])
        }
        if ($PSBoundParameters["maximumCardinality"]) {
            $RequestBody.Add("maximumCardinality", $PSBoundParameters["maximumCardinality"])
        }
        if ($PSBoundParameters["suffix"]) {
            $RequestBody.Add("suffix", $PSBoundParameters["suffix"])
        }
        if ($PSBoundParameters["includeChildObjectTypes"]) {
            $RequestBody.Add("includeChildObjectTypes", $PSBoundParameters["includeChildObjectTypes"])
        }
        if ($PSBoundParameters["iql"]) {
            $RequestBody.Add("iql", $PSBoundParameters["iql"])
        }
        if ($PSBoundParameters["summable"]) {
            $RequestBody.Add("summable", $PSBoundParameters["summable"])
        }
        if ($PSBoundParameters["regexValidation"]) {
            $RequestBody.Add("regexValidation", $PSBoundParameters["regexValidation"])
        }
        if ($PSBoundParameters["options"]) {
            $RequestBody.Add("options", $PSBoundParameters["options"])
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 10
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method POST
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

function Remove-InsightObjectTypeAttributes {
    <#

.SYNOPSIS
Resource to delete an object type attribute in Insight.

.DESCRIPTION
Resource to delete an object type attribute in Insight.

.PARAMETER ID
The Object Type Attribute ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
No output from API

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+type+attributes

.EXAMPLE
Remove-InsightObjectTypeAttributes -ID 11 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttypeattribute/$($ID)"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}


function Set-InsightObjectTypeAttributes {
    <#

.SYNOPSIS
Resource to update an object type attribute in Insight.

.DESCRIPTION
Resource to update an object type attribute in Insight.

.PARAMETER Name
The name.

.PARAMETER Type
The type. ["Default", "Object", "User", "Confluence", "Group", "Status"]

.PARAMETER ParentObjectTypeId
The Object type ID of the Parent

.PARAMETER defaultType
The default type id. Dynamic Parameter if 'Type' is 'Default' ["Text", "Integer", "Boolean", "Double", "Date", "Time", "Date_Time", "URL", "Email", "TextArea", "Select", "IP_Address"]

.PARAMETER typeValue
The referenced object type id. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER typeValueMulti
The JIRA groups to restrict selection. Dynamic Parameter if 'Type' is 'User'

.PARAMETER additionalValue. Dynamic Parameter if 'Type' is 'Object','URL' or 'Confluence'
URL: DISABLED, ENABLED
OBJECT: Reference Type Id
User: SHOW_PROFILE, HIDE_PROFILE
Confluence: Confluence Space Id

.PARAMETER minimumCardinality. Dynamic Parameter if 'Type' is 'Email','Select','Object','User','Group','Version','Project'
The minimum cardinality (default 0)

.PARAMETER maximumCardinality. Dynamic Parameter if 'Type' is 'Email','Select','Object','User','Group','Version','Project'
The maximum cardinality (default 1)

.PARAMETER suffix
If suffix on value types (Integer, Float). Dynamic Parameter if 'Default Type' is 'Integer' or 'Float'

.PARAMETER includeChildObjectTypes
If objects should be valid for object type children. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER iql
If objects should be filtered by IQL. Dynamic Parameter if 'Type' is 'Object'

.PARAMETER uniqueAttribute
If the attribute should be unique (true, false)

.PARAMETER summable
If a sum should be shown in list view (true, false). Dynamic Parameter if 'Default Type' is 'Integer' or 'Float'

.PARAMETER regexValidation. Dynamic Parameter if 'Type' is 'Text' or 'Email'
If a regex validation should apply

.PARAMETER options. Dynamic Parameter if 'Type' is 'Options'
The options for the attribute in comma separate list

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 30
name : A different name then before
label : False
type : 0
defaultType : @{id=0; name=Text}
editable : True
system : False
sortable : True
summable : False
indexed : True
minimumCardinality : 0
maximumCardinality : 1
removable : True
hidden : False
includeChildObjectTypes : False
uniqueAttribute : False
options :
position : 4

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+type+attributes

.EXAMPLE
Set-InsightObjectTypeAttributes -ParentObjectTypeId 2 -objectTypeAttributeId 30 -Name "A different name then before"

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [Alias('ObjectTypeId')]
        [int]$ParentObjectTypeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$objectTypeAttributeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [string]$Name,

        [Parameter(Mandatory = $false)]
        [ValidateSet("Default", "Object", "User", "Confluence", "Group", "Status")]
        [string]$Type,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    DynamicParam {
        # Create a new dictionary to contain all the dynamic parameters
        $paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary

        if ($Type -like "Default") {
            #region DefaultType
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            $attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date_Time", "URL", "Email", "TextArea", "Select", "IP_Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            $attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $DefaultType_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("DefaultType", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("DefaultType", $DefaultType_dynParam)
            #endregion DefaultType
        }

        if ($DefaultType -like "Integer" -or $DefaultType -like "Float") {
            #region suffix
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $true

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $suffix_attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $suffix_attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $suffix_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("suffix", [STRING], $suffix_attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("suffix", $suffix_dynParam)
            #endregion suffix

            #region summable
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $true

            # Create the ValidateSet list
            $attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("True", "False")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            $attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $summable_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("summable", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("summable", $summable_dynParam)
            #endregion summable
        }

        if ($Type -like "Object") {
            #region typeValue
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $typeValue_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("typeValue", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("typeValue", $typeValue_dynParam)
            #endregion typeValue

            #region includeChildObjectTypes
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")

            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $includeChildObjectTypes_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("includeChildObjectTypes", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("includeChildObjectTypes", $includeChildObjectTypes_dynParam)
            #endregion includeChildObjectTypes

            #region iql
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")

            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $iql_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("iql", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("iql", $iql_dynParam)
            #endregion iql
        }

        if ($Type -like "User") {
            #region typeValueMulti
            #The JIRA groups to restrict selection
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $typeValueMulti_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("typeValueMulti", [ARRAY], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("typeValueMulti", $typeValueMulti_dynParam)
            #endregion typeValueMulti
        }

        if ($Type -like "Object" -or $Type -like "URL" -or $Type -like "Confluence") {
            #region additionalValue
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false
            
            # Create the ValidateSet list
            if ($Type -like "URL") {
                $attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("DISABLED", "ENABLED")
            }
            if ($Type -like "User") {
                $attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("SHOW_PROFILE", "HIDE_PROFILE")
            }
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $additionalValue_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("additionalValue", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("additionalValue", $additionalValue_dynParam)
            #endregion additionalValue
        }

        if ($Type -like "Email" -or $Type -like "Select" -or $Type -like "Object" -or $Type -like "User" -or $Type -like "Group" -or $Type -like "Version" -or $Type -like "Project") {
            #region minimumCardinality
            #The JIRA groups to restrict selection
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"

            $attributes.Mandatory = $false
            
            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $minimumCardinality_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("minimumCardinality", [INT], $attributeCollection)
            $PSBoundParameters["minimumCardinality_dynParam"] = 0

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("minimumCardinality", $minimumCardinality_dynParam)
            #endregion minimumCardinality

            #region maximumCardinality
            #The JIRA groups to restrict selection
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"

            $attributes.Mandatory = $false
            
            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")
        
            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $maximumCardinality_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("maximumCardinality", [INT], $attributeCollection)
            $PSBoundParameters["maximumCardinality_dynParam"] = 1

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("maximumCardinality", $maximumCardinality_dynParam)
            #endregion maximumCardinality
        }

        if ($Type -like "Text" -or $Type -like "Email") {
            #region regexValidation
            #Create the base DynamicParam attributes
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")

            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $regexValidation_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("regexValidation", [STRING], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("regexValidation", $regexValidation_dynParam)
            #endregion regexValidation
        }

        if ($Type -like "Options") {
            #region options
            #Create the base DynamicParam attributes
            #The options for the attribute in comma separate list - Might need to add script validation or use .join(",")
            $attributes = new-object System.Management.Automation.ParameterAttribute
            $attributes.ParameterSetName = "__AllParameterSets"
            $attributes.Mandatory = $false

            # Create the ValidateSet list
            #$attributesValidate = New-Object System.Management.Automation.ValidateSetAttribute @("Text", "Integer", "Boolean", "Double", "Date", "Time", "Date Time", "URL", "Email", "Text Area", "Select", "IP Address")

            # Add the Base Attributes and the Validated list attributes to a collection
            $attributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
            $attributeCollection.Add($attributes)
            #$attributeCollection.Add($attributesValidate)

            #Create a new object with the Name, Type, and attributes collection.
            $options_dynParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("options", [ARRAY], $attributeCollection)

            # Add Parameter to the Dictionary collection
            $paramDictionary.Add("options", $options_dynParam)
            #endregion options
        }
        #Return all the dynamic parameters inside the dictionary
        return $paramDictionary
    }

    begin {
        
        # Translate the Object Type Name to the Object Type ID
        switch ($Type) {
            "Default" { $objectTypeID = "0" }
            "Object" { $objectTypeID = "1" }
            "User" { $objectTypeID = "2" }
            "Confluence" { $objectTypeID = "3" }
            "Group" { $objectTypeID = "4" }
            "Status" { $objectTypeID = "7" }
        }

        # Translate the Default Object Type Name to the Default Object Type ID
        switch ($PSBoundParameters["DefaultType"]) {
            "Text" { $DefaultTypeID = 0 }
            "Integer" { $DefaultTypeID = "1" }
            "Boolean" { $DefaultTypeID = "2" }
            "Double" { $DefaultTypeID = "3" }
            "Date" { $DefaultTypeID = "4" }
            "Time" { $DefaultTypeID = "5" }
            "Date Time" { $DefaultTypeID = "6" }
            "URL" { $DefaultTypeID = "7" }
            "Email" { $DefaultTypeID = "8" }
            "Textarea" { $DefaultTypeID = "9" }
            "Select" { $DefaultTypeID = "10" }
            "IP Address" { $DefaultTypeID = "11" }
        } 
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {

        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttypeattribute/$($ParentObjectTypeId)/$($objectTypeAttributeId)"

        #Create default Hash
        $RequestBody = @{
            name = $Name
        }

        #Add required attributes to the hash for all Object Types except Default
        switch ($Type) {
            { @("Object", "Confluence") -contains $_ } {
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValue", $PSBoundParameters["typeValue"])
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "User" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValueMulti", $PSBoundParameters["typeValueMulti"])
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Group" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Status" { 
                $RequestBody.Add("type", $objectTypeID)
                $RequestBody.Add("typeValueMulti", $PSBoundParameters["typeValueMulti"])
            }
        }

        #Add required attributes to the hash for all Object Type "Default"
        switch ($PSBoundParameters["DefaultType"]) {
            { @("Text", "Integer", "Boolean", "Double", "Date", "Date_Time", "Email", "TextArea", "IP_Address") -contains $_ } {
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
            }
            "URL" { 
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
                $RequestBody.Add("additionalValue", $PSBoundParameters["additionalValue"])
            }
            "Select" { 
                $RequestBody.Add("type", 0)
                $RequestBody.Add("defaultTypeId", $DefaultTypeID)
                $RequestBody.Add("options", $PSBoundParameters["options"])
            }
        }

        # Add all the aditional Attributes.
        if ($uniqueAttribute) {
            $RequestBody.Add("uniqueAttribute", $UniqueAttribute)
        }
        if ($PSBoundParameters["minimumCardinality"]) {
            $RequestBody.Add("minimumCardinality", $PSBoundParameters["minimumCardinality"])
        }
        if ($PSBoundParameters["maximumCardinality"]) {
            $RequestBody.Add("maximumCardinality", $PSBoundParameters["maximumCardinality"])
        }
        if ($PSBoundParameters["suffix"]) {
            $RequestBody.Add("suffix", $PSBoundParameters["suffix"])
        }
        if ($PSBoundParameters["includeChildObjectTypes"]) {
            $RequestBody.Add("includeChildObjectTypes", $PSBoundParameters["includeChildObjectTypes"])
        }
        if ($PSBoundParameters["iql"]) {
            $RequestBody.Add("iql", $PSBoundParameters["iql"])
        }
        if ($PSBoundParameters["summable"]) {
            $RequestBody.Add("summable", $PSBoundParameters["summable"])
        }
        if ($PSBoundParameters["regexValidation"]) {
            $RequestBody.Add("regexValidation", $PSBoundParameters["regexValidation"])
        }
        if ($PSBoundParameters["options"]) {
            $RequestBody.Add("options", $PSBoundParameters["options"])
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method PUT
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

function Get-InsightIcons {
    <#

.SYNOPSIS
Resource to find global Icons in Insight.

.DESCRIPTION
Resource to find global Icons in Insight.

.PARAMETER Full
If full switch is used then property url16 is returned

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
If switch 'Full' is used
id name url16
 -- ---- -----
  1 3D Printer /rest/insight/1.0/icon/1/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLm...
  2 AV Receiver /rest/insight/1.0/icon/2/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLm...

if switch 'Full' is not used
id name
 -- ----
  1 3D Printer
  2 AV Receiver
  3 Active Directory
  4 Administrative Tools
  5 Agreement

.LINK
https://documentation.mindville.com/display/ICV811/Icons+-+REST

.EXAMPLE
Get-InsightIcons -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey,

        [switch]$Full = $False
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/icon/global"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }

        if ($Full) {
            Write-Output $response
        }
        else {
            Write-Output $response | Select id,name
        }
    }
}

function Build-ObjectType {
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [Array]$ObjectArray,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$InsightApiKey,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$SchemaID
    )
    
    foreach ($ObjectType in $ObjectArray) {
        
        #Create ObjectType or return info
        try {
            $HashArguments = @{
                objectschemaID = $SchemaID
                InsightApiKey  = $InsightApiKey
            }
            $ObjectTypeParameters = Get-InsightObjectTypes @HashArguments | Where-Object { $_.Name -like $ObjectType.Name }
            if ($ObjectTypeParameters -eq $null) {
                throw "$($ObjectType.Name) - Object not found"
                Write-Verbose 'Object Type not found'
            }
        }
        catch {
            $HashArguments = @{
                Name           = $ObjectType.Name
                IconID         = (Get-InsightIcons -InsightApiKey $InsightApiKey | Where-Object { $_.name -like $ObjectType.Icon }).id
                objectSchemaId = $SchemaID
                InsightApiKey  = $InsightApiKey
            }
            switch ($ObjectType) {
                { $ObjectType.description } {
                    $HashArguments.Add('description', $ObjectType.Description) 
                }
                { $ObjectType.inherited } {
                    $HashArguments.Add('inherited', $ObjectType.inherited) 
                }
                { $ObjectType.abstractObjectType } {
                    $HashArguments.Add('abstractObjectType', $ObjectType.abstractObjectType) 
                }
                { $ObjectType.parentObjectTypeId } {
                    $HashArguments.Add('parentObjectTypeId', $ObjectType.parentObjectTypeId) 
                }
            }
            $ObjectTypeParameters = New-InsightObjectTypes @HashArguments
            Write-Verbose 'Object Type has been created'
        }

        #Create Object Attributes
        if ($ObjectType.Attributes) {
            $HashArguments = @{
                ID            = $ObjectTypeParameters.id
                InsightApiKey = $InsightApiKey
            }
            $ObjectTypeAttributes = Get-InsightObjectTypeAttributes @HashArguments
            
            # Find missing Attributes
            $MissingObjectTypeAttributes = $ObjectType.Attributes | Where-Object { $ObjectTypeAttributes.name -notcontains $_.name }
        
            # Create any missing attributes
            foreach ($Attribute in $MissingObjectTypeAttributes) {
                Write-Host $Attribute -BackgroundColor Yellow
                $HashArguments = @{
                    Name          = $Attribute.name
                    Type          = $Attribute.Type
                    ObjectType    = $ObjectTypeParameters.id
                    InsightApiKey = $InsightApiKey
                }
                switch ($Attribute) {
                    { $Attribute.Description } {
                        $HashArguments.Add('Description', $Attribute.Description) 
                    }
                    { $Attribute.DefaultType } {
                        $HashArguments.Add('DefaultType', $Attribute.DefaultType) 
                    }
                    { $Attribute.ParentObjectTypeId } {
                        $HashArguments.Add('ParentObjectTypeId', $Attribute.ParentObjectTypeId) 
                    }
                    { $Attribute.typeValue } {
                        $HashArguments.Add('typeValue', $Attribute.typeValue) 
                    }
                    { $Attribute.typeValueMulti } {
                        $HashArguments.Add('typeValueMulti', $Attribute.typeValueMulti) 
                    }
                    { $Attribute.additionalValue } {
                        $HashArguments.Add('additionalValue', $Attribute.additionalValue) 
                    }
                    { $Attribute.minimumCardinality } {
                        $HashArguments.Add('minimumCardinality', $Attribute.minimumCardinality) 
                    }
                    { $Attribute.maximumCardinality } {
                        $HashArguments.Add('maximumCardinality', $Attribute.maximumCardinality) 
                    }
                    { $Attribute.suffix } {
                        $HashArguments.Add('suffix', $Attribute.suffix) 
                    }
                    { $Attribute.includeChildObjectTypes } {
                        $HashArguments.Add('includeChildObjectTypes', $Attribute.includeChildObjectTypes) 
                    }
                    { $Attribute.iql } {
                        $HashArguments.Add('iql', $Attribute.iql) 
                    }
                    { $Attribute.uniqueAttribute } {
                        $HashArguments.Add('uniqueAttribute', $Attribute.uniqueAttribute) 
                    }
                    { $Attribute.summable } {
                        $HashArguments.Add('summable', $Attribute.summable) 
                    }
                    { $Attribute.regexValidation } {
                        $HashArguments.Add('regexValidation', $Attribute.regexValidation) 
                    }
                    { $Attribute.options } {
                        $HashArguments.Add('options', $Attribute.options) 
                    }
                }
                New-InsightObjectTypeAttributes @HashArguments
                Write-Verbose "$($Attribute.name): Created"
            }
        } 

        if ($ObjectType.ObjectTypes) {
            # add the parent object type id so that next loop is for a child
            foreach ($child in $ObjectType.ObjectTypes.psobject.Properties) {
                $child.value | Add-Member -NotePropertyName 'parentObjectTypeId' -NotePropertyValue $ObjectTypeParameters.id
            }
            #call itself for recursion
            Build-ObjectType -ObjectArray $ObjectType.ObjectTypes -SchemaID $SchemaID -InsightApiKey $InsightApiKey
        }
    }
}

function Build-Schema {
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [Array]$ObjectArray,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$InsightApiKey
    )
    
    foreach ($item in $ObjectArray) {
        try {
            $HashArguments = @{
                InsightApiKey = $InsightApiKey
            }
            $ObjectSchema = Get-InsightObjectSchema @HashArguments | Where-Object { $_.name -like $item.ObjectSchemaName }
            if (!($ObjectSchema)) {
                throw 'Object Schema not found'
            }
        }
        catch {
            $HashArguments = @{
                Name            = $item.ObjectSchemaName
                ObjectSchemaKey = $item.ObjectSchemaKey
                Description     = $item.ObjectSchemaDescription
                InsightApiKey   = $InsightApiKey
            }
            $ObjectSchema = New-InsightObjectSchema @HashArguments
            Write-Verbose 'Object Schema has been created'
        }
        $ObjectSchema
    }
    
}

function Connect-MEMCM {
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Server,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$SiteCode
    )

    # Import the ConfigurationManager.psd1 module
    if((Get-Module ConfigurationManager) -eq $null) {
        Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1"
    }

    # Connect to the site's drive if it is not already present
    if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {
        New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $Server
    }

    # Set the current location to be the site
    Set-Location "$($SiteCode):\"
}

function Convert-ChassisType {
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ChassisID
    )

    class Chassis {
        [string]$Type
        [string]$ID
        [string]$Category
    }
    
    $Chassis = [Chassis]::new()
    
    switch ($ChassisID) {
        1 { 
            $Chassis.Type = 'Other'
            $Chassis.ID = $_
            $Chassis.Category = 'Unknown'
        }
        2 {  
            $Chassis.Type = 'Unknown'
            $Chassis.ID = $_
            $Chassis.Category = 'Unknown'
        }
        3 {
            $Chassis.Type = 'Desktop'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        4 { 
            $Chassis.Type = 'Low Profile Desktop'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        5 { 
            $Chassis.Type = 'Pizza Box'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        6 { 
            $Chassis.Type = 'Mini Tower'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        7 { 
            $Chassis.Type = 'Tower'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        8 { 
            $Chassis.Type = 'Portable'
            $Chassis.ID = $_
            $Chassis.Category = 'Laptop'
        }
        9 { 
            $Chassis.Type = 'Laptop'
            $Chassis.ID = $_
            $Chassis.Category = 'Laptop'
        }
        10 { 
            $Chassis.Type = 'Notebook'
            $Chassis.ID = $_
            $Chassis.Category = 'Laptop'
        }
        11 { 
            $Chassis.Type = 'Hand Held'
            $Chassis.ID = $_
            $Chassis.Category = 'Tablet'
        }
        12 { 
            $Chassis.Type = 'Docking Station'
            $Chassis.ID = $_
            $Chassis.Category = 'Dock'
        }
        13 { 
            $Chassis.Type = 'All in One'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        14 { 
            $Chassis.Type = 'Sub Notebook'
            $Chassis.ID = $_
            $Chassis.Category = 'Laptop'
        }
        15 { 
            $Chassis.Type = 'Space-Saving'
            $Chassis.ID = $_
            $Chassis.Category = 'Server'
        }
        16 { 
            $Chassis.Type = 'Lunch Box'
            $Chassis.ID = $_
            $Chassis.Category = 'Server'
        }
        17 { 
            $Chassis.Type = 'Main System Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Server'
        }
        18 { 
            $Chassis.Type = 'Expansion Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        19 { 
            $Chassis.Type = 'SubChassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Unknown'
        }
        20 { 
            $Chassis.Type = 'Bus Expansion Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Server'
        }
        21 { 
            $Chassis.Type = 'Peripheral Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Unknown'
        }
        22 { 
            $Chassis.Type = 'Storage Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Unknown'
        }
        23 { 
            $Chassis.Type = 'Rack Mount Chassis'
            $Chassis.ID = $_
            $Chassis.Category = 'Server'
        }
        24 { 
            $Chassis.Type = 'Sealed-Case PC'
            $Chassis.ID = $_
            $Chassis.Category = 'Desktop'
        }
        30 { 
            $Chassis.Type = 'Tablet'
            $Chassis.ID = $_
            $Chassis.Category = 'Tablet'
        }
        31 { 
            $Chassis.Type = 'Convertible'
            $Chassis.ID = $_
            $Chassis.Category = 'Tablet'
        }
        32 { 
            $Chassis.Type = 'Detachable'
            $Chassis.ID = $_
            $Chassis.Category = 'Tablet'
        }
    }
    return $Chassis
}

function Get-MEMCMSQL_ExtendedInfo {
    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [array]$Devices,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$SQLServer,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Database
    )
    
    begin {
        #Test-Module 'PSInsight'
        Test-Module 'SQLServer'
        #Test-Module 'Join-Object'

        # Grab SQL Data
        $Connection = @{
            ServerInstance = $SQLServer
            Database = $Database
        }
        $v_GS_COMPUTER_SYSTEM   = Invoke-Sqlcmd @Connection -Query 'Select * From v_GS_COMPUTER_SYSTEM'
        $v_GS_PHYSICAL_MEMORY   = Invoke-Sqlcmd @Connection -Query 'Select * From v_GS_PHYSICAL_MEMORY'
        $v_GS_DISK              = Invoke-Sqlcmd @Connection -Query 'Select * From v_GS_DISK'
        $v_GS_OPERATING_SYSTEM  = Invoke-Sqlcmd @Connection -Query 'Select * From v_GS_OPERATING_SYSTEM'
        $v_GS_LOGICAL_DISK      = Invoke-Sqlcmd @Connection -Query 'Select ResourceID,Size0,FreeSpace0 From v_GS_LOGICAL_DISK'
        $v_GS_SYSTEM_ENCLOSURE  = Invoke-Sqlcmd @Connection -Query 'Select ResourceID,ChassisTypes0 From v_GS_SYSTEM_ENCLOSURE'
        $v_GS_X86_PC_MEMORY     = Invoke-Sqlcmd @Connection -Query 'Select ResourceID,TotalPhysicalMemory0 From v_GS_X86_PC_MEMORY'
        $v_GS_VIRTUAL_MACHINE   = Invoke-Sqlcmd @Connection -Query 'Select * From v_GS_VIRTUAL_MACHINE'
        
        # Progress bar if running interactively
        if ([Environment]::UserInteractive -eq $true) {
            $DeviceCount = $Devices.count
            $i = 0
        }
    }
    
    process {
        ForEach ($Device in $Devices) {

            if ($DeviceCount) {
                $Percentage = [math]::Round($(($i / $DeviceCount)*100),2)
        
                $Progress = @{
                    Activity = "Building Computer Objects"
                    Status = "$Percentage% Complete:"
                    PercentComplete = $Percentage
                }
                # add SecondsRemaining
                Write-Progress @Progress
                $i++
            }
            
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_COMPUTER_SYSTEM' -Value $($v_GS_COMPUTER_SYSTEM | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_PHYSICAL_MEMORY' -Value $($v_GS_PHYSICAL_MEMORY | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_OPERATING_SYSTEM' -Value $($v_GS_OPERATING_SYSTEM | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_MAPPEDDRIVES640' -Value $($v_GS_MAPPEDDRIVES640 | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_DISK' -Value $($v_GS_DISK | Where { $_.ResourceID -like $Device.ResourceID }) -Force
        
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_LOGICAL_DISK' -Value $($v_GS_LOGICAL_DISK | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_SYSTEM_ENCLOSURE' -Value $($v_GS_SYSTEM_ENCLOSURE | Where { $_.ResourceID -like $Device.ResourceID }) -Force
            $Device | Add-Member -MemberType NoteProperty -Name 'v_GS_X86_PC_MEMORY' -Value $($v_GS_X86_PC_MEMORY | Where { $_.ResourceID -like $Device.ResourceID }) -Force
        
            if ($Device.v_GS_SYSTEM_ENCLOSURE.ChassisTypes0) {
                $Chassis = Convert-ChassisType $Device.v_GS_SYSTEM_ENCLOSURE.ChassisTypes0
            }
            
            $Object = [PSCustomObject]@{
                "Hostname" = $Device.Name
                "ResourceID" = $Device.ResourceID
                "Domain" = $Device.Domain
                "SerialNumber" = $Device.SerialNumber
                "IsVirtualMachine" = $Device.IsVirtualMachine
                "LastHardwareScan" = $Device.LastHardwareScan
                "LastLogonUser" = $Device.LastLogonUser
                "PrimaryUser" = $Device.PrimaryUser
                "MACAddress" = $Device.MACAddress
                
                # v_GS_COMPUTER_SYSTEM
                "Manufacturer" = $Device.v_GS_COMPUTER_SYSTEM.Manufacturer0
                "Model" = $Device.v_GS_COMPUTER_SYSTEM.Model0
                "TotalPhysicalMemory" = $Device.v_GS_COMPUTER_SYSTEM.TotalPhysicalMemory0
        
                # v_GS_SYSTEM_ENCLOSURE
                "ChassisType" = $Chassis.Type
                "ChassisTypeID" = $Chassis.ID
                "ChassisCategory" = $Chassis.Category
        
                # v_GS_OPERATING_SYSTEM
                "Operating System" = $Device.DeviceOS
                "OS Build" = $Device.DeviceOSbuild
                "Caption" = $Device.v_GS_OPERATING_SYSTEM.Caption0
                "CSDVersion" = $Device.v_GS_OPERATING_SYSTEM.CSDVersion0
                "InstallDate" = $Device.v_GS_OPERATING_SYSTEM.InstallDate0
                "OSArchitecture" = $Device.v_GS_OPERATING_SYSTEM.OSArchitecture0
                "Version" = $Device.v_GS_OPERATING_SYSTEM.Version0
        
                # v_GS_PHYSICAL_MEMORY - Physical Memory (Desktop?)
                "DeviceLocator" = $Device.v_GS_PHYSICAL_MEMORY.DeviceLocator0
                "FormFactor" = $Device.v_GS_PHYSICAL_MEMORY.FormFactor0
                "Capacity" = $Device.v_GS_PHYSICAL_MEMORY.Capacity0
                "Speed" = $Device.v_GS_PHYSICAL_MEMORY.Speed0
        
                # $v_GS_X86_PC_MEMORY
                "TotalPhysicalMemory0" = $Device.v_GS_X86_PC_MEMORY.TotalPhysicalMemory0
        
                # v_GS_DISK - Disk (Desktop?)
                "Disk_Caption" = $Device.v_GS_DISK.Caption0
                "Disk_DeviceID" = $Device.v_GS_DISK.DeviceID0
                "Disk_InterfaceType" = $Device.v_GS_DISK.InterfaceType0
                "Disk_Manufacturer" = $Device.v_GS_DISK.Manufacturer0
                "Disk_MediaType" = $Device.v_GS_DISK.MediaType0
                "Disk_Model" = $Device.v_GS_DISK.Model0
        
                # v_GS_LOGICAL_DISK
                "Disk_Size" = $Device.v_GS_LOGICAL_DISK.Size0
                "Disk_FreeSpace" = $Device.v_GS_LOGICAL_DISK.FreeSpace0
        
            }
            $Object
            }
    }
    
    end {
        
    }
}

function Get-ZoomRoomsObjects {
    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$SchemaName,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ObjectTypeName,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ZoomApiKey,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ZoomApiSecret
    )
    
    begin {
    Test-Module "PSZoom"
    Test-Module "PSInsight"
    Test-Module "Join-Object"

    $ZoomRoomIDs = Get-ZoomRooms -PageSize 300
    $DashboardZoomRooms = Get-DashboardZoomRooms -PageSize 300
    $ZoomRoomLocations = Get-ZoomRoomLocations -page_size 300

    function Get-SingleZoomRoomLocation {
        [CmdletBinding()]
        param (
            [String]$location_id,
            [Array]$Locations
        )
        
        begin {
            if ($Locations) {
                
            }
            Else {
                $Locations = Get-ZoomRoomLocations -PageSize 300
            }
        }
        
        process {
    
            $FloorObj = $Locations | Where-Object { $_.id -like $location_id }
            $CampusObj = $Locations | Where-Object { $_.id -like $FloorObj.parent_location_id }
            $CityObj = $Locations | Where-Object { $_.id -like $CampusObj.parent_location_id }
            $StateObj = $Locations | Where-Object { $_.id -like $CityObj.parent_location_id }
            $CountryObj = $Locations | Where-Object { $_.id -like $StateObj.parent_location_id }
    
            $hierarchy = @{
                Floor   = $FloorObj.name
                Campus  = $CampusObj.name
                City    = $CityObj.name
                State   = $StateObj.name
                Country = $CountryObj.name
            }
    
        }
        
        end {
            $hierarchy
        }
    }

    $ZoomRooms = @()    
    }
    
    process {
        foreach ($Room in $ZoomRoomIDs) {

            # Join Objects
            $ZRoom = Join-Object -Left $Room -Right $DashboardZoomRooms -LeftJoinProperty 'name' -RightJoinProperty 'room_name' -ExcludeRightProperties id, status
            
            # Add Devices with unique custom name for use in CMDB
            $Devices = foreach ($device in $(Get-ZoomRoomDevices -RoomID $Room.id)) {
                Add-Member -InputObject $device -NotePropertyName 'device_name' -NotePropertyValue "$($device.room_name) - $($device.device_type)" -Force
                $device
            }
            Add-Member -InputObject $ZRoom -NotePropertyName 'Devices' -NotePropertyValue $Devices -Force
            
            # Add Hierarchy
            Add-Member -InputObject $ZRoom -NotePropertyName 'Location' -NotePropertyValue $(Get-SingleZoomRoomLocation -location_id $Room.location_id -Locations $ZoomRoomLocations) -Force
            
            $ZRoom
            }
    }
    
    end {
        
    }
}

#Used to check if modle is already installed and import if it is, else install.
function Test-Module ($Module) {

    # If the module is already imported, notify and then do nothing
    if (Get-Module | Where-Object {$_.Name -eq $Module}) {
        write-host "Module $Module is already imported."
    }
    else {

        # If the module is not imported but is available on disk then import
        if (Get-Module -ListAvailable | Where-Object {$_.Name -eq $Module}) {
            Import-Module $Module -Verbose
        }
        else {

            # If the module is not imported\available on the disk but is in online gallery then install and then import
            if (Find-Module -Name $Module | Where-Object {$_.Name -eq $Module}) {
                Install-Module -Name $Module -Force -Verbose -Scope CurrentUser
                Import-Module $Module -Verbose
            }
            else {

                # If the module is not imported\available or found in the online gallery then notify and abort
                write-host "Module $Module not imported, not available and not in online gallery, exiting."
                EXIT 1
            }
        }
    }
}

function Find-InsightObjects {
    <#

.SYNOPSIS
Resource to load an object in Insight.

.DESCRIPTION
Resource to load an object in Insight.

.PARAMETER ObjectTypeID
The objects ID.

.PARAMETER query
The query string is a simple text match against the start of the name string.

.PARAMETER start
The start index (0..N).

.PARAMETER limit
The number of objects to fetch.

.PARAMETER includeChildren
If children objects should be included.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 3
label : MyObject
objectKey : ABC-3
avatar : @{url16=/rest/insight/1.0/objecttype/2/icon.png?size=16&uuid=3269b6c6-10cc-41de-88ba-99efae71f8...IjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; objectId=3}
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z; updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False; abstractObjectType=False;
               parentObjectTypeInherited=False}
created : 2020-09-17T01:11:02.596Z
updated : 2020-09-17T01:11:02.596Z
hasAvatar : False
timestamp : 1600305062596
attributes : {@{id=9; objectTypeAttribute=; objectTypeAttributeId=7; objectAttributeValues=System.Object[]; objectId=3}, @{id=12; objectTypeAttribute=; objectTypeAttributeId=8; objectAttributeValues=System.Object[]; objectId=3}, @{id=10;
               objectTypeAttribute=; objectTypeAttributeId=9; objectAttributeValues=System.Object[]; objectId=3}, @{id=11; objectTypeAttribute=; objectTypeAttributeId=10; objectAttributeValues=System.Object[]; objectId=3}...}
extendedInfo : @{openIssuesExists=False; attachmentsExists=False}
_links : @{self=/secure/ShowObject.jspa?id=3}
name : MyObject

.LINK
https://documentation.mindville.com/display/ICV8/Objects+-+REST

.EXAMPLE
Find-InsightObjects -ObjectTypeID "286" -limit 5000 -includeChildren $true -InsightApiKey $InsightApiKey
Find-InsightObjects -ObjectTypeID "295" -limit 100 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [String]$ObjectTypeID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [String]$query,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$start,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$limit,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [bool]$includeChildren,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {

        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttype/$($ObjectTypeID)/objects"

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            }
        if ($query) {
            $RequestBody.Add("query",$query )
        }
        if ($start) {
            $RequestBody.Add("start",$start )
        }
        if ($limit) {
            $RequestBody.Add("limit",$limit )
        }
        if ($includeChildren) {
            $RequestBody.Add("includeChildren",$includeChildren )
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 20

    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method Post
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }

        $response
    }
}

function Find-InsightObjectsAdvanced {
    <#

.SYNOPSIS
Resource to load an object in Insight.

.DESCRIPTION
Resource to load an object in Insight.

.PARAMETER page
The page to fetch. (1..N).

.PARAMETER asc
Ascending or descending, asc = 1, desc = 0.

.PARAMETER objectTypeId
The id of the Object Type to search objects from.

.PARAMETER objectId
Set the page to the page where this object is shown

.PARAMETER objectSchemaId
The id of the Object Schema to search from.

.PARAMETER iql
An valid IQL string to filter the returned objects.

.PARAMETER resultsPerPage
The number of objects to fetch.

.PARAMETER orderByTypeAttrId
The id of the attribute to sort the Objects from.

.PARAMETER includeAttributes
If object attributes should be included.

.PARAMETER attributesToDisplay
List of objectTypeAttributes ids to return.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS

.LINK
https://documentation.mindville.com/display/ICV8/Objects+-+REST

.EXAMPLE
Find-InsightObjects -ObjectTypeID "286" -limit 5000 -includeChildren $true -InsightApiKey $InsightApiKey
Find-InsightObjects -ObjectTypeID "295" -limit 100 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ObjectTypeID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$objectSchemaId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$objectId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$resultsPerPage,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$page,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$asc,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [string]$iql,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int]$orderByTypeAttrId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [bool]$includeAttributes,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $false)]
        [int[]]$attributesToDisplay,

        [Parameter(Mandatory = $false)]
        [switch]$ShowJSON,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {

        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/object/navlist/iql"

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            'objectSchemaId' = $objectSchemaId
            'resultsPerPage' = $resultsPerPage
            }
        if ($page) {
            $RequestBody.Add("page",$page )
        }
        if ($asc) {
            $RequestBody.Add("asc",$asc )
        }
        if ($objectId) {
            $RequestBody.Add("objectId",$objectId )
        }
        if ($iql) {
            $RequestBody.Add("iql",$iql )
        }
        if ($orderByTypeAttrId) {
            $RequestBody.Add("orderByTypeAttrId",$orderByTypeAttrId )
        }
        if ($includeAttributes) {
            $RequestBody.Add("includeAttributes",$includeAttributes )
        }
        if ($attributesToDisplay) {
            $list = @{"attributesToDisplayIds" = @($attributesToDisplay)}
            $RequestBody.Add("attributesToDisplay",$list )
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 20

        if ($ShowJSON -eq $true) {
            Write-Output $RequestBody
            break
        }

    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method Post
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }

        $response
    }
}

function Get-InsightObject {
    <#

.SYNOPSIS
Resource to load an object in Insight.

.DESCRIPTION
Resource to load an object in Insight.

.PARAMETER ID
The objects ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 3
label : MyObject
objectKey : ABC-3
avatar : @{url16=/rest/insight/1.0/objecttype/2/icon.png?size=16&uuid=3269b6c6-10cc-41de-88ba-99efae71f8...IjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; objectId=3}
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z; updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False; abstractObjectType=False;
               parentObjectTypeInherited=False}
created : 2020-09-17T01:11:02.596Z
updated : 2020-09-17T01:11:02.596Z
hasAvatar : False
timestamp : 1600305062596
attributes : {@{id=9; objectTypeAttribute=; objectTypeAttributeId=7; objectAttributeValues=System.Object[]; objectId=3}, @{id=12; objectTypeAttribute=; objectTypeAttributeId=8; objectAttributeValues=System.Object[]; objectId=3}, @{id=10;
               objectTypeAttribute=; objectTypeAttributeId=9; objectAttributeValues=System.Object[]; objectId=3}, @{id=11; objectTypeAttribute=; objectTypeAttributeId=10; objectAttributeValues=System.Object[]; objectId=3}...}
extendedInfo : @{openIssuesExists=False; attachmentsExists=False}
_links : @{self=/secure/ShowObject.jspa?id=3}
name : MyObject

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Objects

.EXAMPLE
Get-InsightObject -ID "3" -InsightApiKey $InsightApiKey
Get-InsightObject -ID "ABC-3" -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [String]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/object/$($ID)"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }        

        $response
    }
}

function New-InsightObject {
    <#

.SYNOPSIS
Resource to create object in Insight.

.DESCRIPTION
Resource to create object in Insight.

.PARAMETER objectTypeId
The Object Type ID

.PARAMETER attributes
An Array of parameters built via 'New-InsightObjectAttribute'

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 5
label : Test name
objectKey : ABC-5
avatar : @{url16=/rest/insight/1.0/objecttype/2/icon.png?size=16&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOi
             JIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6d
             HJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdod
             CIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDMxNDk2MywiZXhwIjoxNjAwMzE1MTQzLCJpYXQiOjE2MDAzMTQ5NjN9.vzQiy3zF1cgjWFBeymAv1Q6lU0dk-Ewv6kuE
             7Gh0ins; url48=/rest/insight/1.0/objecttype/2/icon.png?size=48&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJ
             hbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaW
             dodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiw...; objectId=5}
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z;
             updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False; abstractObjectType=False;
             parentObjectTypeInherited=False}
created : 2020-09-17T03:56:04.262Z
updated : 2020-09-17T03:56:04.262Z
hasAvatar : False
timestamp : 1600314964262
_links : @{self=/secure/ShowObject.jspa?id=5}
name : Test name

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Objects

.EXAMPLE
New-InsightObject -objectTypeId 2 -attributes $array -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$objectTypeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true,valuefrompipelinebypropertyname = $true)]
        [array]$attributes,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/object/create"

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            'attributes'   = @($attributes)
            }
            
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 20
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method POST
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}


function New-InsightObjectAttribute {
    <#

.SYNOPSIS
Resource to create an attribute array to send to New-InsightObject.

.DESCRIPTION
Resource to create an attribute array to send to New-InsightObject.

.PARAMETER objectTypeAttributeId
The object type attribute ID to populate.

.PARAMETER objectAttributeValues
The object attribute value.

.OUTPUTS
Name Value
---- -----
objectTypeAttributeId 8
objectAttributeValues {System.Collections.Hashtable}

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+type+attributes

.EXAMPLE
$1 = New-InsightObjectAttribute -objectTypeAttributeId 8 -objectAttributeValues "Test name"
$2 = New-InsightObjectAttribute -objectTypeAttributeId 12 -objectAttributeValues "test ID"

$array = @($1,$2) # For use with New-InsightObject

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true,valuefrompipelinebypropertyname = $true)]
        [int]$objectTypeAttributeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true,valuefrompipelinebypropertyname = $true)]
        [String[]]$objectAttributeValues
    )
    
    begin {
        $values = New-Object System.Collections.ArrayList 
    }
    
    process {
        $objectAttributeValues | ForEach-Object {
            $values.Add(@{'value' = $_}) | Out-Null
        }        
        $Attribute = @{
            'objectTypeAttributeId' = $objectTypeAttributeId
            'objectAttributeValues'   = @($values)
            }
    }

    end {
        Write-Output $Attribute
        }
}



function Remove-InsightObject {
    <#

.SYNOPSIS
Resource to delete an object in Insight.

.DESCRIPTION
Resource to delete an object in Insight.

.PARAMETER ID
The object ID. Takes a string of the ID or objectKey

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 3
label : MyObject
objectKey : ABC-3
avatar : @{url16=/rest/insight/1.0/objecttype/2/icon.png?size=16&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiw
               iaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDMwNjg5OCwiZXhwIjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-Q
               vW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; url48=/rest/insight/1.0/objecttype/2/icon.png?size=48&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoi
               NWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDMwNjg5OCwiZXhwIjoxNjAwMzA3MD
               c4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; url72=/rest/insight/1.0/objecttype/2/icon.png?size=72&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppc
               mEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI
               6MTYwMDMwNjg5OCwiZXhwIjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; url144=/rest/insight/1.0/objecttype/2/icon.png?size=144&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1N
               iJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW
               5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDMwNjg5OCwiZXhwIjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; url288=/rest/insight/1.0/objecttype/2/icon.png?size=288&uuid=3269b6c6-10cc-41de-88ba-99efae71f889&
               jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY
               29tLnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDMwNjg5OCwiZXhwIjoxNjAwMzA3MDc4LCJpYXQiOjE2MDAzMDY4OTh9._CaSkX-QvW1BlK7-4XJB9UikOvegJS-YSjCrCtYUl7A; objectId=3}
objectType : @{id=2; name=My Object Type; type=0; description=A Sample Object Type; icon=; position=0; created=2020-09-16T07:14:02.118Z; updated=2020-09-16T07:14:02.118Z; objectCount=0; objectSchemaId=3; inherited=False; abstractObjectType=False;
               parentObjectTypeInherited=False}
created : 2020-09-17T01:11:02.596Z
updated : 2020-09-17T01:11:02.596Z
hasAvatar : False
timestamp : 1600305062596
attributes : {@{id=9; objectTypeAttribute=; objectTypeAttributeId=7; objectAttributeValues=System.Object[]; objectId=3}, @{id=12; objectTypeAttribute=; objectTypeAttributeId=8; objectAttributeValues=System.Object[]; objectId=3}, @{id=10;
               objectTypeAttribute=; objectTypeAttributeId=9; objectAttributeValues=System.Object[]; objectId=3}, @{id=11; objectTypeAttribute=; objectTypeAttributeId=10; objectAttributeValues=System.Object[]; objectId=3}...}
extendedInfo : @{openIssuesExists=False; attachmentsExists=False}
_links : @{self=/secure/ShowObject.jspa?id=3}
name : MyObject

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Objects

.EXAMPLE
Remove-InsightObject -ID "3" -InsightApiKey $InsightApiKey
Remove-InsightObject -ID "ABC-3" -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/object/$($ID)"

    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}

function Set-InsightObject {
    <#

.SYNOPSIS
Resource to update an object in Insight.

.DESCRIPTION
Resource to update an object in Insight.

.PARAMETER ID
The ID

.PARAMETER Attributes
An array of attributes. colelcted from New-InsightObjectAttributes

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+schema

.EXAMPLE

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [array]$Attributes,

        [Parameter(Mandatory = $false)]
        [switch]$ShowJSON,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/object/$($ID)"

        $RequestBody = @{
            'objectTypeId' = $objectTypeId
            'attributes'   = @($attributes)
            }
        
            $RequestBody = ConvertTo-Json $RequestBody -Depth 20

            if ($ShowJSON -eq $true) {
                Write-Output $RequestBody
            }
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method PUT
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        }
        
        Write-Output $response
        }
}

function Get-InsightObjectTypes {
<#

.SYNOPSIS
Resource to find object types in Insight for a specific object schema. The object types are responded in a flat list.

.DESCRIPTION
Resource to find object types in Insight for a specific object schema. The object types are responded in a flat list.

.PARAMETER ID
The object type ID.
Can be the Object ID or the Schema ID etc

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : My Object Type
type : 0
description : A Sample Object Type
icon : @{id=1; name=3D Printer; url16=/rest/insight/1.0/objecttype/1/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2
                            lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29t
                            LnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTAxMiwiZXhwIjoxNjAwMjMxMTkyLCJpYXQiOjE2MDAyMzEwMTJ9.oHQ6uHuginJCihoHT2YdSqPMBzgWD
                            KpwZmVoBtlPqY0; url48=/rest/insight/1.0/objecttype/1/icon.png?size=48&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnN
                            pZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhb
                            GFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTAxMiwiZXhwIjoxNjAwMjMxMTkyLCJpYXQiOjE2MDAyMzEwMTJ9.oHQ6uHuginJCihoHT2YdSqPMBzgWDKpwZmVoBt
                            lPqY0}
position : 0
created : 2020-09-16T04:36:52.885Z
updated : 2020-09-16T04:36:52.885Z
objectCount : 0
objectSchemaId : 3
inherited : False
abstractObjectType : False
parentObjectTypeInherited : False

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+types

.EXAMPLE
Get-InsightObjectTypes -ID 3 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objectschema/$($ID)/objecttypes/flat"
    }
    
    end {
        try {
                $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method GET
            }
            catch {
                Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
            } 

            $response
    }
}

function New-InsightObjectTypes {
    <#

.SYNOPSIS
Resource to create an object type in Insight.

.DESCRIPTION
Resource to create an object type in Insight.

.PARAMETER Name
The object type name.

.PARAMETER Description
The object type description.

.PARAMETER IconID
The object type icon ID.

.PARAMETER ParentObjectTypeID
The parent object type id that new child object will be placed in

.PARAMETER objectSchemaId
The object schema id

.PARAMETER inherited
The object schema id

.PARAMETER abstractObjectType
Set to true to stop CI's from being created at this level (parent)

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : My Object Type
type : 0
description : A Sample Object Type
icon : @{id=1; name=3D Printer; url16=/rest/insight/1.0/objecttype/1/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2
                            lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29t
                            LnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTAxMiwiZXhwIjoxNjAwMjMxMTkyLCJpYXQiOjE2MDAyMzEwMTJ9.oHQ6uHuginJCihoHT2YdSqPMBzgWD
                            KpwZmVoBtlPqY0; url48=/rest/insight/1.0/objecttype/1/icon.png?size=48&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnN
                            pZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhb
                            GFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTAxMiwiZXhwIjoxNjAwMjMxMTkyLCJpYXQiOjE2MDAyMzEwMTJ9.oHQ6uHuginJCihoHT2YdSqPMBzgWDKpwZmVoBt
                            lPqY0}
position : 0
created : 2020-09-16T04:36:52.885Z
updated : 2020-09-16T04:36:52.885Z
objectCount : 0
objectSchemaId : 3
inherited : False
abstractObjectType : False
parentObjectTypeInherited : False

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+types

.EXAMPLE
New-InsightObjectTypes -Name "My Object Type" -Description "A Sample Object Type" -IconID 1 -objectSchemaId 3 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

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

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        $IconID,

        [Parameter(Mandatory = $false)]
        $parentObjectTypeId,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        $objectSchemaId,

        [Parameter(Mandatory = $false)]
        [ValidateSet('true','false')]
        $inherited,

        [Parameter(Mandatory = $false)]
        [ValidateSet('true','false')]
        $abstractObjectType,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttype/create"

        $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
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method POST
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

function Remove-InsightObjectTypes {
    <#

.SYNOPSIS
Resource to delete an object type in Insight.

.DESCRIPTION
Resource to delete an object type in Insight.

.PARAMETER ID
The Object Type ID.

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : My Object Type
type : 0
description : A Sample Object Type
icon : @{id=1; name=3D Printer; url16=/rest/insight/1.0/objecttype/1/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2
                            lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29t
                            LnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDI0MDIwNiwiZXhwIjoxNjAwMjQwMzg2LCJpYXQiOjE2MDAyNDAyMDZ9.fOtVat8TB9dOkl-8EWw4z1ztqCBtD
                            LFNeKXi6PjFcW0; url48=/rest/insight/1.0/objecttype/1/icon.png?size=48&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnN
                            pZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhb
                            GFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDI0MDIwNiwiZXhwIjoxNjAwMjQwMzg2LCJpYXQiOjE2MDAyNDAyMDZ9.fOtVat8TB9dOkl-8EWw4z1ztqCBtDLFNeKXi6P
                            jFcW0}
position : 0
created : 2020-09-16T04:36:52.885Z
updated : 2020-09-16T04:50:45.458Z
objectCount : 0
objectSchemaId : 3
inherited : False
abstractObjectType : False
parentObjectTypeInherited : False

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+types

.EXAMPLE
Remove-InsightObjectTypes -id 1 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$ID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttype/$($ID)"
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Method DELETE
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}


function Set-InsightObjectTypes {
    <#

.SYNOPSIS
Resource to create an object type in Insight.

.DESCRIPTION
Resource to create an object type in Insight.

.PARAMETER ID
The object type ID.

.PARAMETER Name
The status Name.

.PARAMETER Description
The object type Description.

.PARAMETER IconID
The object type IconID (Can be collected via Get-InsightIcons).

.PARAMETER InsightApiKey
The Api key.

.OUTPUTS
id : 1
name : My Object Type
type : 0
description : A Sample Object Type - Updated
icon : @{id=1; name=3D Printer; url16=/rest/insight/1.0/objecttype/1/icon.png?size=16&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2
                            lucy5pbnNpZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29t
                            LnJpYWRhbGFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTg0NSwiZXhwIjoxNjAwMjMyMDI1LCJpYXQiOjE2MDAyMzE4NDV9.kOqWqYE7nswEI7WZql7i3pOPp2MM8
                            frWlgwx9fB5GNI; url48=/rest/insight/1.0/objecttype/1/icon.png?size=48&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ucmlhZGFsYWJzLmppcmEucGx1Z2lucy5pbnN
                            pZ2h0Iiwic3ViIjoiNWVkZjBhNDNlMzFmNjIwYWJhNjYyZjAyIiwiaW5zaWdodCI6dHJ1ZSwiY2xpZW50S2V5IjoiN2VmZmExZGQtYzNiMS0zMjQ4LWFjZDUtNjdjNDcxZWFkOGQzIiwiaXNzIjoiY29tLnJpYWRhb
                            GFicy5qaXJhLnBsdWdpbnMuaW5zaWdodCIsIm9yaWdpbmFsbHlJc3N1ZWRBdCI6MTYwMDIzMTg0NSwiZXhwIjoxNjAwMjMyMDI1LCJpYXQiOjE2MDAyMzE4NDV9.kOqWqYE7nswEI7WZql7i3pOPp2MM8frWlgwx9f
                            B5GNI}
position : 0
created : 2020-09-16T04:36:52.885Z
updated : 2020-09-16T04:50:45.458Z
objectCount : 0
objectSchemaId : 3
inherited : False
abstractObjectType : False
parentObjectTypeInherited : False

.LINK
https://documentation.mindville.com/display/INSCLOUD/REST+API+-+Object+types

.EXAMPLE
Set-InsightObjectTypes -ID 1 -Name "My Object Type" -Description "A Sample Object Type - Updated" -IconID 1 -InsightApiKey $InsightApiKey

#>

    [CmdletBinding()]
    param (
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $True)]
        [int]$ID,

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [string]$Name,

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

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory = $true)]
        [int]$IconID,

        [ValidateNotNullOrEmpty()]
        [Alias('ApiKey')]
        [string]$InsightApiKey = $InsightApiKey
    )
    
    begin {
        #Generate Headers
        $headers = New-InsightHeaders -InsightApiKey $InsightApiKey
    }
    
    process {
        $Request = [System.UriBuilder]"https://insight-api.riada.io/rest/insight/1.0/objecttype/$($ID)"

        $RequestBody = @{
            'name'           = $Name
            'iconId'         = $iconId
        }
        If ($Description) {
            $RequestBody.Add('description', $Description)
        }
        
        $RequestBody = ConvertTo-Json $RequestBody -Depth 1
    }
    
    end {
        try {
            $response = Invoke-RestMethod -Uri $Request.Uri -Headers $headers -Body $RequestBody -Method PUT
        }
        catch {
            Write-Error -Message "$($_.Exception.Message)" -ErrorId $_.Exception.Code -Category InvalidOperation
        } 

        $response
    }
}

#endregion