OnCommand-Insight.psm1

# workarounds for PowerShell issues
if ($PSVersionTable.PSVersion.Major -lt 6) {
    Add-Type @"
        using System.Net;
        using System.Security.Cryptography.X509Certificates;
        public class TrustAllCertsPolicy : ICertificatePolicy {
           public bool CheckValidationResult(
                ServicePoint srvPoint, X509Certificate certificate,
                WebRequest request, int certificateProblem) {
                return true;
            }
        }
"@


    # OCI 7.2 only supports TLS 1.2 and PowerShell does not auto negotiate it, thus enforcing TLS 1.2 which works for older OCI Versions as well
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    # Using .NET JSON Serializer as JSON serialization included in Invoke-RestMethod -WebSession $Server.Session has a length restriction for JSON content
    Add-Type -AssemblyName System.Web.Extensions
    $global:javaScriptSerializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
    $global:javaScriptSerializer.MaxJsonLength = [System.Int32]::MaxValue
    $global:javaScriptSerializer.RecursionLimit = 99

    # Functions necessary to parse JSON output from .NET serializer to PowerShell Objects
    function ParseItem($jsonItem) {
        if($jsonItem.PSObject.TypeNames -match "Array") {
            return ParseJsonArray -jsonArray $jsonItem
        }
        elseif($jsonItem.PSObject.TypeNames -match "Dictionary") {
            return ParseJsonObject -jsonObj [HashTable]$jsonItem
        }
        else {
            return $jsonItem
        }
    }

    function ParseJsonObject($jsonObj) {
        $result = New-Object -TypeName PSCustomObject
        foreach ($key in $jsonObj.Keys) {
            $item = $jsonObj[$key]
            if ($item) {
                $parsedItem = ParseItem -jsonItem $item
            } else {
                $parsedItem = $null
            }
            $result | Add-Member -MemberType NoteProperty -Name $key -Value $parsedItem
        }
        return $result
    }

    function ParseJsonArray($jsonArray) {
        $result = @()
        $jsonArray | ForEach-Object {
            $result += ,(ParseItem -jsonItem $_)
        }
        return $result
    }

    function ParseJsonString($json) {
        $config = $javaScriptSerializer.DeserializeObject($json)
        if ($config -is [Array]) {
            return ParseJsonArray -jsonArray $config
        }
        else {
            return ParseJsonObject -jsonObj $config
        }
    }
}

# Function for multipart upload (based on http://blog.majcica.com/2016/01/13/powershell-tips-and-tricks-multipartform-data-requests/)
function global:Invoke-MultipartFormDataUpload
{
    [CmdletBinding()]
    PARAM
    (
        [parameter(Mandatory = $true,
                   Position=0)][ValidateNotNullOrEmpty()][string]$InFile,
        [parameter(Mandatory = $true,
                   Position=1)][ValidateNotNullOrEmpty()][string]$Name,
        [parameter(Mandatory = $true,
                   Position=2)][ValidateNotNullOrEmpty()][Uri]$Uri,
        [parameter(Mandatory = $true,
                   Position=3)][ValidateNotNullOrEmpty()][PSObject]$Header
    )
    BEGIN
    {
        if (-not (Test-Path $InFile))
        {
            $errorMessage = ("File {0} missing or unable to read." -f $InFile)
            $exception =  New-Object System.Exception $errorMessage
            $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, 'MultipartFormDataUpload', ([System.Management.Automation.ErrorCategory]::InvalidArgument), $InFile
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        Add-Type -AssemblyName System.Web

        $mimeType = [System.Web.MimeMapping]::GetMimeMapping($InFile)

        if ($mimeType)
        {
            $ContentType = $mimeType
        }
        else
        {
            $ContentType = "application/octet-stream"
        }
    }
    PROCESS
    {
        Add-Type -AssemblyName System.Net.Http

        $httpClientHandler = New-Object System.Net.Http.HttpClientHandler

        $httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler

        if ($Header.Authorization) {
            $httpClient.DefaultRequestHeaders.Authorization = $Header.Authorization
        }

        # set HTTP Client Timeout to a large value - e.g. 24 hours (in microsecends) to prevent timeout during upload and following processing of data (e.g. restore)
        $httpClient.Timeout = 864000000000

        $packageFileStream = New-Object System.IO.FileStream @($InFile, [System.IO.FileMode]::Open)

        $contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
        $contentDispositionHeaderValue.Name = $Name
        $contentDispositionHeaderValue.FileName = (Split-Path $InFile -leaf)

        $streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
        $streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
        $streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue $ContentType

        $content = New-Object System.Net.Http.MultipartFormDataContent
        $content.Add($streamContent)

        try
        {
            Write-Host "Starting upload"
            $response = $httpClient.PostAsync($Uri, $content).Result

            if (!$response.IsSuccessStatusCode)
            {
                $responseBody = $response.Content.ReadAsStringAsync().Result
                $errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody

                throw [System.Net.Http.HttpRequestException] $errorMessage
            }

            return $response.Content.ReadAsStringAsync().Result
        }
        catch [Exception]
        {
            $PSCmdlet.ThrowTerminatingError($_)
        }
        finally
        {
            if($null -ne $httpClient)
            {
                $httpClient.Dispose()
            }

            if($null -ne $response)
            {
                $response.Dispose()
            }
        }
    }
    END { }
}

# helper function to convert datetime to unix timestamp
function ConvertTo-UnixTimestamp {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True,
                    HelpMessage="Date to be converted.")][DateTime[]]$Date
    )

    BEGIN {
        $epoch = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0
    }

    PROCESS {
        $Date = @($Date)

        foreach ($Date in $Date) {
                $milliSeconds = [math]::truncate($Date.ToUniversalTime().Subtract($epoch).TotalMilliSeconds)
                Write-Output $milliSeconds
        }
    }
}

# helper function to convert unix timestamp to datetime
function ConvertFrom-UnixTimestamp {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True,
                    HelpMessage="Timestamp to be converted.")][String]$Timestamp,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Optional Timezone to be used as basis for Timestamp. Default is system Timezone.")][System.TimeZoneInfo]$Timezone=[System.TimeZoneInfo]::Local
    )

    PROCESS {
        $Timestamp = @($Timestamp)
        foreach ($Timestamp in $Timestamp) {
            $Date = [System.TimeZoneInfo]::ConvertTimeFromUtc(([datetime]'1/1/1970').AddMilliseconds($Timestamp),$Timezone)
            Write-Output $Date
        }
    }
}

# helper function to convert annotations to annotation values
function ConvertTo-AnnotationValues {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True,
                    HelpMessage="Timestamp to be converted.")][PSObject[]]$Annotations
          )

    PROCESS {
        $AnnotationValues = $Annotations | Where-Object { $_.label } | ForEach-Object { [PSCustomObject]@{rawValue=$_.rawValue;label=$_.label;isDerived=$false;annotationAssignment="MANUAL";definition=$_} | Add-Member -MemberType AliasProperty -Name displayValue -Value rawValue -PassThru }
        Write-Output $AnnotationValues
    }
}

### Parsing Functions

function ParseExceptionBody($Response) {
    if ($Response) {
        $Reader = New-Object System.IO.StreamReader($Response.GetResponseStream())
        $Reader.BaseStream.Position = 0
        $Reader.DiscardBufferedData()
        $ResponseBody = $reader.ReadToEnd()
        if ($ResponseBody.StartsWith('{')) {
            $ResponseBody = $ResponseBody | ConvertFrom-Json | ConvertTo-Json
        }
        return $ResponseBody
    }
    else {
        return $Response
    }
}

function ParseAcquisitionUnits($AcquisitionUnits,$Timezone) {
    $AcquisitionUnits = @($AcquisitionUnits)
    foreach ($AcquisitionUnit in $AcquisitionUnits) {
        if ($AcquisitionUnit.nextLeaseRenewal) {
            $AcquisitionUnit.nextLeaseRenewal = $AcquisitionUnit.nextLeaseRenewal | Get-Date
        }

        if ($AcquisitionUnit.lastReported) {
            $AcquisitionUnit.lastReported = $AcquisitionUnit.lastReported | Get-Date
        }

        if ($AcquisitionUnit.datasources) {
            $AcquisitionUnit.datasources = ParseDatasources -Datasources $AcquisitionUnit.datasources -Timezone $Timezone
        }

        Write-Output $AcquisitionUnit
    }
}

function ParseActivePatches($ActivePatches,$Timezone) {
    $ActivePatches = @($ActivePatches)
    foreach ($ActivePatch in $ActivePatches) {
        if ($ActivePatch.createTime) {
            $ActivePatch.createTime = $ActivePatch.createTime | Get-Date
        }
        if ($ActivePatch.lastUpdateTime) {
            $ActivePatch.lastUpdateTime = $ActivePatch.lastUpdateTime | Get-Date
        }

        Write-Output $ActivePatch
    }
}

function ParseDatasources($Datasources,$Timezone) {
    $Datasources = @($Datasources)
    foreach ($Datasource in $Datasources) {
        if ($Datasource.lastSuccessfullyAcquired) {
            $Datasource.lastSuccessfullyAcquired = $Datasource.lastSuccessfullyAcquired | Get-Date
        }

        if ($Datasource.resumeTime) {
            $Datasource.resumeTime = $Datasource.resumeTime | Get-Date
        }
        if ($Datasource.AcquisitionUnit) {
            $Datasource.AcquisitionUnit = ParseAcquisitionUnits -AcquisitionUnits $Datasource.AcquisitionUnit -Timezone $Timezone
        }
        if ($Datasource.Changes) {
            $Datasource.Changes = ParseChanges -Changes $Datasource.Changes -Timezone $Timezone
        }
        if ($Datasource.Events) {
            $Datasource.Events = ParseEvents -Events $Datasource.Events -Timezone $Timezone
        }
        if ($Datasource.activePatch) {
            $Datasource.activePatch = ParseActivePatches -ActivePatches $Datasource.activePatch -Timezone $Timezone
        }
        if ($Datasource.config) {
            $Datasource.config = ParseDatasourceConfig -DatasourceConfig $Datasource.config -Timezone $Timezone
        }
        Write-Output $Datasource
    }
}

function ParseDatasourceTypes($DatasourceTypes,$Timezone) {
    $DatasourceTypes = @($DatasourceTypes)
    foreach ($DatasourceType in $DatasourceTypes) {
        Write-Output $DatasourceType
    }
}

function ParseDatasourceConfig($DatasourceConfig,$Timezone) {
    $DatasourceConfig = @($DatasourceConfig)
    foreach ($DatasourceConfig in $DatasourceConfig) {
        if ($DatasourceConfig.packages | Where-Object { $_.id -eq "foundation" }) {
            $DatasourceConfig | Add-Member -MemberType ScriptProperty -Name "foundation" -Value { $this.packages | Where-Object { $_.id -eq "foundation" } }
            if (!$DatasourceConfig.foundation.attributes.password) {
                $DatasourceConfig.foundation.attributes | Add-Member -MemberType NoteProperty -Name password -Value "" -force
            }
            if ($DatasourceConfig.foundation.attributes.'partner.ip' -and !$DatasourceConfig.foundation.attributes.'partner.password') {
                $DatasourceConfig.foundation.attributes | Add-Member -MemberType NoteProperty -Name 'partner.password' -Value "" -force
            }
        }
        if ($DatasourceConfig.packages | Where-Object { $_.id -eq "storageperformance" }) {
            $DatasourceConfig | Add-Member -MemberType ScriptProperty -Name "storageperformance" -Value { $this.packages | Where-Object { $_.id -eq "storageperformance" } }
        }
        if ($DatasourceConfig.packages | Where-Object { $_.id -eq "hostvirtualization" }) {
            $DatasourceConfig | Add-Member -MemberType ScriptProperty -Name "hostvirtualization" -Value { $this.packages | Where-Object { $_.id -eq "hostvirtualization" } }
        }
        if ($DatasourceConfig.packages | Where-Object { $_.id -eq "performance" }) {
            $DatasourceConfig | Add-Member -MemberType ScriptProperty -Name "performance" -Value { $this.packages | Where-Object { $_.id -eq "performance" } }
        }
        if ($DatasourceConfig.packages | Where-Object { $_.id -eq "cloud" }) {
            $DatasourceConfig | Add-Member -MemberType ScriptProperty -Name "cloud" -Value { $this.packages | Where-Object { $_.id -eq "cloud" } }
        }
        Write-Output $DatasourceConfig
    }
}

function ParseChanges($Changes,$Timezone) {
    $Changes = @($Changes)
    foreach ($Change in $Changes) {
        if ($Change.time) {
            $Change.time = $Change.time | Get-Date
        }

        Write-Output $Change
    }
}

function ParseEvents($Events,$Timezone) {
    $Events = @($Events)
    foreach ($Event in $Events) {
        if ($Event.StartTime) {
            $Event.StartTime = $Event.StartTime | Get-Date
        }
        if ($Event.EndTime) {
            $Event.EndTime = $Event.EndTime | Get-Date
        }

        Write-Output $Event
    }
}

function ParseCertificates($Certificates,$Timezone) {
    $Certificates = @($Certificates)
    foreach ($Certificate in $Certificates) {
        if ($Certificate.ExpirationDate) {
            $Certificate.ExpirationDate = $Certificate.ExpirationDate | Get-Date
        }

        Write-Output $Certificate
    }
}

function ParseLicenseStatus($LicenseStatus,$Timezone) {
    $LicenseStatus.LicenseParts = ParseLicenses -Licenses $LicenseStatus.LicenseParts -Timezone $Timezone

    Write-Output $LicenseStatus
}

function ParseLicenses($Licenses,$Timezone) {
    $Licenses = @($Licenses)
    foreach ($License in $Licenses) {
        if ($License.ExpirationDate) {
            $License.ExpirationDate = $License.ExpirationDate | Get-Date
        }

        Write-Output $License
    }
}

function ParseUsers($Users,$Timezone) {
    $Users = @($Users)
    foreach ($User in $Users) {
        if ($User.lastLogin) {
            $User.lastLogin = $User.lastLogin | Get-Date
        }

        Write-Output $User
    }
}

function ParseDatastores($Datastores,$Timezone) {
    $Datastores = @($Datastores)
    foreach ($Datastore in $Datastores) {
        if ($Datastore.performance) {
            $Datastore.performance = ParsePerformance -Performance $Datastore.performance -Timezone $Timezone
        }

        Write-Output $Datastore
    }
}

function ParseSwitches($Switches,$Timezone) {
    $Switches = @($Switches)
    foreach ($Switch in $Switches) {
        if ($Switch.createTime) {
            $Switch.createTime = $Switch.createTime | Get-Date
        }
        if ($Switch.performance) {
            $Switch.performance = ParsePerformance -Performance $Switch.performance -Timezone $Timezone
        }
        if ($Switch.fabric) {
            $Switch.fabric = ParseFabrics -Fabrics $Switch.fabric -Timezone $Timezone
        }
        if ($Switch.ports) {
            $Switch.ports = ParsePorts -Ports $Switch.ports -Timezone $Timezone
        }
        if ($Switch.annotations) {
            $Switch.annotations = ParseAnnotations -Annotations $Switch.annotations -Timezone $Timezone
        }
        if ($Switch.datasources) {
            $Switch.datasources = ParseDatasources -Datasources $Switch.datasources -Timezone $Timezone
        }
        if ($Switch.applications) {
            $Switch.applications = ParseApplications -Applications $Switch.applications -Timezone $Timezone
        }

        Write-Output $Switch
    }
}

function ParsePerformance($Performance,$Timezone) {
    if ($Performance.accessed) {
        $Performance.accessed.start = $Performance.accessed.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.accessed.end = $Performance.accessed.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.cacheHitRatio) {
        if ($Performance.cacheHitRatio.read) {
            $Performance.cacheHitRatio.read.start = $Performance.cacheHitRatio.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
            $Performance.cacheHitRatio.read.end = $Performance.cacheHitRatio.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        }
        if ($Performance.cacheHitRatio.write) {
            $Performance.cacheHitRatio.write.start = $Performance.cacheHitRatio.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
            $Performance.cacheHitRatio.write.end = $Performance.cacheHitRatio.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        }
        if ($Performance.cacheHitRatio.total) {
            $Performance.cacheHitRatio.total.start = $Performance.cacheHitRatio.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
            $Performance.cacheHitRatio.total.end = $Performance.cacheHitRatio.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        }
    }
    if ($Performance.cpuUtilization) {
        $Performance.cpuUtilization.total.start = $Performance.cpuUtilization.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.cpuUtilization.total.end = $Performance.cpuUtilization.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.diskIops) {
        $Performance.diskIops.read.start = $Performance.diskIops.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.read.end = $Performance.diskIops.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.write.start = $Performance.diskIops.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.write.end = $Performance.diskIops.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.totalMax.start = $Performance.diskIops.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.totalMax.end = $Performance.diskIops.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.total.start = $Performance.diskIops.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskIops.total.end = $Performance.diskIops.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.diskLatency) {
        $Performance.diskLatency.read.start = $Performance.diskLatency.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.read.end = $Performance.diskLatency.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.write.start = $Performance.diskLatency.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.write.end = $Performance.diskLatency.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.total.start = $Performance.diskLatency.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.total.end = $Performance.diskLatency.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.totalMax.start = $Performance.diskLatency.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskLatency.totalMax.end = $Performance.diskLatency.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.diskThroughput) {
        $Performance.diskThroughput.read.start = $Performance.diskThroughput.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.read.end = $Performance.diskThroughput.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.write.start = $Performance.diskThroughput.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.write.end = $Performance.diskThroughput.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.totalMax.start = $Performance.diskThroughput.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.totalMax.end = $Performance.diskThroughput.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.total.start = $Performance.diskThroughput.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.diskThroughput.total.end = $Performance.diskThroughput.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.fcWeightedPortBalanceIndex) {
        $Performance.fcWeightedPortBalanceIndex.start = $Performance.fcWeightedPortBalanceIndex.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.fcWeightedPortBalanceIndex.end = $Performance.fcWeightedPortBalanceIndex.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.iops) {
        $Performance.iops.read.start = $Performance.iops.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.read.end = $Performance.iops.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.write.start = $Performance.iops.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.write.end = $Performance.iops.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.totalMax.start = $Performance.iops.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.totalMax.end = $Performance.iops.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.total.start = $Performance.iops.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.iops.total.end = $Performance.iops.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.ipThroughput) {
        $Performance.ipThroughput.read.start = $Performance.ipThroughput.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.read.end = $Performance.ipThroughput.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.write.start = $Performance.ipThroughput.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.write.end = $Performance.ipThroughput.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.totalMax.start = $Performance.ipThroughput.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.totalMax.end = $Performance.ipThroughput.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.total.start = $Performance.ipThroughput.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.ipThroughput.total.end = $Performance.ipThroughput.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.latency) {
        $Performance.latency.read.start = $Performance.latency.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.read.end = $Performance.latency.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.write.start = $Performance.latency.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.write.end = $Performance.latency.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.total.start = $Performance.latency.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.total.end = $Performance.latency.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.totalMax.start = $Performance.latency.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.latency.totalMax.end = $Performance.latency.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.memoryUtilization) {
        $Performance.memoryUtilization.total.start = $Performance.memoryUtilization.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.memoryUtilization.total.end = $Performance.memoryUtilization.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.partialBlocksRatio.total) {
        $Performance.partialBlocksRatio.total.start = $Performance.partialBlocksRatio.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp
        $Performance.partialBlocksRatio.total.end = $Performance.partialBlocksRatio.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp
    }
    if ($Performance.swapRate) {
        $Performance.swapRate.inRate.start = $Performance.swapRate.inRate.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.inRate.end = $Performance.swapRate.inRate.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.outRate.start = $Performance.swapRate.outRate.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.outRate.end = $Performance.swapRate.outRate.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.totalMaxRate.start = $Performance.swapRate.totalMaxRate.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.totalMaxRate.end = $Performance.swapRate.totalMaxRate.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.totalRate.start = $Performance.swapRate.totalRate.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.swapRate.totalRate.end = $Performance.swapRate.totalRate.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.throughput) {
        $Performance.throughput.read.start = $Performance.throughput.read.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.read.end = $Performance.throughput.read.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.write.start = $Performance.throughput.write.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.write.end = $Performance.throughput.write.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.totalMax.start = $Performance.throughput.totalMax.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.totalMax.end = $Performance.throughput.totalMax.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.total.start = $Performance.throughput.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.throughput.total.end = $Performance.throughput.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.writePending.total) {
        $Performance.writePending.total.start = $Performance.writePending.total.start | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
        $Performance.writePending.total.end = $Performance.writePending.total.end | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone
    }
    if ($Performance.history) {
        $Performance.history = ParsePerformanceHistory -PerformanceHistory $Performance.history -Timezone $Timezone
    }

    Write-Output $Performance
}

function ParsePerformanceHistory($PerformanceHistory,$Timezone) {
    if ($PerformanceHistory[0].count -eq 2) {
        $PerformanceHistory = foreach ($entry in $PerformanceHistory) {
            if ($entry[1] -replace ' ','') {
                $entry[1] | Add-Member -MemberType NoteProperty -Name timestamp -Value ($entry[0] | Where-Object { $_ } | ConvertFrom-UnixTimestamp -Timezone $Timezone) -PassThru
            }
        }
    }
    Write-Output $PerformanceHistory
}

function ParseVirtualMachines($VirtualMachines,$Timezone) {
    $VirtualMachines = @($VirtualMachines)
    foreach ($VirtualMachine in $VirtualMachines) {
        if ($VirtualMachine.createTime) {
            $VirtualMachine.createTime = $VirtualMachine.createTime | Get-Date
        }
        if ($VirtualMachine.powerStateChangeTime) {
            $VirtualMachine.powerStateChangeTime = $VirtualMachine.powerStateChangeTime | Get-Date
        }
        if ($VirtualMachine.performance) {
            $VirtualMachine.performance = ParsePerformance -Performance $VirtualMachine.performance -Timezone $Timezone
        }
        if ($VirtualMachine.vmdks) {
            $VirtualMachine.vmdks = ParseVmdks -Vmdks $VirtualMachine.vmdks -Timezone $Timezone
        }
        if ($VirtualMachine.host) {
            $VirtualMachine.host = ParseHosts -Hosts $VirtualMachine.host -Timezone $Timezone
        }
        if ($VirtualMachine.ports) {
            $VirtualMachine.ports = ParsePorts -Ports $VirtualMachine.ports -Timezone $Timezone
        }
        if ($VirtualMachine.dataStore) {
            $VirtualMachine.dataStore = ParseDatastores -Datastores $VirtualMachine.dataStore -Timezone $Timezone
        }
        if ($VirtualMachine.applications) {
            $VirtualMachine.applications = ParseApplications -Applications $VirtualMachine.applications -Timezone $Timezone
        }
        if ($VirtualMachine.fileSystems) {
            $VirtualMachine.fileSystems = ParseFileSystems -FileSystems $VirtualMachine.fileSystems -Timezone $Timezone
        }
        if ($VirtualMachine.storageResources) {
            $VirtualMachine.storageResources = ParseStorageResources -StorageResources $VirtualMachine.storageResources -Timezone $Timezone
        }
        if ($VirtualMachine.annotations) {
            $VirtualMachine.annotations = ParseAnnotations -Annotations $VirtualMachine.annotations -Timezone $Timezone
        }
        if ($VirtualMachine.datasources) {
            $VirtualMachine.datasources = ParseDatasources -Datasources $VirtualMachine.datasources -Timezone $Timezone
        }

        Write-Output $VirtualMachine
    }
}

function ParseFilesystems($FileSystems,$Timezone) {
    $FileSystems = @($FileSystems)
    foreach ($FileSystem in $FileSystems) {
        Write-Output $FileSystem
    }
}

function ParseVmdks($Vmdks,$Timezone) {
    $Vmdks = @($Vmdks)
    foreach ($Vmdk in $Vmdks) {
        if ($vmdk.dataStore) {
            $vmdk.dataStore = ParseDatastores -Datastores $vmdk.dataStore -Timezone $Timezone
        }
        if ($vmdk.virtualMachine) {
            $vmdk.virtualMachine = ParseVirtualMachines -VirtualMachines $vmdk.virtualMachine -Timezone $Timezone
        }
        if ($vmdk.performance) {
            $vmdk.performance = ParsePerformance -Performance $vmdk.performance -Timezone $Timezone
        }
        if ($vmdk.storageResources) {
            $vmdk.storageResources = ParseStorageResources -StorageResources $vmdk.storageResources -Timezone $Timezone
        }
        if ($vmdk.annotations) {
            $vmdk.annotations = ParseAnnotations -Annotations $vmdk.annotations -Timezone $Timezone
        }
        if ($vmdk.datasources) {
            $vmdk.datasources = ParseDatasources -Datasources $vmdk.datasources -Timezone $Timezone
        }

        Write-Output $vmdk
    }
}

function ParseHosts($Hosts,$Timezone) {
    foreach ($HostInstance in $Hosts) {
        if ($HostInstance.createTime) {
            $HostInstance.createTime = $HostInstance.createTime | Get-Date
        }
        if ($HostInstance.performance) {
            $HostInstance.performance = ParsePerformance -Performance $HostInstance.performance -Timezone $Timezone
        }
        if ($HostInstance.storageResources) {
            $HostInstance.storageResources = ParseStorageResources -StorageResources $HostInstance.storageResources -Timezone $Timezone
        }
        if ($HostInstance.fileSystems) {
            $HostInstance.fileSystems = ParseFileSystems -FileSystems $HostInstance.fileSystems -Timezone $Timezone
        }
        if ($HostInstance.ports) {
            $HostInstance.ports = ParsePorts -Ports $HostInstance.ports -Timezone $Timezone
        }
        if ($HostInstance.applications) {
            $HostInstance.applications = ParseApplications -Applications $HostInstance.applications -Timezone $Timezone
        }
        if ($HostInstance.virtualMachines) {
            $HostInstance.virtualMachines = ParseVirtualMachines -VirtualMachines $HostInstance.virtualMachines -Timezone $Timezone
        }
        if ($HostInstance.clusterHosts) {
            $HostInstance.clusterHosts = ParseHosts -Hosts $HostInstance.clusterHosts -Timezone $Timezone
        }
        if ($HostInstance.annotations) {
            $HostInstance.annotations = ParseAnnotations -Annotations $HostInstance.annotations -Timezone $Timezone
        }
        if ($HostInstance.datasources) {
            $HostInstance.datasources = ParseDatasources -Datasources $HostInstance.datasources -Timezone $Timezone
        }

        Write-Output $HostInstance
    }
}

function ParseTopologies($Topologies,$Timezone) {
    foreach ($Topology in $Topologies) {
        if ($Topology.nodes) {
            $Topology.nodes = ParseTopologyNodes -Nodes $Topology.nodes -Timezone $Timezone
        }
        if ($Topology.links) {
            $Topology.links = ParseTopologyLinks -Links $Topology.links -Timezone $Timezone
        }

        Write-Output $Topology
    }
}

function ParseTopologyNodes($Nodes,$Timezone) {
    foreach ($Node in $Nodes) {
        Write-Output $Node
    }
}

function ParseTopologyLinks($Links,$Timezone) {
    foreach ($Link in $Links) {
        Write-Output $Link
    }
}

function ParsePorts($Ports,$Timezone) {
    $Ports = @($Ports)
    foreach ($Port in $Ports) {
        if ($Port.connectedPorts) {
            $Port.connectedPorts = ParsePorts -Ports $Port.connectedPorts -Timezone $Timezone
        }
        if ($Port.performance) {
            $Port.performance = ParsePerformance -Performance $Port.performance -Timezone $Timezone
        }
        if ($Port.device) {
            $Port.device = ParseDevices -Devices $Port.device -Timezone $Timezone
        }
        if ($Port.fabrics) {
            $Port.fabrics = ParseFabrics -Fabrics $Port.fabrics -Timezone $Timezone
        }
        if ($Port.annotations) {
            $Port.annotations = ParseAnnotations -Annotations $Port.annotations -Timezone $Timezone
        }
        if ($Port.datasources) {
            $Port.datasources = ParseDatasources -Datasources $Port.datasources -Timezone $Timezone
        }
        if ($Port.application) {
            $Port.application = ParseApplication -Application $Port.application -Timezone $Timezone
        }

        Write-Output $Port
    }
}

function ParseDevices($Device,$Timezone) {
    $Devices = @($Devices)
    foreach ($Device in $Devices) {
        if ($Device.performance) {
            $Device.performance = ParsePerformance -Performance $Device.performance -Timezone $Timezone
        }
        if ($Device.device) {
            $Device.device = ParseDevice -Device $Device.device -Timezone $Timezone
        }
        if ($Device.fabrics) {
            $Device.fabrics = ParseFabrics -Fabrics $Device.fabrics -Timezone $Timezone
        }
        if ($Device.annotations) {
            $Device.annotations = ParseAnnotations -Annotations $Device.annotations -Timezone $Timezone
        }
        if ($Device.datasources) {
            $Device.datasources = ParseDatasources -Datasources $Device.datasources -Timezone $Timezone
        }
        if ($Device.application) {
            $Device.application = ParseApplication -Application $Device.application -Timezone $Timezone
        }

        Write-Output $Device
    }
}

function ParseApplications($Applications,$Timezone) {
    $Applications = @($Applications)
    foreach ($Application in $Applications) {
        if (!$Application.isBusinessEntityDefault) {
            Write-Output $Application
        }
    }
}

function ParseAnnotations($Annotations,$Timezone) {
    $Annotations = @($Annotations)
    foreach ($Annotation in $Annotations) {
        Write-Output $Annotation
    }
}

function ParseAnnotationValues($AnnotationValues,$Timezone) {
    $AnnotationValues = @($AnnotationValues)
    foreach ($AnnotationValue in $AnnotationValues) {
        Write-Output $AnnotationValue
    }
}

function ParseComputeResources($ComputeResources,$Timezone) {
    $ComputeResources = @($ComputeResources)
    foreach ($ComputeResource in $ComputeResources) {
        if ($ComputeResource.createTime) {
            $ComputeResource.createTime = $ComputeResource.createTime | Get-Date
        }
        if ($ComputeResource.performance) {
            $ComputeResource.performance = ParsePerformance -Performance $ComputeResource.performance -Timezone $Timezone
        }
        if ($ComputeResource.storageResources) {
            $ComputeResource.storageResources = ParseStorageResources -StorageResources $ComputeResource.storageResources -Timezone $Timezone
        }
        if ($ComputeResource.fileSystems) {
            $ComputeResource.fileSystems = ParseFileSystems -FileSystems $ComputeResource.fileSystems -Timezone $Timezone
        }
        if ($ComputeResource.ports) {
            $ComputeResource.ports = ParsePorts -Ports $ComputeResource.ports -Timezone $Timezone
        }
        if ($ComputeResource.applications) {
            $ComputeResource.applications = ParseApplications -Applications $ComputeResource.applications -Timezone $Timezone
        }
        if ($ComputeResource.virtualMachines) {
            $ComputeResource.virtualMachines = ParseVirtualMachines -VirtualMachines $ComputeResource.virtualMachines -Timezone $Timezone
        }
        if ($ComputeResource.clusterHosts) {
            $ComputeResource.clusterHosts = ParseHosts -Hosts $ComputeResource.clusterHosts -Timezone $Timezone
        }
        if ($ComputeResource.annotations) {
            $ComputeResource.annotations = ParseAnnotations -Annotations $ComputeResource.annotations -Timezone $Timezone
        }
        if ($ComputeResource.datasources) {
            $ComputeResource.datasources = ParseDatasources -Datasources $ComputeResource.datasources -Timezone $Timezone
        }

        Write-Output $ComputeResource
    }
}

function ParseStorageResources($StorageResources,$Timezone) {
    $StorageResources = @($StorageResources)
    foreach ($StorageResource in $StorageResources) {
        if ($StorageResource.createTime) {
            $StorageResource.createTime = $StorageResource.createTime | Get-Date
        }
        if ($StorageResource.powerStateChangeTime) {
            $StorageResource.powerStateChangeTime = $StorageResource.powerStateChangeTime | Get-Date
        }
        if ($StorageResource.performance) {
            $StorageResource.performance = ParsePerformance -Performance $StorageResource.performance -Timezone $Timezone
        }
        if ($StorageResource.computeResources) {
            $StorageResource.computeResources = ParseComputeResources -ComputeResources $StorageResource.computeResources -Timezone $Timezone
        }
        if ($StorageResource.fileSystems) {
            $StorageResource.fileSystems = ParseFileSystems -FileSystems $StorageResource.fileSystems -Timezone $Timezone
        }
        if ($StorageResource.storagePools) {
            $StorageResource.storagePools = ParseStoragePools -StoragePools $StorageResource.storagePools -Timezone $Timezone
        }
        if ($StorageResource.applications) {
            $StorageResource.applications = ParseApplications -Applications $StorageResource.applications -Timezone $Timezone
        }
        if ($StorageResource.virtualMachines) {
            $StorageResource.virtualMachines = ParseVirtualMachines -VirtualMachines $StorageResource.virtualMachines -Timezone $Timezone
        }
        if ($StorageResource.annotations) {
            $StorageResource.annotations = ParseAnnotations -Annotations $StorageResource.annotations -Timezone $Timezone
        }
        if ($StorageResource.datasources) {
            $StorageResource.datasources = ParseDatasources -Datasources $StorageResource.datasources -Timezone $Timezone
        }

        Write-Output $StorageResource
    }
}

function ParseVolumes($Volumes,$Timezone) {
    $Volumes = @($Volumes)
    foreach ($Volume in $Volumes) {
        if ($Volume.storage) {
            $Volume.storage = ParseStorages -Storages $Volume.storage -Timezone $Timezone
        }
        if ($Volume.computeResources) {
            $Volume.computeResources = ParseComputeResources -ComputeResources $Volume.computeResources -Timezone $Timezone
        }
        if ($Volume.storagePool) {
            $Volume.storagePool = ParseStoragePools -StoragePools $Volume.storagePool -Timezone $Timezone
        }
        if ($Volume.virtualStoragePool) {
            $Volume.virtualStoragePool = ParseStoragePools -StoragePools $Volume.virtualStoragePool -Timezone $Timezone
        }
        if ($Volume.qtrees) {
            $Volume.qtrees = ParseAnnotations -Annotations $Volume.qtrees -Timezone $Timezone
        }
        if ($Volume.internalVolume) {
            $Volume.internalVolume = ParseInternalVolumes -InternalVolumes $Volume.internalVolume -Timezone $Timezone
        }
        if ($Volume.dataStores) {
            $Volume.dataStores = ParseDatastores -Datastores $Volume.dataStores -Timezone $Timezone
        }
        if ($Volume.annotations) {
            $Volume.annotations = ParseAnnotations -Annotations $Volume.annotations -Timezone $Timezone
        }
        if ($Volume.performance) {
            $Volume.performance = ParsePerformance -Performance $Volume.performance -Timezone $Timezone
        }
        if ($Volume.ports) {
            $Volume.ports = ParsePorts -Ports $Volume.ports -Timezone $Timezone -Timezone $Timezone
        }
        if ($Volume.storageNodes) {
            $Volume.storageNodes = ParseStorageNodes -StorageNodes $Volume.storageNodes -Timezone $Timezone
        }
        if ($Volume.replicaSources) {
            $Volume.replicaSources = ParseVolumes -Volumes $Volume.replicaSources -Timezone $Timezone
        }
        if ($Volume.applications) {
            $Volume.applications = ParseApplications -Applications $Volume.applications -Timezone $Timezone
        }
        if ($Volume.datasources) {
            $Volume.datasources = ParseDatasources -Datasources $Volume.datasources -Timezone $Timezone
        }

        Write-Output $Volume
    }
}

function ParseInternalVolumes($InternalVolumes,$Timezone) {
    $InternalVolumes = @($InternalVolumes)
    foreach ($InternalVolume in $InternalVolumes) {
        if ($InternalVolume.storage) {
            $InternalVolume.storage = ParseStorages -Storages $InternalVolume.storage -Timezone $Timezone
        }
        if ($InternalVolume.computeResources) {
            $InternalVolume.computeResources = ParseComputeResources -ComputeResources $InternalVolume.computeResources -Timezone $Timezone
        }
        if ($InternalVolume.storagePool) {
            $InternalVolume.storagePool = ParseStoragePools -StoragePools $InternalVolume.storagePool -Timezone $Timezone
        }
        if ($InternalVolume.performance) {
            $InternalVolume.performance = ParsePerformance -Performance $InternalVolume.performance -Timezone $Timezone
        }
        if ($InternalVolume.volumes) {
            $InternalVolume.volumes = ParseVolumes -Volumes $InternalVolume.volumes -Timezone $Timezone
        }
        if ($InternalVolume.storageNodes) {
            $InternalVolume.storageNodes = ParseStorageNodes -StorageNodes $InternalVolume.storageNodes -Timezone $Timezone
        }
        if ($InternalVolume.datasources) {
            $InternalVolume.datasources = ParseDatasources -Datasources $InternalVolume.datasources -Timezone $Timezone
        }
        if ($InternalVolume.datastores) {
            $InternalVolume.datastores = ParseDatastores -Datastores $InternalVolume.datastores -Timezone $Timezone
        }
        if ($InternalVolume.applications) {
            $InternalVolume.applications = ParseApplications -Applications $InternalVolume.applications -Timezone $Timezone
        }
        if ($InternalVolume.annotations) {
            $InternalVolume.annotations = ParseAnnotations -Annotations $InternalVolume.annotations -Timezone $Timezone
        }
        if ($InternalVolume.qtrees) {
            $InternalVolume.qtrees = ParseAnnotations -Annotations $InternalVolume.qtrees -Timezone $Timezone
        }

        Write-Output $InternalVolume
    }
}

function ParseQtrees($Qtrees,$Timezone) {
    $Qtrees = @($Qtrees)
    foreach ($Qtree in $Qtrees) {
        if ($Qtree.quotaCapacity) {
            $Qtree.quotaCapacity = ParseQuotaCapacities -QuotaCapacities $Qtree.quotaCapacity -Timezone $Timezone
        }
        if ($Qtree.storage) {
            $Qtree.storage = ParseStorages -Storages $Qtree.storage -Timezone $Timezone
        }
        if ($Qtree.internalVolume) {
            $Qtree.internalVolume = ParseInternalVolumes -InternalVolumes $Qtree.internalVolume -Timezone $Timezone
        }
        if ($Qtree.shares) {
            $Qtree.shares = ParseShares -Shares $Qtree.shares -Timezone $Timezone
        }
        if ($Qtree.annotations) {
            $Qtree.annotations = ParseAnnotations -Annotations $Qtree.annotations -Timezone $Timezone
        }
        if ($Qtree.applications) {
            $Qtree.applications = ParseApplications -Applications $Qtree.applications -Timezone $Timezone
        }
        if ($Qtree.volumes) {
            $Qtree.volumes = ParseVolumes -Volumes $Qtree.volumes -Timezone $Timezone
        }

        Write-Output $Qtree
    }
}

function ParseQuotaCapacities($QuotaCapacities,$Timezone) {
    $QuotaCapacities = @($QuotaCapacities)
    foreach ($QuotaCapacity in $QuotaCapacities) {
        Write-Output $QuotaCapacity
    }
}

function ParseShares($Shares) {
    $Shares = @($Shares)
    foreach ($Share in $Shares) {
        Write-Output $Share
    }
}

function ParseStoragePools($StoragePools,$Timezone) {
    $StoragePools = @($StoragePools)
    foreach ($StoragePool in $StoragePools) {
        if ($StoragePool.performance) {
            $StoragePool.performance = ParsePerformance -Performance $StoragePool.performance -Timezone $Timezone
        }
        if ($StoragePool.storage) {
            $StoragePool.storage = ParseStorages -Storages $StoragePool.storage -Timezone $Timezone
        }
        if ($StoragePool.disks) {
            $StoragePool.disks = ParseDisks -Disks $StoragePool.disks -Timezone $Timezone
        }
        if ($StoragePool.storageResources) {
            $StoragePool.storageResources = ParseStorageResources -StorageResources $StoragePool.storageResources -Timezone $Timezone
        }
        if ($StoragePool.internalVolumes) {
            $StoragePool.internalVolumes = ParseInternalVolumes -InternalVolumes $StoragePool.internalVolumes -Timezone $Timezone
        }
        if ($StoragePool.volumes) {
            $StoragePool.volumes = ParseVolumes -Volumes $StoragePool.volumes -Timezone $Timezone
        }
        if ($StoragePool.storageNodes) {
            $StoragePool.storageNodes = ParseStorageNodes -StorageNodes $StoragePool.storageNodes -Timezone $Timezone
        }
        if ($StoragePool.datasources) {
            $StoragePool.datasources = ParseDatasources -Datasources $StoragePool.datasources -Timezone $Timezone
        }
        if ($StoragePool.annotations) {
            $StoragePool.annotations = ParseAnnotations -Annotations $StoragePool.annotations -Timezone $Timezone
        }

        Write-Output $StoragePool
    }
}

function ParseStorages($Storages, $Timezone) {
    $Storages = @($Storages)
    foreach ($Storage in $Storages) {
        if ($Storage.createTime) {
            $Storage.createTime = $Storage.createTime | Get-Date
        }
        if ($Storage.storageNodes) {
            $Storage.storageNodes = ParseStorageNodes -StorageNodes $Storage.storageNodes -Timezone $Timezone
        }
        if ($Storage.storagePools) {
            $Storage.storagePools = ParseStoragePools -StoragePools $Storage.storagePools -Timezone $Timezone
        }
        if ($Storage.storageResources) {
            $Storage.storageResources = ParseStorageResources -StorageResources $Storage.storageResources -Timezone $Timezone
        }
        if ($Storage.internalVolumes) {
            $Storage.internalVolumes = ParseInternalVolumes -InternalVolumes $Storage.internalVolumes -Timezone $Timezone
        }
        if ($Storage.volumes) {
            $Storage.volumes = ParseVolumes -Volumes $Storage.volumes -Timezone $Timezone
        }
        if ($Storage.disks) {
            $Storage.disks = ParseDisks -Disks $Storage.disks -Timezone $Timezone
        }
        if ($Storage.datasources) {
            $Storage.datasources = ParseDatasources -Datasources $Storage.datasources -Timezone $Timezone
        }
        if ($Storage.ports) {
            $Storage.ports = ParsePorts -Ports $Storage.ports -Timezone $Timezone
        }
        if ($Storage.annotations) {
            $Storage.annotations = ParseAnnotations -Annotations $Storage.annotations -Timezone $Timezone
        }
        if ($Storage.qtrees) {
            $Storage.qtrees = ParseQtrees -Qtrees $Storage.qtrees -Timezone $Timezone
        }
        if ($Storage.shares) {
            $Storage.shares = ParseShares -Shares $Storage.shares -Timezone $Timezone
        }
        if ($Storage.applications) {
            $Storage.applications = ParseApplications -Applications $Storage.applications -Timezone $Timezone
        }
        if ($Storage.performance) {
            $Storage.performance = ParsePerformance -Performance $Storage.performance -Timezone $Timezone
        }

        Write-Output $Storage
    }
}

function ParseStorageNodes($StorageNodes,$Timezone) {
    $StorageNodes = @($StorageNodes)
    foreach ($StorageNode in $StorageNodes) {
        if ($StorageNode.performance) {
            $StorageNode.performance = ParsePerformance -Performance $StorageNode.performance -Timezone $Timezone
        }

        Write-Output $StorageNode
    }
}

function ParseDisks($Disks,$Timezone) {
    $Disks = @($Disks)
    foreach ($Disk in $Disks) {
        if ($Disk.performance) {
            $Disk.performance = ParsePerformance -Performance $Disk.performance -Timezone $Timezone
        }
        if ($Disk.storage) {
            $Disk.storage = ParseStorages -Storages $Disk.storage -Timezone $Timezone
        }
        if ($Disk.storageResources) {
            $Disk.storageResources = ParseStorageResources -StorageResources $Disk.storageResources -Timezone $Timezone
        }
        if ($Disk.backendVolumes) {
            $Disk.backendVolumes = ParseVolumes -Volumes $Disk.backendVolumes -Timezone $Timezone
        }
        if ($Disk.datasources) {
            $Disk.datasources = ParseDatasources -Datasources $Disk.datasources -Timezone $Timezone
        }
        if ($Disk.annotations) {
            $Disk.annotations = ParseAnnotations -Annotations $Disk.annotations -Timezone $Timezone
        }

        Write-Output $Disk
    }
}

function ParseFabrics($Fabrics,$Timezone) {
    $Fabrics = @($Fabrics)
    foreach ($Fabric in $Fabrics) {
        if ($Fabric.datasources) {
            $Fabric.datasources = ParseDatasources -Datasources $Fabric.datasources -Timezone $Timezone
        }
        if ($Fabric.switches) {
            $Fabric.switches = ParseSwitches -Switches $Fabric.switches -Timezone $Timezone
        }

        Write-Output $Fabric
    }
}

function ParsePatchStatus($PatchStatus,$Timezone) {
    $PatchStatus = @($PatchStatus)
    foreach ($PatchStatus in $PatchStatus) {
        if ($PatchStatus.createTime) {
            $PatchStatus.createTime = [DateTime]$PatchStatus.createTime
        }
        if ($PatchStatus.lastUpdateTime) {
            $PatchStatus.lastUpdateTime = [DateTime]$PatchStatus.lastUpdateTime
        }
        if ($PatchStatus.datasourceTypes) {
            $PatchStatus.datasourceTypes = ParseDatasourceTypes -DatasourceTypes $PatchStatus.datasourceTypes -Timezone $Timezone
        }

        Write-Output $PatchStatus
    }
}

## generic functions ##

<#
    .SYNOPSIS
    Retrieve OCI Webinterface Metadata
    .DESCRIPTION
    Retrieve OCI Webinterface Metadata
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciMetadata {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/uiserver/webui/v1/metadata"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim
        }

        # TODO: Implement parsing
        $Metadata = $Result
        Write-Output $Metadata
    }
}

<#
.EXAMPLE
Connect-OciServer -Name ociserver.example.com -Credential (Get-Credential)
 
Name : ociserver.example.com
BaseURI : https://ociserver.example.com
Credential : System.Management.Automation.PSCredential
Headers : {Authorization}
APIVersion : 1.3
Timezone : (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
#>

function global:Connect-OciServer {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="The name of the OCI Server. This value may also be a string representation of an IP address. If not an address, the name must be resolvable to an address.")][String]$Name,
        [parameter(Mandatory=$True,
                   Position=1,
                   HelpMessage="A System.Management.Automation.PSCredential object containing the credentials needed to log into the OCI server.")][System.Management.Automation.PSCredential]$Credential,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="This cmdlet always tries to establish a secure HTTPS connection to the OCI server, but it will fall back to HTTP if necessary. Specify -HTTP to skip the HTTPS connection attempt and only try HTTP.")][Switch]$HTTP,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="This cmdlet always tries to establish a secure HTTPS connection to the OCI server, but it will fall back to HTTP if necessary. Specify -HTTPS to fail the connection attempt in that case rather than fall back to HTTP.")][Switch]$HTTPS,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="If the OCI server certificate cannot be verified, the connection will fail. Specify -Insecure to ignore the validity of the OCI server certificate.")][Switch]$Insecure,
        [parameter(Position=4,
                   Mandatory=$False,
                   HelpMessage="Specify -Transient to not set the global variable `$CurrentOciServer.")][Switch]$Transient,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="As the timezone of the OCI Server is not available via the REST API, it needs to be manually set so that all timestamps are displayed with the correct timezone. By default the timezone will be set to the local timezone of the PowerShell environment.")][PSObject]$Timezone,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="Timeout value for HTTP connections. Defaults to 600 seconds.")][Int]$Timeout
    )

    $EncodedAuthorization = [System.Text.Encoding]::UTF8.GetBytes($Credential.UserName + ':' + $Credential.GetNetworkCredential().Password)
    $EncodedPassword = [System.Convert]::ToBase64String($EncodedAuthorization)
    $Headers = @{"Authorization"="Basic $($EncodedPassword)"}

    # check if untrusted SSL certificates should be ignored
    if ($Insecure) {
        if ($PSVersionTable.PSVersion.Major -lt 6) {
            [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
        }
        else {
            if (!$PSDefaultParameterValues."Invoke-RestMethod:SkipCertificateCheck") {
                $PSDefaultParameterValues.Add("Invoke-RestMethod:SkipCertificateCheck",$true)
            }
            else {
                $PSDefaultParameterValues."Invoke-RestMethod:SkipCertificateCheck"=$true
            }
        }
    }

    # TODO: Remove as soon as PowerShell 6 fixes OSVersion implementation
    try {
        if ([environment]::OSVersion.Platform -match "Win") {
            # check if proxy is used
            $ProxyRegistry = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
            $ProxySettings = Get-ItemProperty -Path $ProxyRegistry
            if ($ProxySettings.ProxyEnable) {
                Write-Warning "Proxy Server $($ProxySettings.ProxyServer) configured in Internet Explorer may be used to connect to the OCI server!"
            }
            if ($ProxySettings.AutoConfigURL) {
                Write-Warning "Proxy Server defined in automatic proxy configuration script $($ProxySettings.AutoConfigURL) configured in Internet Explorer may be used to connect to the OCI server!"
            }
        }
    }
    catch {}

    if ($HTTPS -or !$HTTP) {
        Try {
            $BaseURI = "https://$Name"
            $Response = Invoke-RestMethod -Session Session -Method Post -Uri "$BaseURI/rest/v1/login" -TimeoutSec $Timeout -Headers $Headers
            $APIVersion = [System.Version]$Response.apiVersion
        }
        Catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            if ($_.Exception.Message -match "Unauthorized") {
                Write-Error "Authorization for $BaseURI/rest/v1/login with user $($Credential.UserName) failed"
                return
            }
            else {
                if ($HTTPS) {
                    Write-Error "Login to $BaseURI/rest/v1/login failed via HTTPS protocol, but HTTPS was enforced. Exception $($_.Exception.Message)`n $ResponseBody"
                    return
                }
                else {
                    Write-Warning "Login to $BaseURI/rest/v1/login failed via HTTPS protocol. Exception message: $($_.Exception.Message)`n $ResponseBody"
                    $HTTP = $True
                }
            }
        }
    }

    if ($HTTP) {
        Try {
            $BaseURI = "http://$Name"
            $Response = Invoke-RestMethod -Session Session -Method Post -Uri "$BaseURI/rest/v1/login" -TimeoutSec $Timeout -Headers $Headers
            $APIVersion = [System.Version]$Response.apiVersion
        }
        Catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            if ($_.Exception.Message -match "Unauthorized") {
                Write-Error "Authorization for $BaseURI/rest/v1/login with user $($Credential.UserName) failed"
                return
            }
            else {
                Write-Error "Login to $BaseURI/rest/v1/login failed via HTTP protocol. Exception message: $($_.Exception.Message)`n $ResponseBody"
                return
            }
        }
    }

    if (!$Timezone) {
        $Timezone = [System.TimeZoneInfo]::Local
    }

    if ($Timezone -isnot [System.TimeZoneInfo]) {
        if ([System.TimeZoneInfo]::GetSystemTimeZones().Id -contains $Timezone) {
            $Timezone = [System.TimeZoneInfo]::GetSystemTimeZones() | Where-Object { $_.Id -contains $Timezone }
        }
        else {
            Write-Warning "Timezone $Timezone is not supported by this system. Setting Timezone to $([System.TimeZoneInfo]::Local)"
            $Timezone = [System.TimeZoneInfo]::Local
        }
    }

    if (!$Timeout) {
        $Timeout = 600
    }

    $Server = [PSCustomObject]@{Name=$Name;
                            BaseURI=$BaseURI;
                            Credential=$Credential;
                            Headers=$Headers;
                            APIVersion=$APIVersion;
                            Timezone=$Timezone;
                            Timeout=$Timeout;
                            Session=$Session}

    if (!$Transient) {
        Set-Variable -Name CurrentOciServer -Value $Server -Scope Global
    }

    return $Server
}

<#
    .SYNOPSIS
    Import OCI Server Certificate into Windows Certificate store
    .DESCRIPTION
    Import OCI Server Certificate into Windows Certificate store
    .PARAMETER CertificateStoreOwner
    Owner of the certificate store where the certificate should be stored.
    .PARAMETER Name
    The name of the OCI Server. This value may also be a string representation of an IP address. If not an address, the name must be resolvable to an address.
    .PARAMETER Server
    OCI Server to connect to
    .EXAMPLE
    Import-OciServerCertificate
#>

function global:Import-OciServerCertificate {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="Owner of the certificate store where the certificate should be stored.")][ValidateSet("CurrentUser","LocalMachine")][String]$CertificateStoreOwner="CurrentUser",
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="The name of the OCI Server. This value may also be a string representation of an IP address. If not an address, the name must be resolvable to an address.")]$Name,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server -and !$Name) {
            throw "Server and Name parameter not specified and no global OCI Server available. Use Name parameter or run Connect-OciServer first!"
        }
        if ($Name) {
            $Uri = "https://$Name"
        }
        else {
            $Uri = $Server.BaseUri
        }
        if ($CertificateStoreOwner -eq "LocalMachine" -and ![Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
            throw "Administrator privilige required to store certificate in LocalMachine certificate store"
        }
    }

    Process {
        $Request = [Net.HttpWebRequest]::Create($Uri)
        $Request.Method = "OPTIONS"

        try {
            $Response = $Request.GetResponse()
        }
        catch {
        }

        if (!$Request.ServicePoint.Certificate) {
            Write-Error "No Certificate returned for $Uri"
        }

        $Certificate = $Request.ServicePoint.Certificate

        Write-Verbose "Retrieved certificate with subject $($Certificate.Subject) from issuer $($Certificate.Issuer)"

        $CertificateStore = New-Object System.Security.Cryptography.X509Certificates.X509Store([System.Security.Cryptography.X509Certificates.StoreName]::Root,$CertificateStoreOwner)

        $CertificateStore.Open("ReadWrite")

        $CertificateStore.Add($Certificate)

        if ($CertificateStore.Certificates.Contains($Certificate)) {
            Write-Host "Certificate added succesfully"
        }
        else {
            Write-Warning "Adding certificate failed"
        }

        $CertificateStore.Close()
    }
}

<#
    .SYNOPSIS
    Remove OCI Server Certificate from Windows Certificate store
    .DESCRIPTION
    Remove OCI Server Certificate from Windows Certificate store
    .PARAMETER CertificateStoreOwner
    Owner of the certificate store where the certificate should be removed from.
    .PARAMETER Name
    The name of the OCI Server. This value may also be a string representation of an IP address. If not an address, the name must be resolvable to an address.
    .PARAMETER Server
    OCI Server to connect to
    .EXAMPLE
    Remove-OciServerCertificate
#>

function global:Remove-OciServerCertificate {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="Owner of the certificate store where the certificate should be removed from.")][ValidateSet("CurrentUser","LocalMachine")][String]$CertificateStoreOwner="CurrentUser",
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="The name of the OCI Server. This value may also be a string representation of an IP address. If not an address, the name must be resolvable to an address.")]$Name,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server -and !$Name) {
            throw "Server and Name parameter not specified and no global OCI Server available. Use Name parameter or run Connect-OciServer first!"
        }
        if ($Name) {
            $Uri = "https://$Name"
        }
        else {
            $Uri = $Server.BaseUri
        }
        if ($CertificateStoreOwner -eq "LocalMachine" -and ![Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
            throw "Administrator privilige required to remove certificate from LocalMachine certificate store"
        }
    }

    Process {
        $Request = [Net.HttpWebRequest]::Create($Uri)
        $Request.Method = "OPTIONS"

        try {
            $Response = $Request.GetResponse()
        }
        catch {
        }

        if (!$Request.ServicePoint.Certificate) {
            Write-Error "No Certificate returned for $Uri"
        }

        $Certificate = $Request.ServicePoint.Certificate

        Write-Verbose "Retrieved certificate with subject $($Certificate.Subject) from issuer $($Certificate.Issuer)"

        $CertificateStore = New-Object System.Security.Cryptography.X509Certificates.X509Store([System.Security.Cryptography.X509Certificates.StoreName]::Root,$CertificateStoreOwner)

        $CertificateStore.Open("ReadWrite")

        $CertificateStore.Remove($Certificate)

        if (!$CertificateStore.Certificates.Contains($Certificate)) {
            Write-Host "Certificate removed succesfully"
        }
        else {
            Write-Warning "Removing certificate failed"
        }

        $CertificateStore.Close()
    }
}

## admin/acquisitionUnits ##

<#
    .SYNOPSIS
    Retrieve all Acquisition Units
    .DESCRIPTION
    Retrieve all Acquisition Units
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=datasources)
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAcquisitionUnits {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=datasources)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/acquisitionUnits"

        if ($expand) {
            $Uri += "?expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim
        }

        $AcquisitionUnits = ParseAcquisitionUnits -AcquisitionUnits $Result -Timezone $Server.Timezone
        Write-Output $AcquisitionUnits
    }
}

<#
    .SYNOPSIS
    Retrieve one Acquisition Unit
    .DESCRIPTION
    Retrieve one Acquisition Unit
    .PARAMETER id
    Id of acquisition unit to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=datasources)
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAcquisitionUnit {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of acquisition unit to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=datasources)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $($Server.BaseUri) + "/rest/v1/admin/acquisitionUnits/$id"

            if ($expand) {
                $Uri += "?expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $AcquisitionUnit = ParseAcquisitionUnits -AcquisitionUnits $Result -Timezone $Server.Timezone
            Write-Output $AcquisitionUnit
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all datasources of an acquisition unit
    .DESCRIPTION
    Retrieve all datasources of an acquisition unit
    .PARAMETER id
    ID of acquisition unit to get datasources for
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=datasources)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourcesByAcquisitionUnit {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="ID of acquisition unit to get datasources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=datasources)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/acquisitionUnits/$id/datasources"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Restart an Acquisition Unit
    .DESCRIPTION
    Restart an Acquisition Unit
    .PARAMETER id
    ID of acquisition unit to restart
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Restart-OciAcquisitionUnit {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of acquisition unit to restart",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/acquisitionUnits/$id/restart"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $AcquisitionUnit = ParseAcquisitionUnits -AcquisitionUnits $Result -Timezone $Server.Timezone
            Write-Output $AcquisitionUnit
        }
    }
}

## admin/certificates ##

<#
    .SYNOPSIS
    Retrieve list of certificates
    .DESCRIPTION
    Retrieve list of certificates
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciCertificates {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/certificates"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Certificates = ParseCertificates -Certificates $Result -Timezone $Server.Timezone
            Write-Output $Certificates
        }
    }
}

# TODO: Implement uploading of certificates
<#
    .SYNOPSIS
    Add a certificate based on source host/port or certificate file
    .DESCRIPTION
    User can add certificate for LDAP based on either source host/port or certificate file. Two ways to create certificate are supported: <br/>
 
To create from host and port use:
<pre>
{
    "host": "localhost",
    "port": 389
}
</pre>
 
To create from existing certificate file create a multi part request with the attributes:
<pre>
    alias: the alias for certificate in store
    certificateFile: the actual file to load into store
</pre>
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciCertificate {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   ParameterSetName='host',
                   HelpMessage="LDAP URI (e.g. dc1.example.com)")][String]$HostName,
        [parameter(Mandatory=$False,
                   Position=1,
                   ParameterSetName='host',
                   HelpMessage="LDAP SSL Port")][Int]$Port=636,
        [parameter(Mandatory=$True,
                   Position=0,
                   ParameterSetName='file',
                   HelpMessage="OnCommand Insight Server.")][String]$Alias,
        [parameter(Mandatory=$True,
                   Position=1,
                   ParameterSetName='file',
                   HelpMessage="OnCommand Insight Server.")][String]$File,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/certificates"

            try {
                $Body = ConvertTo-Json @{"host"=$HostName;"port"=$Port} -Compress
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Certificate = ParseCertificate -Certificate $Result -Timezone $Server.Timezone
            Write-Output $Certificate
        }
    }
}

## admin/datasources

<#
    .SYNOPSIS
    Retrieve all data source types.
    .DESCRIPTION
    Retrieve all data source types.
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceTypes {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasourceTypes"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim
        }

        $DatasourceTypes = ParseDatasourceTypes -DatasourceTypes $Result -Timezone $Server.Timezone
        Write-Output $DatasourceTypes
    }
}

<#
    .SYNOPSIS
    Retrieve one data source type.
    .DESCRIPTION
    Retrieve one data source type.
    .PARAMETER id
    ID of data source type
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceType {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Id of data source type",
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasourceTypes/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $DatasourceType = ParseDatasourceTypes -DatasourceTypes $Result -Timezone $Server.Timezone
            Write-Output $DatasourceType
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all Data Sources
    .DESCRIPTION
    Retrieve all Data Sources
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasources {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    New Data Source
    .DESCRIPTION
    Create new Data Source from type definition
    .PARAMETER type
    Datasource type
    .PARAMETER name
    Name of the datasource
    .PARAMETER acquisitionUnit
    Acquisition unit to associated datasource with
    .PARAMETER server
    OCI Server to connect to
#>

function Global:New-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Datasource type",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$type,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Datasource name",
                    ValueFromPipelineByPropertyName=$True)][String]$name,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="Datasource acquisition unit",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$acquisitionUnit
    )

    Process {

        $Datasource = [PSCustomObject]@{name=$Name;acquisitionUnit=[PSCustomObject]@{}}

        $Datasource | Add-Member -MemberType NoteProperty -Name "config" -Value ([PSCustomObject]@{})

        if ($acquisitionUnit -is [int]) {
            $Datasource.acquisitionUnit | Add-Member -MemberType NoteProperty -Name "id" -value $acquisitionUnit
        }
        elseif ($acquisitionUnit.id) {
            $Datasource.acquisitionUnit = $acquisitionUnit | Select-Object -Property id
        }

        $Datasource.config | Add-Member -MemberType NoteProperty -Name "dsTypeId" -Value $type.id
        $Datasource.config | Add-Member -MemberType NoteProperty -Name "vendor" -Value $type.vendorModels.vendorDescription
        $Datasource.config | Add-Member -MemberType NoteProperty -Name "model" -Value $type.vendorModels.modelDescription
        $Datasource.config | Add-Member -MemberType NoteProperty -Name "packages" -Value @()

        # if no packages are specified, enable all packages of specified type
        if ($packages) {
            $type.packages = $type.packages | Where-Object { $packages -match $_.id }
        }

        foreach ($package in $type.packages) {
            $attributes = $package.attributes
            $package = [PSCustomObject]@{id=$package.id;displayName=$package.displayName;attributes=[PSCustomObject]@{}}
            foreach ($attribute in $attributes) {
                $package.attributes | Add-Member -MemberType NoteProperty -Name $attribute.name -Value $attribute.defaultValue
            }
            $Datasource.config.packages += $package
        }

        # parse datasource to make sure that script properties are created
        $Datasource = ParseDatasources -Datasources $Datasource -Timezone $Server.Timezone
        Write-Output $Datasource
    }
}

<#
    .SYNOPSIS
    Add Data Source
    .DESCRIPTION
    Add Data Source
    .PARAMETER name
    Datasource name
    .PARAMETER acquisitionUnit
    Acquisition unit to associated datasource with
    .PARAMETER config
    Configuration of datasource
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Datasource name",
                    ValueFromPipelineByPropertyName=$True)][String]$name,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Datasource acquisition unit",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$acquisitionUnit,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="Datasource configuration",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$config,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources"

        try {
            $Body = @{}
            if ($Name) {
                $Body.name = $Name
            }
            if ($acquisitionUnit) {
                if ($acquisitionUnit -is [int]) {
                    $Body.acquisitionUnit = @{id=$acquisitionUnit}
                }
                elseif ($acquisitionUnit.id) {
                    $Body.acquisitionUnit = $acquisitionUnit | Select-Object -Property id
                }
            }
            if ($config) {
                $ConfigScriptProperties = $config.PSObject.Members | Where-Object { $_.MemberType -eq "ScriptProperty" } | ForEach-Object { $_.Name }
                $Body.config = $config | Select-Object -Property * -ExcludeProperty $ConfigScriptProperties
                $Uri += "?expand=config"
            }
            $Body = $Body | ConvertTo-Json -Depth 10
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            if ($Result.toString().startsWith('{')) {
                $Result = ParseJsonString -json $Result
            }
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        $Datasource = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
        Write-Output $Datasource
    }
}

<#
    .SYNOPSIS
    Remove a Datasource
    .DESCRIPTION
    Remove a Datasource
    .PARAMETER id
    Id of data source to remove
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to remove",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Datasource = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasource
        }
    }
}

<#
    .SYNOPSIS
    Retrieve a DataSource
    .DESCRIPTION
    Retrieve a DataSource
    .PARAMETER id
    Id of data source to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Datasource = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasource
        }
    }
}

<#
    .SYNOPSIS
    Update OCI Datasource
    .DESCRIPTION
    Update OCI Datasource
    .PARAMETER id
    Id of data source to update
    .PARAMETER name
    New name for datasource
    .PARAMETER acquisitionUnit
    New Acquisition unit to associated datasource with
    .PARAMETER config
    Updated configuration of datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciDataSource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to update",
                    ValueFromPipelineByPropertyName=$True)][Long]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Datasource name",
                    ValueFromPipelineByPropertyName=$True)][String]$name,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Datasource acquisition unit",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Datasource configuration",
                    ValueFromPipelineByPropertyName=$True)][PSObject]$config,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id"

        try {
            $Body = @{}
            if ($Name) {
                $Body.name = $Name
            }
            if ($acquisitionUnit) {
                $Body.acquisitionUnit = $acquisitionUnit | Select-Object -Property id
            }
            if ($config) {
                $ConfigScriptProperties = $config.PSObject.Members | Where-Object { $_.MemberType -eq "ScriptProperty" } | ForEach-Object { $_.Name }
                if ($config.foundation) {
                    if (!$config.foundation.attributes.password) {
                        $config.foundation.attributes.PSObject.Properties.Remove('password')
                    }
                    if (!$config.foundation.attributes.'partner.password') {
                        $config.foundation.attributes.PSObject.Properties.Remove('partner.password')
                    }
                }
                $Body.config = $config | Select-Object -Property * -ExcludeProperty $ConfigScriptProperties
                $Uri += "?expand=config"
            }
            $Body = $Body | ConvertTo-Json -Depth 10
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            if ($Result.toString().startsWith('{')) {
                $Result = ParseJsonString -json $Result
            }
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        $Datasource = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
        if ($Datasource.config.packages) {
            $config.packages = $Datasource.config.packages
        }
        Write-Output $Datasource
    }
}

<#
    .SYNOPSIS
    Retrieves Acquisition Unit by datasource.
    .DESCRIPTION
    Retrieves Acquisition Unit by datasource.
    .PARAMETER id
    Id of datasource for which to retrieve acquisition unit
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAcquisitionUnitByDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datasource for which to retrieve acquisition unit",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $($Server.BaseUri) + "/rest/v1/admin/datasources/$id/acquisitionUnit"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $AcquisitionUnit = ParseAcquisitionUnits -AcquisitionUnits $Result -Timezone $Server.Timezone
            Write-Output $AcquisitionUnit
        }
    }
}

<#
    .SYNOPSIS
    Retrieves the active patch for a data source
    .DESCRIPTION
    Retrieves the active patch for a data source
    .PARAMETER id
    Id of data source to find active patch
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER datasourceConclusions
    Return list of related Patched datasources status
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciActivePatchByDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to find active patch",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Patched datasources status")][Switch]$datasourceConclusions,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasourceConclusions")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/activePatch"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $ActivePatch = ParseActivePatches -ActivePatches $Result -Timezone $Server.Timezone
            Write-Output $ActivePatch
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Data Source changes
    .DESCRIPTION
    Retrieve Data Source changes
    .PARAMETER id
    Id of data source to get data for
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER details
    Return list of related Details
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceChanges {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to get data for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Details")][Switch]$details,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("details")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/changes"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim
            }

            $Change = ParseChanges -Changes $Result -Timezone $Server.Timezone
            Write-Output $Change
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Datasource configuration.
    .DESCRIPTION
    Retrieve Datasource configuration.
    .PARAMETER id
    Id of data source to retrieve configuration for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceConfiguration {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to retrieve configuration for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/config"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $DatasourceConfiguration = ParseDatasourceConfig -DatasourceConfig $Result -Timezone $Server.Timezone
            Write-Output $DatasourceConfiguration
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasource devices
    .DESCRIPTION
    Retrieve datasource devices
    .PARAMETER id
    Id of data source to get devices for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceDevices {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to get devices for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/devices"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Data Source events (audits)
    .DESCRIPTION
    Retrieve Data Source events (audits)
    .PARAMETER id
    Id of data source to get data for
    .PARAMETER details
    Return event details
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceEvents {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to get data for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return event details")][Switch]$details,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("details")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/events"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Datasource event details
    .DESCRIPTION
    Retrieve Datasource event details
    .PARAMETER id
    Id of data source event to get data for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceEventDetails {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source event to get data for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/events/$id/details"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Events = ParseEvents -Events $Result -Timezone $Server.Timezone
            Write-Output $Events
        }
    }
}

<#
    .SYNOPSIS
    Retrieve DataSource note
    .DESCRIPTION
    Retrieve DataSource note
    .PARAMETER id
    Id of data source to retrieve note for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourceNote {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to retrieve note for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/note"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update one Data Source note
    .DESCRIPTION
    Update one Data Source note
    .PARAMETER id
    Id of data source to update
    .PARAMETER value
    Note to be added to datasource
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciDatasourceNote {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Note to be added to datasource")][String]$value,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/note"

        try {
            $Body = @{value=$value} | ConvertTo-Json -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve DataSource package status
    .DESCRIPTION
    Retrieve DataSource package status
    .PARAMETER id
    Id of data source to get package status for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourcePackageStatus {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to get data for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/packages"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Poll one Data Source
    .DESCRIPTION
    Empty POST body
    .PARAMETER id
    Id of data source to poll
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Poll-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to poll",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/poll"

        try {
            $Body = ""
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Postpone one Data Source
    .DESCRIPTION
    Postpone one Data Source
    .PARAMETER id
    Id of data source to postpone
    .PARAMETER Days
    Number of days to postpone datasource polling
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Suspend-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to postpone",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Number of days to postpone datasource polling")][Long]$Days,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/postpone"

        try {
            $Body = @{days=$days} | ConvertTo-Json -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Resume one Data Source
    .DESCRIPTION
    Resume one Data Source
    .PARAMETER id
    Id of data source to resume
#>

function Global:Resume-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of data source to resume",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/resume"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            Write-Verbose "Body: "
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body "" -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Test Data Source
    .DESCRIPTION
    Empty POST body
    .PARAMETER id
    Id of data source to test
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Test-OciDatasource {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Id of data source to test",
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/datasources/$id/test"

        try {
            $Body = ""
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

## admin/ldap ##

<#
    .SYNOPSIS
    Retrieve LDAP configuration
    .DESCRIPTION
    Retrieve LDAP configuration
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciLdapConfiguration {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/ldap"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # add empty password to directoryLookup as this is not returned from OCI Server and is required for passing object to Update-OciLdapConfiguration
        $Result.directoryLookup | Add-Member -MemberType NoteProperty -Name password -Value "" -ErrorAction SilentlyContinue

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Update LDAP config
    .DESCRIPTION
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciLdapConfiguration {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Enable LDAP Configuration",
                   ValueFromPipelineByPropertyName=$True)][Boolean]$isEnabled=$true,
        [parameter(Mandatory=$True,
                   Position=1,
                   HelpMessage="Directory Lookup configuration. Hash containing key,value pairs for server, timeout, referral, userName, password and domain. Example: @{'server'='ldap://','timeout'=2000,'referral'='follow','userName'='directoryLookupUserName','domain'='DC=domain,DC=com'}",
                   ValueFromPipelineByPropertyName=$True)][PSCustomObject]$DirectoryLookup,
        [parameter(Mandatory=$True,
                   Position=2,
                   HelpMessage="LDAP Groups configuration. Hash containing LDAP groups as key,value pairs for users, guests, admins and serverAdmins. Example: @{'users'='insight.users','guests'='insight.guests','admins'='insight.admins','serverAdmins'='insight.server.admins'}",
                   ValueFromPipelineByPropertyName=$True)][PSCustomObject]$Groups,
        [parameter(Mandatory=$True,
                   Position=3,
                   HelpMessage="LDAP Attribute configuration. Hash containing LDAP attributes as key,value pairs for role, mail, userPrincipalName and distinguishedName. Example: @{'role'='memberOf','mail'='mail','userPrincipalName'='userPrincipalName','distinguishedName'='distinguishedName'}",
                   ValueFromPipelineByPropertyName=$True)][PSCustomObject]$Attributes,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/ldap"

        try {
            $Input = @{"isEnabled"=$isEnabled;
                        "directoryLookup"=$DirectoryLookup;
                        "groups"=$Groups;
                        "attributes"=$Attributes}
            $Body = ConvertTo-Json -InputObject $Input -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Perform an LDAP connection test
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Test-OciLdapConfiguration {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="LDAP Server URL",
                   ValueFromPipelineByPropertyName=$True)][String]$LdapServer,
        [parameter(Mandatory=$True,
                   Position=1,
                   HelpMessage="User name to use for LDAP test",
                   ValueFromPipelineByPropertyName=$True)][String]$UserName,
        [parameter(Mandatory=$True,
                   Position=2,
                   HelpMessage="The password of the user for the LDAP test",
                   ValueFromPipelineByPropertyName=$True)][PSCustomObject]$Password,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/ldap/test"

        try {
            $Body = ConvertTo-Json -InputObject @{"server"=$LdapServer;"userName"=$UserName;"password"=$Password} -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

## admin/licenses ##

<#
    .SYNOPSIS
    Retrieve licenses
    .DESCRIPTION
    Retrieve licenses
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciLicenses {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/license"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $LicenseStatus = ParseLicenseStatus -LicenseStatus $Result -Timezone $Server.Timezone
        Write-Output $LicenseStatus
    }
}

<#
    .SYNOPSIS
    Update license information
    .DESCRIPTION
    Update license information
    .PARAMETER Licenses
    List of OCI Licenses
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciLicenses {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="List of OCI licenses")][String[]]$Licenses,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/license"

        try {
            $Body = ConvertTo-Json -InputObject @($Licenses) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            throw "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $NewLicenses = ParseLicenses -Licenses $Result -Timezone $Server.Timezone
        Write-Output $NewLicenses
    }
}

<#
    .SYNOPSIS
    Replace license information
    .DESCRIPTION
    Replace license information
    .PARAMETER Licenses
    List of OCI Licenses
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Replace-OciLicenses {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="List of OCI licenses")][String[]]$Licenses,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/license"

        try {
            $Body = $Licenses | ConvertTo-Json -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            throw "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

## admin/patches ##

<#
    .SYNOPSIS
    Retrieve all patches
    .DESCRIPTION
    Retrieve all patches
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER datasourceConclusions
    Return related datasource status
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciPatches {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related datasource status")][Switch]$datasourceConclusions,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasourceConclusions")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches"

        if ($expand) {
            $Uri += "?$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $PatchStatus = ParsePatchStatus -PatchStatus $Result -Timezone $Server.Timezone
        Write-Output $PatchStatus
    }
}

<#
    .SYNOPSIS
    Add Patch
    .DESCRIPTION
    POST request to include 'patchFile' file parameter
    .PARAMETER datasourceConclusions
    Return list of related Patched datasources status
#>

function Global:Add-OciPatch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Return list of related Patched datasources status")][System.IO.FileInfo]$patchFile,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Patched datasources status")][Switch]$datasourceConclusions,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasourceConclusions")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches"

        try {
            $Result = Invoke-MultipartFormDataUpload -InFile $patchFile -Name "patchFile" -Uri $Uri -Header $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $PatchStatus = ParsePatchStatus -PatchStatus $Result -Timezone $Server.Timezone
        Write-Output $PatchStatus
    }
}

<#
    .SYNOPSIS
    Get patch
    .DESCRIPTION
    Get patch
    .PARAMETER id
    Id of a patch to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER datasourceConclusions
    Return list of related Patched datasources status
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciPatch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of a patch to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Patched datasources status")][Switch]$datasourceConclusions,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasourceConclusions")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id"

        if ($expand) {
            $Uri += "?$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Update one patch
    .DESCRIPTION
    Update one patch
    .PARAMETER id
    Id of patch to update
    .PARAMETER datasourceConclusions
    Return list of related Patched datasources status
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciPatch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of patch to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Return list of related Patched datasources status")][System.IO.FileInfo]$patchFile,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Patched datasources status")][Switch]$datasourceConclusions,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("datasourceConclusions")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-MultipartFormDataUpload -InFile $patchFile -Name "patchFile" -Uri $Uri -Header $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $PatchStatus = ParsePatchStatus -PatchStatus $Result -Timezone $Server.Timezone
        Write-Output $PatchStatus
    }
}

<#
    .SYNOPSIS
    Approve a patch
    .DESCRIPTION
    Approve a patch
    .PARAMETER id
    ID of patch to approve
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Approve-OciPatch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of patch to approve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id/approve"

        try {
            $Body = ""
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve Patch Data Source Conclusions
    .DESCRIPTION
    Retrieve Patch Data Source Conclusions
    .PARAMETER id
    Id of patch to get data source conslusions for
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciPatchDatasourceConclusions {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of patch to get data source conslusions for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id/datasourceConclusions"

        if ($expand) {
            $Uri += "?$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Update one patch note
    .DESCRIPTION
    Update one patch note
    .PARAMETER id
    ID of patch to update
    .PARAMETER note
    Note to be added to patch
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciPatchNote {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="ID of patch to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Note to be added to patch")][String]$value,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id/note"

        try {
            $Body = @{value=$value} | ConvertTo-Json -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Rollback one patch
    .DESCRIPTION
    Empty body
    .PARAMETER id
    Id of patch to rolback
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Rollback-OciPatch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of patch to rolback",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/patches/$id/rollback"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            $Body = ""

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## admin/users ##

<#
    .SYNOPSIS
    Retrieve all users
    .DESCRIPTION
    Retrieve all users
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciUsers {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/users"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Users = ParseUsers -Users $Result -Timezone $Server.Timezone
        Write-Output $Users
    }
}

# TODO: Implement / Test creation of new user
<#
    .SYNOPSIS
    Create a new user
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
{
    "name":"test",
    "password": "pwd",
    "email": "email@test.com",
    "insightRole": "USER",
    "isActive": false
}
</pre>
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciUsers {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/users"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            $Body = ""

            try {
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'

            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve currently logged in user
    .DESCRIPTION
    Retrieve currently logged in user
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciCurrentUser {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/users/current"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $User = ParseUsers -Users $Result -Timezone $Server.Timezone
        Write-Output $User
    }
}

# TODO: Implement / Test deletion of user
<#
    .SYNOPSIS
    Delete one user
    .DESCRIPTION
 
    .PARAMETER id
    The id of user to delete
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciUser {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="The id of user to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/users/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            $Body = ""

            try {
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one user
    .DESCRIPTION
    Retrieve one user
    .PARAMETER id
    The id of user to retrieve
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciUser {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="The id of user to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/users/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $User = ParseUsers -Users $Result -Timezone $Server.Timezone
            Write-Output $User
        }
    }
}

# TODO: Implement / Test updating of users
<#
    .SYNOPSIS
    Update one user
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
{
    "password": "pwd",
    "email": "email@test.com",
    "insightRole": "USER",
    "isActive": false
}
</pre>
 
    .PARAMETER id
    The id of user to update
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciUser {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="The id of user to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/users/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            $Body = ""

            try {
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/annotations ##

<#
    .SYNOPSIS
    Retrieve all annotation definitions
    .DESCRIPTION
    Retrieve all annotation definitions
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotations {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/annotations"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Add annotation
    .DESCRIPTION
    Add annotation
    .PARAMETER name
    Annotation name
    .PARAMETER type
    Annotation type. Must be either DATE, TEXT, FIXED_ENUM, FLEXIBLE_ENUM, BOOLEAN or NUMBER
    .PARAMETER description
    Annotation description
    .PARAMETER enumValues
    List of name, label pairs for enum types (e.g. @(@{name='name',label='label'}) )
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciAnnotation {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=1,
                   HelpMessage="Annotation name")][String]$Name,
        [parameter(Mandatory=$True,
                   Position=2,
                   HelpMessage="Annotation type. Must be either DATE, TEXT, FIXED_ENUM, FLEXIBLE_ENUM, BOOLEAN or NUMBER")][ValidateSet("DATE","TEXT","FIXED_ENUM","FLEXIBLE_ENUM","BOOLEAN","NUMBER")][String]$Type,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="Annotation description.")][String]$Description,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="List of name, label pairs for enum types (e.g. @(@{name='name';label='label'}) )")][Hashtable[]]$enumValues,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations"

            if ($type -match "ENUM" -and -not $enumValues) {
                throw "$type specified, but no enumValues provided"
            }

            try {
                $Body = ConvertTo-Json @{name=$name;type=$type;description=$description;enumValues=$enumValues} -Compress -Depth 4
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete annotation definition by id or name
    .DESCRIPTION
    Delete annotation definition by id or name
    .PARAMETER id
    Id or name of annotation definition to delete
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciAnnotation {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id"

            try {
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body "" -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotation definition
    .DESCRIPTION
    Retrieve annotation definition
    .PARAMETER id
    Id or name of annotation definition to retrieve
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotation {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Annotation = ParseAnnotations -Annotations $Result -Timezone $Server.Timezone
            Write-Output $Annotation
        }
    }
}

<#
    .SYNOPSIS
    Update annotation definition by id
    .DESCRIPTION
    Update annotation definition by id
    .PARAMETER server
    OCI Server to connect to
    .PARAMETER Id
    Annotation ID to be updated
    .PARAMETER name
    Annotation name
    .PARAMETER type
    Annotation type. Must be either DATE, TEXT, FIXED_ENUM, FLEXIBLE_ENUM, BOOLEAN or NUMBER
    .PARAMETER description
    Annotation description
    .PARAMETER enumValues
    List of name, label pairs for enum types (e.g. @(@{name='name',label='label'}) )
 
#>

function Global:Update-OciAnnotation {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer,
        [parameter(Mandatory=$True,
                   Position=1,
                   ValueFromPipelineByPropertyName=$True,
                   HelpMessage="Annotation name")][String]$Id,
        [parameter(Mandatory=$False,
                   Position=2,
                   ValueFromPipelineByPropertyName=$True,
                   HelpMessage="Annotation name")][String]$Name,
        [parameter(Mandatory=$False,
                   Position=3,
                   ValueFromPipelineByPropertyName=$True,
                   HelpMessage="Annotation type. Must be either DATE, TEXT, FIXED_ENUM, FLEXIBLE_ENUM, BOOLEAN or NUMBER")][ValidateSet("DATE","TEXT","FIXED_ENUM","FLEXIBLE_ENUM","BOOLEAN","NUMBER")][String]$Type,
        [parameter(Mandatory=$False,
                   Position=4,
                   ValueFromPipelineByPropertyName=$True,
                   HelpMessage="Annotation description.")][String]$Description,
        [parameter(Mandatory=$False,
                   Position=5,
                   ValueFromPipelineByPropertyName=$True,
                   HelpMessage="List of name, label pairs for enum types (e.g. @(@{name='name',label='label'}) )")][PSCustomObject[]]$enumValues
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$Id"
        $Method = "PATCH"

        if ($type -match "ENUM" -and -not $enumValues) {
            throw "$type specified, but no enumValues provided"
        }

        try {
            $Body = ConvertTo-Json @{name=$name;type=$type;description=$description;enumValues=$enumValues} -Compress -Depth 4
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method $Method -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Remove object annotation values in bulk by annotation
    .DESCRIPTION
    Remove object annotation values in bulk by annotation
    .PARAMETER id
    Id or name of annotation to remove values from
    .PARAMETER objectType
    Object type of objects where annotations should be deleted (e.g. StoragePool or InternalVolume)
    .PARAMETER targets
    IDs of object where annotation should be deleted
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciAnnotationValues {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation to remove values from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Object type of objects where annotations should be deleted (e.g. StoragePool or InternalVolume)")][ValidateSet("StoragePool","Qtree","Port","Host","StorageNode","Storage","InternalVolume","Switch","Volume","Vmdk","DataStore","Disk","Share","VirtualMachine")][String]$objectType,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="IDs of object where annotation should be deleted")][String[]]$targets,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
        # if targets are specified as URLs, remove everything except the target ID
        $Targets = $Targets -replace ".*/",""
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id/values"

            if ($targets -and $objectType) {
                $items = @(@{objectType=$objectType;values=@{targets=$targets}})
            }
            else {
                Write-Verbose "Deleting all values from annotation with ID $id"
                $items = Get-OciAnnotationValues -id $id -server $server
            }

            try {
                foreach ($item in $items) {
                    $objectType = $item.objectType
                    $targets = $item.values.targets | ForEach-Object { $_ -split '/' | Select-Object -last 1 }
                    if ($targets) {
                        $Body = ConvertTo-Json @(@{objectType=$objectType;targets=$targets}) -Compress -Depth 4
                        Write-Verbose "Body: $Body"
                        $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
                    }
                }
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotation definition values for all supported object types
    .DESCRIPTION
    Retrieve annotation definition values for all supported object types
    .PARAMETER id
    Id or name of annotation definition to retrieve values for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationValues {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to retrieve values for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id/values"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update object annotations in bulk by annotation
    .DESCRIPTION
    Update object annotations in bulk by annotation
    .PARAMETER id
    Id or name of annotation definition to update
    .PARAMETER objectType
    Object type of objects where annotations should be added (e.g. StoragePool or InternalVolume)
    .PARAMETER rawValue
    Value of Annotation
    .PARAMETER targets
    IDs of object where annotation should be added
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciAnnotationValues {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Object type of objects where annotations should be added (e.g. StoragePool or InternalVolume)")][ValidateSet("StoragePool","Qtree","Port","Host","StorageNode","Storage","InternalVolume","Switch","Volume","Vmdk","DataStore","Disk","Share","VirtualMachine")][String]$objectType,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="Value of Annotation")][String]$rawValue,
        [parameter(Mandatory=$True,
                    Position=3,
                    HelpMessage="IDs of object where annotation should be added")][String[]]$targets,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
        # if targets are specified as URLs, remove everything except the target ID
        $Targets = $Targets -replace ".*/",""
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id/values"

        try {
            $Body = ConvertTo-Json @(@{objectType=$objectType;values=@(@{rawValue=$rawValue;targets=$targets})}) -Compress -Depth 4
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve annotation definition values for one supported object type
    .DESCRIPTION
    'targets' in response contains URLs for target objects
    .PARAMETER id
    Id or name of annotation definition to retrieve
    .PARAMETER objectType
    The object type to retrieve values for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationValuesByObjectType {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="The object type to retrieve values for")][ValidateSet("StoragePool","Qtree","Port","Host","StorageNode","Storage","InternalVolume","Switch","Volume","Vmdk","DataStore","Disk","Share","VirtualMachine")][String]$objectType,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id/values/$objectType"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotation definition targets for one supported object type, one specific value
    .DESCRIPTION
    Returns list of URLs for objects for annotation, object type, value
    .PARAMETER id
    Id or name of annotation definition to retrieve
    .PARAMETER objectType
    The object type to retrieve target objects for
    .PARAMETER value
    The specific value to retrieve target objects for
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationValuesByObjectTypeAndValue {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id or name of annotation definition to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="The object type to retrieve target objects for")][ValidateSet("StoragePool","Qtree","Port","Host","StorageNode","Storage","InternalVolume","Switch","Volume","Vmdk","DataStore","Disk","Share","VirtualMachine")][String]$objectType,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="The specific value to retrieve target objects for")][String]$value,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
        $Value = [Uri]::EscapeDataString($Value)
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/annotations/$id/values/$objectType/$Value"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

## assets/applications ##

<#
    .SYNOPSIS
    Retrieve all applications
    .DESCRIPTION
    Retrieve all applications
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciApplications {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Applications = ParseApplications -Applications $Result -Timezone $Server.Timezone
            Write-Output $Applications
        }
    }
}

<#
    .SYNOPSIS
    Add a new application
    .DESCRIPTION
    Add a new application
    .PARAMETER name
    Name of the application
    .PARAMETER priority
    Application priority (Critical, High, Medium or Low). Default is Medium.
    .PARAMETER businessEntity
    Business entity ID to attach the application to
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Name of the application")][String]$name,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Application priority (Critical, High, Medium or Low). Default is Medium.")][ValidateSet("Critical", "High", "Medium", "Low")][String]$priority="Medium",
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Business entity ID to attach the application to")][String]$businessEntity,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Business entity ID to attach the application to")][Switch]$ignoreShareViolations,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/applications"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            if ($businessEntity) {
                $Body = ConvertTo-Json @{name=$name;priority=$priority;businessEntity=@{id=$businessEntity};ignoreShareViolations=$($ignoreShareViolations.IsPresent)} -Compress
            }
            else {
                $Body = ConvertTo-Json @{name=$name;priority=$priority;ignoreShareViolations=$($ignoreShareViolations.IsPresent)} -Compress
            }
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Application = ParseApplications -Applications $Result -Timezone $Server.Timezone
        Write-Output $Application
    }
}

# TODO: Implemet / Test unassigning of applications from assets
<#
    .SYNOPSIS
    Bulk un-assign applications from assets
    .DESCRIPTION
    Request body should contain a list application ids mapped to a list of asset ids, grouped by type, example: <br/>
 
<pre>
[
    {
        "123": [
            {
                "objectType": "Qtree",
                "targets": [
                    "11299",
                    "11305"
                ]
            },
            {
                "objectType": "InternalVolume",
                "targets": [
                    "11299",
                    "11305"
                ]
            }
        ]
    },
    {
        "456": [
            {
                "objectType": "VirtualMachine",
                "targets": [
                    "2052",
                    "8739"
                ]
            }
        ]
    }
]
</pre>
 
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciApplicationsFromAssets {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/assets"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

# TODO: Implement / Test
<#
    .SYNOPSIS
    Assign applications to assets
    .DESCRIPTION
    Assign applications to assets
<pre>
[
    {
        "123": [
            {
                "objectType": "Qtree",
                "targets": [
                    "11299",
                    "11305"
                ]
            },
            {
                "objectType": "InternalVolume",
                "targets": [
                    "11299",
                    "11305"
                ]
            }
        ]
    },
    {
        "456": [
            {
                "objectType": "VirtualMachine",
                "targets": [
                    "2052",
                    "8739"
                ]
            }
        ]
    }
]
</pre>
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciApplicationsToAssets {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/assets"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                if ('PATCH' -match 'PUT|POST') {
                    Write-Verbose "Body: "
                    $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body "" -ContentType 'application/json'
                }
                else {
                    $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers
                }
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Remove an application
    .DESCRIPTION
    Remove an application
    .PARAMETER id
    Id of application to delete
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Application = ParseApplications -Applications $Result -Timezone $Server.Timezone
            Write-Output $Application
        }
    }
}

<#
    .SYNOPSIS
    Retrieve application
    .DESCRIPTION
    Retrieve application
    .PARAMETER id
    Id of application to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Application = ParseApplications -Applications $Result -Timezone $Server.Timezone
            Write-Output $Application
        }
    }
}

<#
    .SYNOPSIS
    Update an application
    .DESCRIPTION
    Update an application
    .PARAMETER id
    Id of application to update
    .PARAMETER priority
    Application priority (Critical, High, Medium or Low). Default is Medium.
    .PARAMETER businessEntity
    Business entity ID to attach the application to
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Application priority (Critical, High, Medium or Low). Default is Medium.")][ValidateSet("Critical", "High", "Medium", "Low")][String]$priority="Medium",
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Business entity ID to attach the application to")][String]$businessEntity,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Business entity ID to attach the application to")][Switch]$ignoreShareViolations,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                if ($businessEntity) {
                    $Body = ConvertTo-Json @{name=$name;priority=$priority;businessEntity=@{id=$businessEntity};ignoreShareViolations=$($ignoreShareViolations.IsPresent)} -Compress
                }
                else {
                    $Body = ConvertTo-Json @{name=$name;priority=$priority;ignoreShareViolations=$($ignoreShareViolations.IsPresent)} -Compress
                }
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Application = ParseApplications -Applications $Result -Timezone $Server.Timezone
            Write-Output $Application
        }
    }
}

# TODO: Implement / Test
<#
    .SYNOPSIS
    Bulk un-assign application from assets
    .DESCRIPTION
    Request body should contain a list of asset ids, grouped by type, example: <br/>
 
<pre>
[
    {
        "objectType": "StoragePool"
        "targets": [
            "11299",
            "11305"
        ]
    },
    {
        "objectType": "VirtualMachine"
        "targets": [
            "2052",
            "8739"
        ]
    }
]
</pre>
 
    .PARAMETER id
    Id of application to un-assign from assets
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciApplicationFromAssets {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to un-assign from assets",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Array of OCI Object IDs to remove from the Application.")][String[]]$Assets,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="Type of OCI asset to update VirtualMachine, Host etc..")][String]$AssetType,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        $Targets = @($Assets)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id/assets"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = @{objectType=$AssetType;targets=$Targets} | ConvertTo-Json -Compress
                $Body = $Body.Insert(0,'[')
                $Body = $Body.Insert($Body.Length,']')
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve assets for application
    .DESCRIPTION
    Retrieve assets for application
    .PARAMETER id
    Id of application to retrieve assets for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAssetsByApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to retrieve assets for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id/assets"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

# TODO: Implement / Test
<#
    .SYNOPSIS
    Bulk assign application to assets
    .DESCRIPTION
    Request body should contain lists of asset ids, grouped by type, example: <br/>
 
<pre>
[
    {
        "objectType": "Volume",
        "targets": [
            "11299",
            "11305"
        ]
    },
    {
        "objectType": "VirtualMachine",
        "targets": [
            "2052",
            "8739"
        ]
    }
]
</pre>
 
    .PARAMETER id
    Id of application to assign to assets
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Bulk-OciAssignApplicationToAssets {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to assign to assets",
                    ValueFromPipeline=$False,
                    ValueFromPipelineByPropertyName=$False)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Array of OCI Object IDs to add the Application to.")][String[]]$Assets,
        [parameter(Mandatory=$True,
                    Position=2,
                    HelpMessage="Type of OCI asset to update VirtualMachine, Host etc..")][String]$AssetType,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        if (!$assets) {
            throw "No Assets specified!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        $Targets = @($Assets)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id/assets"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = @{objectType=$AssetType;targets=$Targets} | ConvertTo-Json -Compress
                $Body = $Body.Insert(0,'[')
                $Body = $Body.Insert($Body.Length,']')
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri  -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -Headers $Server.Headers -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve compute resources by application
    .DESCRIPTION
    Retrieve compute resources by application
    .PARAMETER id
    Id of application to retrieve compute resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciComputeResourcesByApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to retrieve compute resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id/computeResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $ComputeResources = ParseComputeResources -ComputeResources $Result -Timezone $Server.Timezone
            Write-Output $ComputeResources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage resources by application
    .DESCRIPTION
    Retrieve storage resources by application
    .PARAMETER id
    Id of application to retrieve storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciStorageResourcesByApplication {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of application to retrieve storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/applications/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageResources = ParseStorageResources -StorageResources $Result -Timezone $Server.Timezone
            Write-Output $StorageResources
        }
    }
}

## assets/businessEntities ##

<#
    .SYNOPSIS
    Retrieve all business entities
    .DESCRIPTION
    Retrieve all business entities
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciBusinessEntities {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/businessEntities"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Add a new business entity
    .DESCRIPTION
    Add a new business entity
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Add-OciBusinessEntity {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Tenant.")][String]$Tenant,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")][String]$LineOfBusiness,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")][String]$BusinessUnit,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")][String]$Project,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/businessEntities"

        try {
            $Body = @{tenant=$Tenant;lob=$LineOfBusiness;businessUnit=$BusinessUnit;project=$project} | ConvertTo-Json -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Remove a business entity
    .DESCRIPTION
    Remove a business entity
    .PARAMETER id
    Id of business entity to remove
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciBusinessEntity {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of business entity to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/businessEntities/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve business entity with empty fields set to N/A
    .DESCRIPTION
    Retrieve business entity with empty fields set to N/A
    .PARAMETER id
    Id of business entity to retrieve
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciBusinessEntity {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of business entity to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/businessEntities/$id"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/datastores ##

<#
    .SYNOPSIS
    Retrieve all datastores
    .DESCRIPTION
    Retrieve all datastores
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER limit
    Number of datastores per page (range: 0-50, default: 0)
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER sort
    Performance metric for sorting (Default iops.total)
    .PARAMETER performance
    Return related Performance
    .PARAMETER hosts
    Return list of related Hosts
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatastores {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Number of datastores per page (range: 0-50, default: 0)")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items, thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $($Server.BaseUri) + "/rest/v1/assets/dataStores"

            $Uri += '?'
            $Separator = ''
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datastores = ParseDatastores -Datastores $Result -Timezone $Timezone

            if ($Datastores) { Write-Output $Datastores }

            if ($FetchAll -and @($Datastores).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciDatastores -fromTime $fromTime -toTime $toTime -limit $limit -offset $offset -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of datastores.
    .DESCRIPTION
    Retrieve total count of datastores.
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatastoreCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/count"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result.value
    }
}

<#
    .SYNOPSIS
    Retrieve one datastore
    .DESCRIPTION
    Retrieve one datastore
    .PARAMETER id
    Id of datastore to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER hosts
    Return list of related Hosts
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datastore to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Hosts")][Switch]$hosts,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
        $switchparameters=@("performance","hosts","vmdks","datasources","storageResources","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datastore = ParseDatastores -Datastores $Result -Timezone $Timezone
            Write-Output $Datastore
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Delete annotations from object
    .PARAMETER id
    Id of datastore where annotation should be deleted
    .PARAMATER annotationId
    Id of annotation to delete. If no annotation is specified, all annotations will be deleted
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciAnnotationsByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datastore to delete annotations from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Annotations to remove from datastore")][PSObject[]]$annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $CurrentOciServer.BaseUri + "/rest/v1/assets/dataStores/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        if (!$Annotations) {
            $Annotations = Get-OciAnnotationsByDatastore -id $id -definition -Server $Server
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Retrieve annotations by datastore
    .DESCRIPTION
    Retrieve annotations by datastore
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationsByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Annotations = ParseAnnotations -Annotations $Result -Timezone $Server.Timezone

        Write-Output $Annotations
    }
}

<#
    .SYNOPSIS
    Update annotations for datastore
    .DESCRIPTION
    Update annotations for datastore
    .PARAMETER id
    Id of datastore to update
    .PARAMETER Annotations
    Annotations
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciAnnotationsByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datastore to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Annotations")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a datastore.
    .DESCRIPTION
    Retrieve datasources of a datastore.
    .PARAMETER id
    Id of datastore to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourcesByDataStore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datastore to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/datasources"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
        if ($Datasources) {
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all hosts mapped to a datastore.
    .DESCRIPTION
    Retrieve all hosts mapped to a datastore.
    .PARAMETER id
    Id of the datastore to retrieve the hosts
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER virtualMachines
    Return list of related Virtual machines
    .PARAMETER dataCenter
    Return related Data center
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER clusterHosts
    Return list of related Cluster hosts
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciHostsByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the datastore to retrieve the hosts",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Virtual machines")][Switch]$virtualMachines,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Data center")][Switch]$dataCenter,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Cluster hosts")][Switch]$clusterHosts,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","applications","virtualMachines","dataCenter","annotations","clusterHosts","datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/hosts"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Hosts = ParseHosts -Hosts $Result -Timezone $Server.Timezone

        if ($Hosts) {
            Write-Output $Hosts
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datastore performance data
    .DESCRIPTION
    Retrieve datastore performance data
    .PARAMETER id
    Id of datastore to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatastorePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of datastore to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage resources mapped to a datastore.
    .DESCRIPTION
    Retrieve all storage resources mapped to a datastore.
    .PARAMETER id
    Id of the datastore to retrieve the storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciStorageResourcesByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the datastore to retrieve the storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageResources = ParseStorageResources -StorageResources $Result -Timezone $Server.Timezone
            Write-Output $StorageResources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all Vmdks belonging to a datastore.
    .DESCRIPTION
    Retrieve all Vmdks belonging to a datastore.
    .PARAMETER id
    Id of the datastore to retrieve the Vmdks
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER virtualMachine
    Return related Virtual machine
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciVmdksByDatastore {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the datastore to retrieve the Vmdks",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return related Virtual machine")][Switch]$virtualMachine,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","dataStore","storageResources","virtualMachine","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/dataStores/$id/vmdks"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Vmdks = ParseVmdks -Vmdks $Result -Timezone $Server.Timezone

            Write-Output $Vmdks
        }
    }
}

## assets/disks ##

<#
    .SYNOPSIS
    Retrieve storage pool disks
    .DESCRIPTION
    Retrieve storage pool disks
    .PARAMETER id
    Id of storage pool disk to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER backendVolumes
    Return list of related Backend volumes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool disk to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Backend volumes")][Switch]$backendVolumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","storagePools","performance","storageResources","backendVolumes","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Disks = ParseDisks -Disks $Result -Timezone $Server.Timezone
            Write-Output $Disks
        }
    }
}

<#
    .SYNOPSIS
    Remove annotations from disk
    .DESCRIPTION
    Remove annotations from disk
    .PARAMETER id
    Id of disk where annotations should be removed from
    .PARAMETER Annotations
    Annotations to remove
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciAnnotationsByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Annotations to remove from disk")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        if (!$Annotations) {
            $Annotations = Get-OciAnnotationsByDisk -id $id -definition -Server $Server
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Retrieve annotations of disk
    .DESCRIPTION
    Retrieve annotations of disk
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationsByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Annotations = ParseAnnotations -Annotations $Result -Timezone $Server.Timezone
        Write-Output $Annotations
    }
}

<#
    .SYNOPSIS
    Update annotations of disk
    .DESCRIPTION
    Update annotations of disk
    .PARAMETER id
    Id of disk to update
    .PARAMETER Annotations
    Annotations to be updated
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Update-OciAnnotationsByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Annotations to be updated")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        $Annotations = ParseAnnotations -Annotations $Result -Timezone $Server.Timezone
        Write-Output $Annotations
    }
}

<#
    .SYNOPSIS
    Retrieve backend volumes of a virtual disk.
    .DESCRIPTION
    Retrieve backend volumes of a virtual disk.
    .PARAMETER id
    Id of the virtual disk to retrieve backend volumes for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciBackendVolumesByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the virtual disk to retrieve backend volumes for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=21,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/backendVolumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Volumes = ParseVolumes -Volumes $Result -Timezone $Server.Timezone
            Write-Output $Volumes
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a disk.
    .DESCRIPTION
    Retrieve datasources of a disk.
    .PARAMETER id
    Id of disk to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourcesByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of disk to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone

            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one disk performance
    .DESCRIPTION
    Retrieve one disk performance
    .PARAMETER id
    Id of disk to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDiskPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of disk to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage pools for disk
    .DESCRIPTION
    Retrieve storage pools for disk
    .PARAMETER id
    Id of disk to retrieve storage pools for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciStoragePoolsByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of disk to retrieve storage pools for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/storagePools"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StoragePools = ParseStoragePools -StoragePools $Result -Timezone $Server.Timezone
            Write-Output $StoragePools
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage resources for disk
    .DESCRIPTION
    Retrieve storage resources for disk
    .PARAMETER id
    Id of disk to retrieve resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciStorageResourcesByDisk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of disk to retrieve resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/disks/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageResources = ParseStorageResources -StorageResources $Result -Timezone $Server.Timezone
            Write-Output $StorageResources
        }
    }
}

## assets/fabrics ##

<#
    .SYNOPSIS
    Retrieve all fabrics
    .DESCRIPTION
    Retrieve all fabrics
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER limit
    Number of fabrics per page.
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER switches
    Return list of related Switches
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciFabrics {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Number of fabrics per page (range: 0-50, default: 0)")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Switches")][Switch]$switches,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("switches","datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics"

            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Fabrics = ParseFabrics -Fabrics $Result -Timezone $Server.Timezone
            if ($Fabrics)  { Write-Output $Fabrics }

            if ($FetchAll -and @($Fabrics).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciFabrics -fromTime $fromTime -toTime $toTime -limit $limit -offset $offset -switches:$switches -datasources:$datasources -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of fabrics.
    .DESCRIPTION
    Retrieve total count of fabrics.
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciFabricCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/count"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve one fabric
    .DESCRIPTION
    Retrieve one fabric
    .PARAMETER id
    Id of fabric to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER switches
    Return list of related Switches
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciFabric {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of fabric to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Switches")][Switch]$switches,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("switches","datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Fabric = ParseFabrics -Fabrics $Result -Timezone $Server.Timezone
            Write-Output $Fabric
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Datasources for one fabric
    .DESCRIPTION
    Retrieve Datasources for one fabric
    .PARAMETER id
    Id of fabric to retrieve datasources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciDatasourcesByFabric {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of fabric to retrieve datasources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Ports for one fabric
    .DESCRIPTION
    Retrieve Ports for one fabric
    .PARAMETER id
    Id of fabric to retrieve ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER limit
    Number of ports in fabric to retrieve (range: 0-50, default: 0)
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER sort
    Performance metric used for sorting (Default iops.total)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciPortsByFabric {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of fabric to retrieve ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Limit for number of ports in fabric to retrieve")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="sort will specify the field name on which sorting to be applied")][String]$sort="trafficRate.total",
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items when performance data is requested, thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/$id/ports"

            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($sort) {
                $Uri += "$($Separator)sort=$sort"
                $Separator = '&'
            }
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Ports = ParsePorts -Ports $Result -Timezone $Server.Timezone
            if ($Ports) { Write-Output $Ports }

            if ($FetchAll -and @($Ports).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciPortsByFabric -id $id -fromTime $fromTime -toTime $toTime -performance:$performance -performancehistory:$performancehistory -sort $sort -limit $limit -offset $offset -device:$device -fabrics:$fabrics -connectedPorts:$connectedPorts -annotations:$annotations -datasources:$datasources -applications:$applications -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of ports by fabric with performance.
    .DESCRIPTION
    Retrieve total count of ports by fabric with performance.
    .PARAMETER id
    Id of fabric to retrieve ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciPortsByFabricCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of fabric to retrieve ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/$id/ports/count"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result.Value
        }
    }
}

<#
    .SYNOPSIS
    Retrieve switches for one fabric
    .DESCRIPTION
    Retrieve switches for one fabric
    .PARAMETER id
    Id of fabric to retrieve switches for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fabric
    Return related Fabric
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciSwitchesByFabric {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of fabric to retrieve switches for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Fabric")][Switch]$fabric,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("fabric","performance","ports","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fabrics/$id/switches"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Switches = ParseSwitches -Switches $Result -Timezone $Server.Timezone
            Write-Output $Switches
        }
    }
}

## assets/fileSystems ##

<#
    .SYNOPSIS
    Retrieve one file system
    .DESCRIPTION
 
    .PARAMETER id
    Id of file system to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER computeResource
    Return related Compute resource
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciFilesystem {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of file system to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Compute resource")][Switch]$computeResource,
        [parameter(Mandatory=$False,
                   Position=7,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageResources","vmdks","computeResource")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fileSystems/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve compute resource for a file system
    .DESCRIPTION
 
    .PARAMETER id
    Id of file system to retrieve the compute resource for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciComputeResourceByFileSystem {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of file system to retrieve the compute resource for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fileSystems/$id/computeResource"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage resources for a file system
    .DESCRIPTION
 
    .PARAMETER id
    Id of file system to retrieve the storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciStorageResorcesByFileSystem {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of file system to retrieve the storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fileSystems/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve VMDKs for a file system
    .DESCRIPTION
 
    .PARAMETER id
    Id of file system to retrieve the VMDKs for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER virtualMachine
    Return related Virtual machine
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciVmdksByFileSystem {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of file system to retrieve the VMDKs for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return related Virtual machine")][Switch]$virtualMachine,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","dataStore","storageResources","virtualMachine","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/fileSystems/$id/vmdks"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the topology of a host
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciTopologyByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the host to retrieve the topology for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/topology/Host/$id"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Topology = ParseTopologies -Topologies $Result -Timezone $Server.Timezone

        Write-Output $Topology
    }
}

<#
    .SYNOPSIS
    Retrieve the topology of a storage system
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciTopologyByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the storage system to retrieve the topology for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/topology/Storage/$id"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Topology = ParseTopologies -Topologies $Result -Timezone $Server.Timezone

        Write-Output $Topology
    }
}

## assets/hosts ##

<#
    .SYNOPSIS
    Retrieve all hosts
    .DESCRIPTION
 
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER limit
    Number of hosts per page (range: 0-50, default: 0)
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER sort
    Performance metric for sorting (Default diskIops.total)
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER virtualMachines
    Return list of related Virtual machines
    .PARAMETER dataCenter
    Return related Data center
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER clusterHosts
    Return list of related Cluster hosts
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciHosts {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Number of hosts per page (range: 0-50, default: 0)")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Performance metric for sorting (Default diskIops.total)")][String]$sort="diskIops.total",
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Virtual machines")][Switch]$virtualMachines,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Data center")][Switch]$dataCenter,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Cluster hosts")][Switch]$clusterHosts,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","applications","virtualMachines","dataCenter","annotations","clusterHosts","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items, thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts"

            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($sort) {
                $Uri += "$($Separator)sort=$sort"
                $Separator = '&'
            }
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Hosts = ParseHosts -Hosts $Result -Timezone $Server.Timezone

            if ($Hosts) { Write-Output $Hosts }

            if ($FetchAll -and @($Hosts).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciHosts -fromTime $fromTime -toTime $toTime -performance:$performance -performancehistory:$performancehistory -sort $sort -limit $limit -offset $offset -ports:$ports -storageResources:$storageResources -fileSystems:$fileSystems -applications:$applications -virtualMachines:$virtualMachines -dataCenter:$dataCenter -annotations:$annotations -clusterHosts:$clusterHosts -datasources:$datasources -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of hosts.
    .DESCRIPTION
    Retrieve total count of hosts.
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciHostCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/count"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result.Value
    }
}

<#
    .SYNOPSIS
    Retrieve one host
    .DESCRIPTION
    Retrieve one host
    .PARAMETER id
    Id of host to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER virtualMachines
    Return list of related Virtual machines
    .PARAMETER dataCenter
    Return related Data center
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER clusterHosts
    Return list of related Cluster hosts
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Virtual machines")][Switch]$virtualMachines,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Data center")][Switch]$dataCenter,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Cluster hosts")][Switch]$clusterHosts,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","applications","virtualMachines","dataCenter","annotations","clusterHosts","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Hosts = ParseHosts -Hosts $Result -Timezone $Server.Timezone

        Write-Output $Hosts
    }
}

<#
    .SYNOPSIS
    Remove annotations from host
    .DESCRIPTION
    Remove annotations from host
    .PARAMETER id
    Id of host to remove annotations from
    .PARAMETER Annotations
    Annotations to remove
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Remove-OciAnnotationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Annotations to remove")][PSObject[]]$annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/annotations"

        if ($definition) {
            $Uri += "?expand=definition"
        }

        if (!$Annotations) {
            $Annotations = Get-OciAnnotationsByHost -id $id -definition -Server $Server
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Retrieve annotations of host
    .DESCRIPTION
    Retrieve annotations of host
    .PARAMETER id
    Id of host to retrieve annotations for
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve annotations for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $($Server.BaseUri) + "/rest/v1/assets/hosts/$id/annotations"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Update annotations of host
    .DESCRIPTION
    Update annotations of host
    .PARAMETER id
    Id of host to update
    .PARAMETER annotation
    Annotations to update
    .PARAMETER definition
    Return annotation definitions
#>

function Global:Update-OciAnnotationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Id of object to update",
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                   Position=1,
                   HelpMessage="Annotations to update")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/annotations"

        if ($expand) {
            $Uri += "?$($Separator)expand=$expand"
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $AnnotationValues = ParseAnnotationValues -AnnotationValues $Result -Timezone $Server.Timezone
        Write-Output $AnnotationValues
    }
}

<#
    .SYNOPSIS
    Remove applications from host
    .DESCRIPTION
    Remove applications from host
    .PARAMETER id
    Id of host to remove applications from
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciApplicationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="Applications to remove")][PSObject[]]$Applications,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/applications"

        if ($expand) {
            $Uri += "?expand=$expand"
        }

        if (!$Applications) {
            $Applications = Get-OciApplicationsByHost -id $id -Server $Server
        }

        try {
            $Body = ConvertTo-Json -InputObject @($Applications) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Applications = ParseApplications -Applications $Result -Timezone $Server.Timezone
        Write-Output $Applications
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of a host
    .DESCRIPTION
    Retrieve the applications of a host
    .PARAMETER id
    Id of host to retrieve applications for
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciApplicationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve applications for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/applications"

        if ($expand) {
            $Uri += "$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Applications = ParseApplications -Applications $Result -Timezone $Server.Timezone
        if ($Applications) {
            Write-Output $Applications
        }
    }
}

<#
    .SYNOPSIS
    Update Applications of host
    .DESCRIPTION
    Update Applications of host
    .PARAMETER id
    Id of host to update applications of
    .PARAMETER Applications
    Applications to update
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Update-OciApplicationsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Applications to update")][PSObject[]]$Applications,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/applications"

        if ($expand) {
            $Uri += "$($Separator)expand=$expand"
        }

        try {
            $Body = ConvertTo-Json -InputObject @($Applications) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Applications = ParseApplications -Applications $Result -Timezone $Server.Timezone
        Write-Output $Applications
    }
}

<#
    .SYNOPSIS
    Add application to host
    .DESCRIPTION
    Add application to host
    .PARAMETER id
    Id of host to application to
    .PARAMETER Application
    Application to add to host
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Add-OciApplicationByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Applications to update")][PSObject]$Application,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/applications"

        if ($expand) {
            $Uri += "$($Separator)expand=$expand"
        }

        try {
            $Body = ConvertTo-Json -InputObject $Application -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Application = ParseApplications -Applications $Result -Timezone $Server.Timezone
        Write-Output $Application
    }
}

<#
    .SYNOPSIS
    Remove application from host
    .DESCRIPTION
    Remove application from host
    .PARAMETER id
    Id of host to remove application from
    .PARAMETER Application
    Application to remove from host
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciApplicationByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Applications to remove from host")][PSObject]$Application,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $($Server.BaseUri) + "/rest/v1/assets/hosts/$id/applications/$($Application.id)"

        if ($expand) {
            $Uri += "$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Applications = ParseApplications -Applications $Result -Timezone $Server.Timezone
        Write-Output $Applications
    }
}

<#
    .SYNOPSIS
    Retrieve the hosts from same cluster
    .DESCRIPTION
    Retrieve the hosts from same cluster
    .PARAMETER id
    Id of host to retrieve cluster hosts for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER virtualMachines
    Return list of related Virtual machines
    .PARAMETER dataCenter
    Return related Data center
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER clusterHosts
    Return list of related Cluster hosts
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciClusterHostsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve cluster hosts for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Virtual machines")][Switch]$virtualMachines,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Data center")][Switch]$dataCenter,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Cluster hosts")][Switch]$clusterHosts,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","applications","virtualMachines","dataCenter","annotations","clusterHosts","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/clusterHosts"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the data center of host
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
#>

function Global:Get-OciDataCenterByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/dataCenter"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a host.
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the file systems of host
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve file systems for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER computeResource
    Return related Compute resource
#>

function Global:Get-OciFileSystemsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve file systems for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Compute resource")][Switch]$computeResource,
        [parameter(Mandatory=$False,
                   Position=7,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageResources","vmdks","computeResource")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/fileSystems"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one host performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciHostPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the ports of host
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage resources by host
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageResourcesByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the virtual machines of host
    .DESCRIPTION
 
    .PARAMETER id
    Id of host to retrieve virtual machines for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER host
    Return related Host
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVirtualMachinesByHost {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of host to retrieve virtual machines for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Host")][Switch]$host,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","dataStore","host","vmdks","applications","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }

    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/hosts/$id/virtualMachines"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/internalVolumes ##

<#
    .SYNOPSIS
    Retrieve internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $InternalVolume = ParseInternalVolumes -InternalVolumes $Result -Timezone $Server.Timezone
            Write-Output $InternalVolume
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
        .PARAMETER definition
        Return related Definition
#>

function Global:Get-OciAnnotationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from internal volume
    .DESCRIPTION
    Bulk un-assign applications from internal volume
    .PARAMETER id
    Id of internal volume to update
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciApplicationsFromInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="List of application IDs",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/applications"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Body = ConvertTo-Json @($applicationId | ForEach-Object { @{id=$_} }) -Compress
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciApplicationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to internal volume
    .DESCRIPTION
    Bulk assign applications to internal volume
    .PARAMETER id
    Id of object to update
    .PARAMETER applicationId
    List of application IDs
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Add-OciApplicationsToInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="List of application IDs",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        $applicationId = @($applicationId)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/applications"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Body = ConvertTo-Json @($applicationId | ForEach-Object { @{id=$_} }) -Compress
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
    .PARAMETER applicationId
    Valid application id which should be associated
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciApplicationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Valid application id which should be associated")][String]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = "{ `"id`": `"$applicationId`" }"
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete application from internal volume
    .DESCRIPTION
    Delete application from internal volume
    .PARAMETER id
    Id of object to delete application from
    .PARAMETER appId
    Id of application to delete from object
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciApplicationsByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Id of application to delete from object")][Long]$appId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/applications/$appId"

            if ($expand) {
                $Uri += "?$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all compute resources for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve compute resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciComputeResourcesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve compute resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/computeResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all data stores for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve data stores for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER hosts
    Return list of related Hosts
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciDataStoresByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve data stores for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Hosts")][Switch]$hosts,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","hosts","vmdks","datasources","storageResources","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/dataStores"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the datasources for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve datasource for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve datasource for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve internal volume performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
        .PARAMETER history
        Return list of related History
#>

function Global:Get-OciInternalVolumePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve qtrees for one internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve storage qtrees for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER volumes
    Return list of related Volumes
#>

function Global:Get-OciQtreesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve storage qtrees for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","internalVolume","shares","annotations","applications","volumes")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/qtrees"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Qtrees = ParseQtrees -Qtrees $Result -Timezone $Server.Timezone
            Write-Output $Qtrees
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all replica source internal volumes for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve replica source internal volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciSourceInternalVolumesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve replica source internal volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/replicaSources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage nodes for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve storage nodes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER partner
    Return related HA partner
    .PARAMETER performance
    Return related Performance
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageNodesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve storage nodes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related HA partner")][Switch]$partner,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","partner","performance","datasources","storagePools","ports","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/storageNodes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageNodes = ParseStorageNodes -StorageNodes $Result -Timezone $Server.Timezone
            Write-Output $StorageNodes
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all volumes for an internal volume
    .DESCRIPTION
 
    .PARAMETER id
    Id of internal volume to retrieve volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVolumesByInternalVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of internal volume to retrieve volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/internalVolumes/$id/volumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Volues = ParseVolumes -Volumes $Result -Timezone $Server.Timezone
            Write-Output $Volumes
        }
    }
}

## assets/ports ##

<#
    .SYNOPSIS
    Retrieve one port
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
        .PARAMETER definition
        Return related Definition
#>

function Global:Get-OciAnnotationsByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-get-Port {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Get-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve connected ports for one port
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve connected port for
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciConnectedPortsByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve connected port for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/connectedPorts"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a port.
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one device for port
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve device
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
#>

function Global:Get-OciDeviceByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve device",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/device"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Fabric for port
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve fabric
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER switches
    Return list of related Switches
    .PARAMETER datasources
    Return list of related Datasources
#>

function Global:Get-OciFabricsByPort {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve fabric",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Switches")][Switch]$switches,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("switches","datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/fabrics"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one port performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of port to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciPortPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of port to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/ports/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

## assets/qtrees ##

<#
    .SYNOPSIS
    Retrieve one Qtree
    .DESCRIPTION
 
    .PARAMETER id
    Id of qtree to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER volumes
    Return list of related Volumes
#>

function Global:Get-OciQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of qtree to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","internalVolume","shares","annotations","applications","volumes")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
Remove annotations by qtree
    .DESCRIPTION
Remove annotations by qtree
    .PARAMETER id
    Id of object to delete
.PARAMETER Annotations
List of annotations to remove
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                HelpMessage="List of annotations to remove")][PSObject[]]$Annotations,
    [parameter(Mandatory=$False,
                Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
               Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
                }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/annotations"

        if ($Definition) {
            $Uri += "?expand=definition"
        }

        if (!$Annotations) {
            $Annotations = Get-OciAnnotationsByQtree -id $id -definition -Server $Server
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve annotations of qtree
    .DESCRIPTION
    Retrieve annotations of qtree
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
                }

    Process {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/annotations"

            if ($Definition) {
                $Uri += "?expand=definition"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }

<#
    .SYNOPSIS
    Update Annotations of Qtree
    .DESCRIPTION
    Update Annotations of Qtree
    .PARAMETER id
    Id of object to update
    .PARAMETER Annotations
    Annotations to be updated
    .PARAMETER definition
    Return related Definition
#>

function Global:Update-OciAnnotationsByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Annotations to be updated")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/annotations"

        if ($Definition) {
            $Uri += "?expand=definition"
        }

        try {
        $Body = ConvertTo-Json -InputObject @($Annotations | ForEach-Object { @{rawValue=$_.rawValue;definition=@{id=$_.definition.id}} } ) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete application from object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to delete application from
    .PARAMETER appId
    Id of application to delete from object
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Id of application to delete from object")][Long]$appId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/applications/$appId"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve internal volume for given qtree
    .DESCRIPTION
 
    .PARAMETER id
    Id of qtree to retrieve internal volume for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciInternalVolumeByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of qtree to retrieve internal volume for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/internalVolume"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve shares for one qtree
    .DESCRIPTION
 
    .PARAMETER id
    Id of qtree to retrieve shares for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
#>

function Global:Get-OciSharesByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of qtree to retrieve shares for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=8,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","qtree","annotations","applications")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/shares"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage for given qtree
    .DESCRIPTION
 
    .PARAMETER id
    Id of qtree to retrieve storage for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of qtree to retrieve storage for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/storage"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Storage = ParseStorages -Storages $Result -Timezone $Server.Timezone
            Write-Output $Storage
        }
    }
}

<#
    .SYNOPSIS
    Retrieve volumes for one qtree
    .DESCRIPTION
 
    .PARAMETER id
    Id of qtree to retrieve volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVolumesByQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of qtree to retrieve volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=21,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/qtrees/$id/volumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Volumes = ParseVolumes -Volumes $Result -Timezone $Timezone
            Write-Output $Volumes
        }
    }
}

## assets/shares ##

<#
    .SYNOPSIS
    Retrieve one Share
    .DESCRIPTION
 
    .PARAMETER id
    Id of share to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
#>

function Global:Get-OciShare {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of share to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=8,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","qtree","annotations","applications")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete application from object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to delete application from
    .PARAMETER appId
    Id of application to delete from object
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Id of application to delete from object")][Long]$appId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/applications/{appId}"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve qtree for given share
    .DESCRIPTION
 
    .PARAMETER id
    Id of share to retrieve qtree for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER volumes
    Return list of related Volumes
#>

function Global:Get-OciQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of share to retrieve qtree for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","internalVolume","shares","annotations","applications","volumes")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/qtree"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage for given share
    .DESCRIPTION
    Retrieve storage for given share
    .PARAMETER id
    Id of share to retrieve storage for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageByShare {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of share to retrieve storage for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/shares/$id/storage"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/storageNodes ##

<#
    .SYNOPSIS
    Retrieve one storage node
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage node to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER partner
    Return related HA partner
    .PARAMETER performance
    Return related Performance
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage node to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related HA partner")][Switch]$partner,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","partner","performance","datasources","storagePools","ports","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageNodes = ParseStorageNodes -StorageNodes $Result -Timezone $Server.Timezone
            Write-Output $StorageNodes
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
        .PARAMETER definition
        Return related Definition
#>

function Global:Get-OciAnnotationsByStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage node datasources
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage node to retrieve datasources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage node to retrieve datasources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage node performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage node to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciStorageNodePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage node to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all ports by node
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage node to retrieve ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsByStorageNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage node to retrieve ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage pools by node
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage node to retrieve storage pool for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStoragePoolsByNode {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage node to retrieve storage pool for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storageNodes/$id/storagePools"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/storagePools ##

<#
    .SYNOPSIS
    Retrieve one storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage pool datasources
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve datasources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve datasources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Disks for storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve disks for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER backendVolumes
    Return list of related Backend volumes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciDisksByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve disks for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Backend volumes")][Switch]$backendVolumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","storagePools","performance","storageResources","backendVolumes","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/disks"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve internal volumes for storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve internal volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciInternalVolumesByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve internal volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/internalVolumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage pool performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
        .PARAMETER history
        Return list of related History
#>

function Global:Get-OciStoragePoolPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage pool storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve storage for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve storage for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/storage"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage nodes for storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve storage nodes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER partner
    Return related HA partner
    .PARAMETER performance
    Return related Performance
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageNodesByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve storage nodes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related HA partner")][Switch]$partner,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","partner","performance","datasources","storagePools","ports","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/storageNodes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve resources for storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageResourcesByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve volumes for storage pool
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage pool to retrieve volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVolumesByStoragePool {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage pool to retrieve volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=21,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storagePools/$id/volumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Volumes = ParseVolumes -Volumes $Result -Timezone $Server.Timezone
            Write-Output $Volumes
        }
    }
}

## assets/storages ##

<#
    .SYNOPSIS
    Retrieve all storages
    .DESCRIPTION
    Retrieve all storages
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER sort
    Filter for sorting by metric/s
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER limit
    Number of storages per page.
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorages {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Number of storages per page.")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Filter for sorting by metric/s")][String]$sort="iops.total",
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=21,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=22,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        # OCI allows to only fetch maximum 50 items, thus we need to repeat the command if no limit is specified to fetch all items
        if ($Limit -eq 0) {
            $FetchAll = $true
            $Limit = 50
        }

        $Uri = $Server.BaseUri + "/rest/v1/assets/storages"

        $Uri += '?'
        $Separator = ''
        if ($fromTime) {
            $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
            $Separator = '&'
        }
        if ($toTime) {
            $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
            $Separator = '&'
        }
        if ($sort) {
            $Uri += "$($Separator)sort=$sort"
            $Separator = '&'
        }
        if ($limit) {
            $Uri += "$($Separator)limit=$limit"
            $Separator = '&'
        }
        if ($limit -and $offset) {
            $Uri += "$($Separator)offset=$offset"
            $Separator = '&'
        }
        if ($expand) {
            $Uri += "$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Storages = ParseStorages -Storages $Result -Timezone $Server.Timezone
        if ($Storages) { Write-Output $Storages }

        if ($FetchAll -and @($Storages).Count -eq $Limit) {
            $Offset += $Limit
            Get-OciStorages -fromTime $fromTime -toTime $toTime -sort $sort -limit $limit -offset $offset -performance:$performance -performancehistory:$performancehistory -storageNodes:$storageNodes -storageResources:$storageResources -storagePools:$storagePools -internalVolumes:$internalVolumes -volumes:$volumes -qtrees:$qtrees -shares:$shares -ports:$ports -datasources:$datasources -annotations:$annotations -disks:$disks -protocols:$protocols -applications:$applications -Server $Server
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of storages.
    .DESCRIPTION
 
 
#>

function Global:Get-OciStorageCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/count"

            try {
                    $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id"

        if ($fromTime -or $toTime -or $expand) {
            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        $Storage = ParseStorages -Storages $Result -Timezone $Server.Timezone
        Write-Output $Storage
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
 
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a storage.
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve disks for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve disks for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER backendVolumes
    Return list of related Backend volumes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciDisksByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve disks for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Backend volumes")][Switch]$backendVolumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","storagePools","performance","storageResources","backendVolumes","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/disks"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve internal volumes for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve internal volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciInternalVolumesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve internal volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=21,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/internalVolumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one storage performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciStoragePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage ports for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve protocols of a storage.
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve protocols for.
#>

function Global:Get-OciProtocolsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve protocols for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/protocols"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage qtrees for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage qtrees for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER volumes
    Return list of related Volumes
#>

function Global:Get-OciQtreesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage qtrees for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","internalVolume","shares","annotations","applications","volumes")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/qtrees"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage shares for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage shares for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
#>

function Global:Get-OciSharesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage shares for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=8,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","qtree","annotations","applications")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/shares"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage nodes for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage nodes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER partner
    Return related HA partner
    .PARAMETER performance
    Return related Performance
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageNodesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage nodes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related HA partner")][Switch]$partner,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","partner","performance","datasources","storagePools","ports","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/storageNodes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage pools for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage pools for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStoragePoolsByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage pools for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/storagePools"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage resources for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageResourcesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve volumes for one storage
    .DESCRIPTION
 
    .PARAMETER id
    Id of storage to retrieve volumes for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVolumesByStorage {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of storage to retrieve volumes for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/storages/$id/volumes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/switches ##

<#
    .SYNOPSIS
    Retrieve all Switches
    .DESCRIPTION
    Retrieve all Switches
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER limit
    Number of switches per page.
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER fabric
    Return related Fabric
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciSwitches {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Number of switches per page (range: 0-50, default: 0)")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return related Fabric")][Switch]$fabric,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("fabric","performance","ports","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items, thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $Server.BaseUri + "/rest/v1/assets/switches"

            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($sort) {
                $Uri += "$($Separator)sort=$sort"
                $Separator = '&'
            }
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Switches = ParseSwitches -Switches $Result -Timezone $Server.Timezone
            if ($Switches) { Write-Output $Switches }

            if ($FetchAll -and @($Switches).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciSwitches -fromTime $fromTime -toTime $toTime -performance:$performance -performancehistory:$performancehistory -limit $limit -offset $offset -fabric:$fabric -ports:$ports -annotations:$annotations -datasources:$datasources -applications:$appliactions -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of switches.
    .DESCRIPTION
 
 
#>

function Global:Get-OciSwitchCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/switches/count"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result.Value
    }
}

<#
    .SYNOPSIS
    Retrieve one switch
    .DESCRIPTION
    Retrieve one switch
    .PARAMETER id
    Id of switch to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER fabric
    Return related Fabric
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciSwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of switch to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Fabric")][Switch]$fabric,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("fabric","performance","ports","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Switch = ParseSwitches -Switches $Result -Timezone $Server.Timezone
            Write-Output $Switch
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
    Retrieve annotations for object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                    Write-Verbose "Body: $Body"
                    $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
    Retrieve the applications of object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciApplicationsBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a switch
    .DESCRIPTION
    Retrieve datasources of a switch
    .PARAMETER id
    Id of switch to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of switch to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one fabric from switch
    .DESCRIPTION
 
    .PARAMETER id
    Id of switch.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=portSummary)
        .PARAMETER switches
        Return list of related Switches
        .PARAMETER datasources
        Return list of related Datasources
#>

function Global:Get-OciFabricBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of switch.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=portSummary)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Switches")][Switch]$switches,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("switches","datasources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/fabric"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one switch performance.
    .DESCRIPTION
 
    .PARAMETER id
    Id of switch.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=portSummary)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciSwitchPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of switch.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=portSummary)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve switch ports for one switch
    .DESCRIPTION
 
    .PARAMETER id
    Id of switch to retrieve switch ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsBySwitch {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of switch to retrieve switch ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/switches/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## assets/virtualMachines ##

<#
    .SYNOPSIS
    Retrieve all Virtual Machines
    .DESCRIPTION
    Retrieve all Virtual Machines
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER performancehistory
    Return related Performance History
    .PARAMETER limit
    Number of virtual machines per page (range: 0-50, default: 0)
    .PARAMETER offset
    Offset to be used with limit
    .PARAMETER sort
    Performance metric for sorting (Default diskIops.total)
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER host
    Return related Host
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
#>

function Global:Get-OciVirtualMachines {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Number of virtual machines per page (range: 0-50, default: 0)")][Long]$limit=0,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Offset to be used with limit")][Long]$offset=0,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Performance metric for sorting (Default diskIops.total)")][String]$sort="diskIops.total",
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Host")][Switch]$HostSwitch,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","dataStore","HostSwitch","vmdks","applications","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            # OCI allows to only fetch maximum 50 items, thus we need to repeat the command if no limit is specified to fetch all items
            if ($Limit -eq 0) {
                $FetchAll = $true
                $Limit = 50
            }

            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines"

            $Uri += '?'
            $Separator = ''
            if ($fromTime) {
                $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($toTime) {
                $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                $Separator = '&'
            }
            if ($sort) {
                $Uri += "$($Separator)sort=$sort"
                $Separator = '&'
            }
            if ($limit) {
                $Uri += "$($Separator)limit=$limit"
                $Separator = '&'
            }
            if ($limit -and $offset) {
                $Uri += "$($Separator)offset=$offset"
                $Separator = '&'
            }
            if ($expand) {
                $Uri += "$($Separator)expand=$expand"
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $VirtualMachines = ParseVirtualMachines -VirtualMachines $Result -Timezone $Server.Timezone
            Write-Output $VirtualMachines

            if ($FetchAll -and @($VirtualMachines).Count -eq $Limit) {
                $Offset += $Limit
                Get-OciVirtualMachines -fromTime $fromTime -toTime $toTime -performance:$performance -performancehistory:$performancehistory -sort $sort -limit $limit -offset $offset -ports:$ports -storageResources:$storageResources -fileSystems:$fileSystems -dataStore:$dataStore -host:$HostSwitch -vmdks:$vmdks -applications:$applications -annotations:$annotations -datasources:$datasources -Server $Server
            }
        }
    }
}

<#
    .SYNOPSIS
    Retrieve total count of Virtual Machines
    .DESCRIPTION
    Retrieve total count of Virtual Machines
#>

function Global:Get-OciVirtualMachineCount {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/count"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result.Value
    }
}

<#
    .SYNOPSIS
    Retrieve one Virtual Machine
    .DESCRIPTION
    Retrieve one Virtual Machine
    .PARAMETER id
    Id of virtual machine to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER host
    Return related Host
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Host")][Switch]$host,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","dataStore","host","vmdks","applications","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $VirtualMachine = ParseVirtualMachines -VirtualMachines $Result -Timezone $Server.Timezone
            Write-Output $VirtualMachine
        }
    }
}

<#
    .SYNOPSIS
    Remove annotations from virtual machine
    .DESCRIPTION
    Remove annotations from virtual machine
    .PARAMETER id
    Id of object to delete
    .PARAMETER Annotations
    List of annotations to remove
    .PARAMETER definition
    Return related Definition
#>

function Global:Remove-OciAnnotationsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="List of annotations to remove")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/annotations"

        if ($Definition) {
            $Uri += "?expand=definition"
        }

        if (!$Annotations) {
            $Annotations = Get-OciAnnotationsByVirtualMachine -id $id -definition -Server $Server
        }

        try {
            $Body = ConvertTo-Json @($Annotations | ConvertTo-AnnotationValues) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
    Retrieve annotations for object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/annotations"

        if ($Definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Update Annotations of Virtual Machine
    .DESCRIPTION
    Update Annotations of Virtual Machine
    .PARAMETER id
    Id of object to update
    .PARAMETER Annotations
    Annotations to be updated
    .PARAMETER definition
    Return related Definition
#>

function Global:Update-OciAnnotationsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Annotations to be updated")][PSObject[]]$Annotations,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/annotations"

        if ($Definition) {
            $Uri += "?expand=definition"
        }

        try {
            $Body = ConvertTo-Json $($Annotations | ForEach-Object { @{rawValue=$_.rawValue;definition=@{id=$_.definition.id}} } ) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciUnAssignApplicationsFromAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
    Retrieve the applications of object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciApplicationsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Bulk-OciAssignApplicationsToAsset {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete application from object
    .DESCRIPTION
    Delete application from object
    .PARAMETER id
    Id of object to delete application from
    .PARAMETER appId
    Id of application to delete from object
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Id of application to delete from object")][Long]$appId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/applications/$appId"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one data store for virtual machine
    .DESCRIPTION
    Retrieve one data store for virtual machine
    .PARAMETER id
    Id of virtual machine to retrieve data store for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER hosts
    Return list of related Hosts
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciDataStoreByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve data store for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Hosts")][Switch]$hosts,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","hosts","vmdks","datasources","storageResources","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/dataStore"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datastore = ParseDatastores -Datastores $Result -Timezone $Timezone
            Write-Output $Datastore
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a virtual machine.
    .DESCRIPTION
    Retrieve datasources of a virtual machine.
    .PARAMETER id
    Id of virtual machine to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all file systems by virtual machine
    .DESCRIPTION
    Retrieve all file systems by virtual machine
    .PARAMETER id
    Id of virtual machine to retrieve file systems for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER computeResource
    Return related Compute resource
#>

function Global:Get-OciFileSystemsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve file systems for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Compute resource")][Switch]$computeResource,
        [parameter(Mandatory=$False,
                   Position=7,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageResources","vmdks","computeResource")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/fileSystems"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one virtual machine host
    .DESCRIPTION
    Retrieve one virtual machine host
    .PARAMETER id
    Id of virtual machine to retrieve host for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER virtualMachines
    Return list of related Virtual machines
    .PARAMETER dataCenter
    Return related Data center
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER clusterHosts
    Return list of related Cluster hosts
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciHostByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve host for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Virtual machines")][Switch]$virtualMachines,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Data center")][Switch]$dataCenter,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Cluster hosts")][Switch]$clusterHosts,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","applications","virtualMachines","dataCenter","annotations","clusterHosts","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/host"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Hosts = ParseHosts -Hosts $Result -Timezone $Server.Timezone
            Write-Output $Hosts
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one Virtual Machine Performance
    .DESCRIPTION
    Retrieve one Virtual Machine Performance
    .PARAMETER id
    Id of virtual machine to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
        .PARAMETER history
        Return list of related History
#>

function Global:Get-OciVirtualMachinePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all ports by virtual machine
    .DESCRIPTION
    Retrieve all ports by virtual machine
    .PARAMETER id
    Id of virtual machine to retrieve ports for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve ports for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Ports = ParsePorts -Ports $Result -Timezone $Server.Timezone
            Write-Output $Ports
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage resources by virtual machine
    .DESCRIPTION
    Retrieve all storage resources by virtual machine
    .PARAMETER id
    Id of virtual machine to retrieve storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageResourcesByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageResources = ParseStorageResources -StorageResources $Result -Timezone $Server.Timezone
            Write-Output $StorageResources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve Vmdks for virtual machine
    .DESCRIPTION
    Retrieve Vmdks for virtual machine
    .PARAMETER id
    Id of virtual machine to retrieve disks for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER virtualMachine
    Return related Virtual machine
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVmdksByVirtualMachine {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine to retrieve disks for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return related Virtual machine")][Switch]$virtualMachine,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","dataStore","storageResources","virtualMachine","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/virtualMachines/$id/vmdks"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Vmdks = ParseVmdks -Vmdks $Result -Timezone $Server.Timezone
            Write-Output $Vmdks
        }
    }
}

## assets/vmdks ##

<#
    .SYNOPSIS
    Retrieve one virtual machine Vmdk
    .DESCRIPTION
    Retrieve one virtual machine Vmdk
    .PARAMETER id
    Id of virtual machine disk to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER virtualMachine
    Return related Virtual machine
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine disk to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return related Virtual machine")][Switch]$virtualMachine,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","dataStore","storageResources","virtualMachine","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Vmdk = ParseVmdks -Vmdks $Result -Timezone $Server.Timezone
            Write-Output $Vmdk
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations for object
    .DESCRIPTION
    Retrieve annotations for object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: "
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a vmdk.
    .DESCRIPTION
    Retrieve datasources of a vmdk.
    .PARAMETER id
    Id of vmdk to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of vmdk to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
            Write-Output $Datasources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one Vmdk performance
    .DESCRIPTION
    Retrieve one Vmdk performance
    .PARAMETER id
    Id of virtual machine disk to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciVmdkPerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine disk to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage resources for virtual machine disk
    .DESCRIPTION
    Retrieve storage resources for virtual machine disk
    .PARAMETER id
    Id of virtual machine disk to retrieve storage resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageResourcesByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine disk to retrieve storage resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/storageResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $StorageResources = ParseStorageResources -StorageResources $Result -Timezone $Server.Timezone
            Write-Output $StorageResources
        }
    }
}

<#
    .SYNOPSIS
    Retrieve virtual machine for virtual machine disk
    .DESCRIPTION
    Retrieve virtual machine for virtual machine disk
    .PARAMETER id
    Id of virtual machine disk to retrieve virtual machine for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER dataStore
    Return related Datastore
    .PARAMETER host
    Return related Host
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVirtualMachineByVmdk {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of virtual machine disk to retrieve virtual machine for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Datastore")][Switch]$dataStore,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Host")][Switch]$host,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=15,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","dataStore","host","vmdks","applications","annotations","datasources","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/vmdks/$id/virtualMachine"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $VirtualMachine = ParseVirtualMachines -VirtualMachines $Result -Timezone $Server.Timezone
            Write-Output $VirtualMachine
        }
    }
}

## assets/volumes ##

<#
    .SYNOPSIS
    Retrieve one volume
    .DESCRIPTION
    Retrieve one volume
    .PARAMETER id
    Id of volume to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Volume = ParseVolumes -Volumes $Result -Timezone $Server.Timezone
            Write-Output $Volume
        }
    }
}

<#
    .SYNOPSIS
    Delete annotations from object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
{
  "definition":{"id":"5001"}
},
{
  "definition":{"id":"5002"}
}
]
</pre>
 
    .PARAMETER id
    Id of object to delete
        .PARAMETER definition
        Return related Definition
#>

function Global:Remove-OciAnnotationsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve annotations by volume
    .DESCRIPTION
    Retrieve annotations by volume
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=definition)
    .PARAMETER definition
    Return related Definition
#>

function Global:Get-OciAnnotationsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=definition)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=3,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Update annotations for object
    .DESCRIPTION
    Request body should be like JSON below: <br/>
 
<pre>
 
[
  {
    "rawValue": "Bronze",
    "definition": {
      "id": "4992",
    }
  }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER definition
        Return related Definition
#>

function Global:Update-OciAnnotationsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Return related Definition")][Switch]$definition,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("definition")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/annotations"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ""
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PUT -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PUT to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk un-assign applications from volume
    .DESCRIPTION
    Bulk un-assign applications from volume
    .PARAMETER id
    Id of volume to remove applications from
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciApplicationsFromVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="List of application IDs")][String[]]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/applications"

        if (!$applicationId) {
            $applicationId = Get-OciApplicationsByVolume -id $id | Select-Object -ExpandProperty id
        }

        try {
            $Body = ConvertTo-Json @($applicationId | ForEach-Object { @{id=$_} }) -Compress
            Write-Verbose "Body: $Body"
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Retrieve the applications of object
    .DESCRIPTION
    Retrieve the applications of object
    .PARAMETER id
    Id of object to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Get-OciApplicationsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=6,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Bulk assign applications to asset
    .DESCRIPTION
    Request body should contain a list of valid application ids, example: <br/>
 
<pre>
[
    {
        "id":"12345"
    },
    {
        "id":"67890"
    }
]
</pre>
 
    .PARAMETER id
    Id of object to update
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Add-OciApplicationsToVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="List of application IDs",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][String[]]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ConvertTo-Json @($applicationId | ForEach-Object { @{id=$_} }) -Compress
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method PATCH -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "PATCH to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Add applications for object
    .DESCRIPTION
    Request body should contain only one valid application id, example: <br/>
 
<pre>
{
    "id":"12345"
}
</pre>
 
    .PARAMETER id
    Id of object to update
    .PARAMETER applicationId
    Valid application id which should be associated
        .PARAMETER computeResources
        Return list of related Compute resources
        .PARAMETER storageResources
        Return list of related Storage resources
#>

function Global:Update-OciApplicationsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to update",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Valid application id which should be associated")][String]$applicationId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/applications"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Body = ConvertTo-Json ($applicationId | ForEach-Object { @{id=$_} }) -Compress
                Write-Verbose "Body: $Body"
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method POST -Uri $Uri -Headers $Server.Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -ContentType 'application/json'
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "POST to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Delete application from object
    .DESCRIPTION
    Delete application from object
    .PARAMETER id
    Id of object to delete application from
    .PARAMETER appId
    Id of application to delete from object
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER storageResources
    Return list of related Storage resources
#>

function Global:Remove-OciByTypeAndId {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of object to delete application from",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$True,
                    Position=1,
                    HelpMessage="Id of application to delete from object")][Long]$appId,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                   Position=4,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("computeResources","storageResources")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/applications/$appId"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the auto tier policy name of a volume.
    .DESCRIPTION
    Retrieve the auto tier policy name of a volume.
    .PARAMETER id
    Id of the volume to retrieve the auto tier policy name.
#>

function Global:Get-OciAutoTierPolicyByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the volume to retrieve the auto tier policy name.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@()
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/autoTierPolicy"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all compute resources for a volume
    .DESCRIPTION
    Retrieve all compute resources for a volume
    .PARAMETER id
    Id of volume to retrieve compute resources for
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER fileSystems
    Return list of related File systems
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciComputeResourcesByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve compute resources for",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related File systems")][Switch]$fileSystems,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=9,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","ports","storageResources","fileSystems","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/computeResources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all data stores for a given target volume.
    .DESCRIPTION
    Retrieve all data stores for a given target volume.
    .PARAMETER id
    Id of target volume to retrieve the data stores for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER performance
    Return related Performance
    .PARAMETER hosts
    Return list of related Hosts
    .PARAMETER vmdks
    Return list of related Vmdks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciDatastoresByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of target volume to retrieve the data stores for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Hosts")][Switch]$hosts,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Vmdks")][Switch]$vmdks,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=11,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("performance","hosts","vmdks","datasources","storageResources","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/dataStores"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve datasources of a volume.
    .DESCRIPTION
    Retrieve datasources of a volume.
    .PARAMETER id
    Id of volume to retrieve datasources for.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER acquisitionUnit
    Return related Acquisition unit
    .PARAMETER note
    Return related Note
    .PARAMETER changes
    Return list of related Changes
    .PARAMETER packages
    Return list of related Packages
    .PARAMETER activePatch
    Return related Active patch
    .PARAMETER events
    Return list of related Events
    .PARAMETER devices
    Return list of related Devices
    .PARAMETER config
    Return related Config
#>

function Global:Get-OciDatasourcesByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve datasources for.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Acquisition unit")][Switch]$acquisitionUnit,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Note")][Switch]$note,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Changes")][Switch]$changes,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Packages")][Switch]$packages,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return related Active patch")][Switch]$activePatch,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Events")][Switch]$events,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Devices")][Switch]$devices,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Config")][Switch]$config,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("acquisitionUnit","note","changes","packages","activePatch","events","devices","config")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/datasources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve internal volume for a given volume.
    .DESCRIPTION
    Retrieve internal volume for a given volume.
    .PARAMETER id
    Id of volume to retrieve the internal volume.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePool
    Return related Storage pool
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciInternalVolumeByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the internal volume.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return related Storage pool")][Switch]$storagePool,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=17,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePool","volumes","storageNodes","annotations","datasources","replicaSources","qtrees","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/internalVolume"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve one volume performance
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER history
    Return list of related History
#>

function Global:Get-OciVolumePerformance {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related History")][Switch]$history,
        [parameter(Mandatory=$False,
                   Position=5,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("history")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/performance"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            $Performance = ParsePerformance -Performance $Result -Timezone $Server.Timezone
            Write-Output $Performance
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all storage ports and their connected ports by volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the ports that are connected to storage ports.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER device
    Return related Device Object
    .PARAMETER fabrics
    Return list of related Fabrics
    .PARAMETER performance
    Return related Performance
    .PARAMETER connectedPorts
    Return list of related Connected ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciPortsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the ports that are connected to storage ports.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Device Object")][Switch]$device,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Fabrics")][Switch]$fabrics,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Connected ports")][Switch]$connectedPorts,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("device","fabrics","performance","connectedPorts","annotations","datasources","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/ports"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve qtree for a given volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the qtree.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER volumes
    Return list of related Volumes
#>

function Global:Get-OciQtree {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the qtree.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                   Position=10,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","internalVolume","shares","annotations","applications","volumes")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/qtree"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve all source volumes for a given target volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of target volume to retrieve the source volumes.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER dataStores
    Return list of related Datastores
    .PARAMETER computeResources
    Return list of related Compute resources
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER virtualStoragePools
    Return list of related Virtual storage pools
    .PARAMETER virtualizer
    Return related Virtualizer
    .PARAMETER internalVolume
    Return related Internal volume
    .PARAMETER autoTierPolicy
    Return related Auto tier policy
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER replicaSources
    Return list of related Replica sources
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER qtree
    Return related Qtree
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciSourceVolumesByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of target volume to retrieve the source volumes.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Datastores")][Switch]$dataStores,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Compute resources")][Switch]$computeResources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Virtual storage pools")][Switch]$virtualStoragePools,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Virtualizer")][Switch]$virtualizer,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return related Internal volume")][Switch]$internalVolume,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Auto tier policy")][Switch]$autoTierPolicy,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Replica sources")][Switch]$replicaSources,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=19,
                    HelpMessage="Return related Qtree")][Switch]$qtree,
        [parameter(Mandatory=$False,
                    Position=20,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=21,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","dataStores","computeResources","applications","storagePools","virtualStoragePools","virtualizer","internalVolume","autoTierPolicy","ports","storageNodes","replicaSources","datasources","annotations","qtree","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/replicaSources"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve the storage of a volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of the volume to retrieve the storage.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of the volume to retrieve the storage.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/storage"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage nodes for a given volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the storage nodes.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER partner
    Return related HA partner
    .PARAMETER performance
    Return related Performance
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStorageNodesByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the storage nodes.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related HA partner")][Switch]$partner,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=12,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","partner","performance","datasources","storagePools","ports","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/storageNodes"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve storage pools for a given volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the storage pools.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciStoragePoolsByVolume {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the storage pools.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/storagePools"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve virtual storage pools for a given volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the virtual storage pools.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storage
    Return related Storage
    .PARAMETER performance
    Return related Performance
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVirtualStoragePools {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the virtual storage pools.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return related Storage")][Switch]$storage,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=14,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storage","performance","storageResources","internalVolumes","volumes","disks","datasources","storageNodes","annotations","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/virtualStoragePools"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

<#
    .SYNOPSIS
    Retrieve virtualizer for a given backend volume.
    .DESCRIPTION
 
    .PARAMETER id
    Id of volume to retrieve the virtualizer.
    .PARAMETER fromTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER toTime
    Filter for time range, either in milliseconds or as DateTime
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=read,items)
    .PARAMETER storageNodes
    Return list of related Storage nodes
    .PARAMETER storageResources
    Return list of related Storage resources
    .PARAMETER storagePools
    Return list of related Storage pools
    .PARAMETER internalVolumes
    Return list of related Internal volumes
    .PARAMETER volumes
    Return list of related Volumes
    .PARAMETER qtrees
    Return list of related Qtrees
    .PARAMETER shares
    Return list of related Shares
    .PARAMETER ports
    Return list of related Ports
    .PARAMETER datasources
    Return list of related Datasources
    .PARAMETER annotations
    Return list of related Annotations
    .PARAMETER disks
    Return list of related Disks
    .PARAMETER performance
    Return related Performance
    .PARAMETER protocols
    Return list of related Protocols
    .PARAMETER applications
    Return list of related Applications
    .PARAMETER performancehistory
    Return related Performance History
#>

function Global:Get-OciVirtualizer {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of volume to retrieve the virtualizer.",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                    Position=1,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$fromTime,
        [parameter(Mandatory=$False,
                    Position=2,
                    HelpMessage="Filter for time range, either in milliseconds or as DateTime")][PSObject]$toTime,
        [parameter(Mandatory=$False,
                    Position=3,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=read,items)")][String]$expand,
        [parameter(Mandatory=$False,
                    Position=4,
                    HelpMessage="Return list of related Storage nodes")][Switch]$storageNodes,
        [parameter(Mandatory=$False,
                    Position=5,
                    HelpMessage="Return list of related Storage resources")][Switch]$storageResources,
        [parameter(Mandatory=$False,
                    Position=6,
                    HelpMessage="Return list of related Storage pools")][Switch]$storagePools,
        [parameter(Mandatory=$False,
                    Position=7,
                    HelpMessage="Return list of related Internal volumes")][Switch]$internalVolumes,
        [parameter(Mandatory=$False,
                    Position=8,
                    HelpMessage="Return list of related Volumes")][Switch]$volumes,
        [parameter(Mandatory=$False,
                    Position=9,
                    HelpMessage="Return list of related Qtrees")][Switch]$qtrees,
        [parameter(Mandatory=$False,
                    Position=10,
                    HelpMessage="Return list of related Shares")][Switch]$shares,
        [parameter(Mandatory=$False,
                    Position=11,
                    HelpMessage="Return list of related Ports")][Switch]$ports,
        [parameter(Mandatory=$False,
                    Position=12,
                    HelpMessage="Return list of related Datasources")][Switch]$datasources,
        [parameter(Mandatory=$False,
                    Position=13,
                    HelpMessage="Return list of related Annotations")][Switch]$annotations,
        [parameter(Mandatory=$False,
                    Position=14,
                    HelpMessage="Return list of related Disks")][Switch]$disks,
        [parameter(Mandatory=$False,
                    Position=15,
                    HelpMessage="Return related Performance")][Switch]$performance,
        [parameter(Mandatory=$False,
                    Position=16,
                    HelpMessage="Return list of related Protocols")][Switch]$protocols,
        [parameter(Mandatory=$False,
                    Position=17,
                    HelpMessage="Return list of related Applications")][Switch]$applications,
        [parameter(Mandatory=$False,
                    Position=18,
                    HelpMessage="Return related Performance History")][Switch]$performancehistory,
        [parameter(Mandatory=$False,
                   Position=19,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }

        $switchparameters=@("storageNodes","storageResources","storagePools","internalVolumes","volumes","qtrees","shares","ports","datasources","annotations","disks","performance","protocols","applications","performancehistory")
        foreach ($parameter in $switchparameters) {
            if ((Get-Variable $parameter).Value) {
                if ($expand) {
                    $expand += ",$($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')"
                }
                else {
                    $expand = $($parameter -replace 'performancehistory','performance.history' -replace 'hostswitch','host')
                }
            }
        }
    }

    Process {
        $id = @($id)
        foreach ($id in $id) {
            $Uri = $Server.BaseUri + "/rest/v1/assets/volumes/$id/virtualizer"

            if ($fromTime -or $toTime -or $expand) {
                $Uri += '?'
                $Separator = ''
                if ($fromTime) {
                    $Uri += "fromTime=$($fromTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($toTime) {
                    $Uri += "$($Separator)toTime=$($toTime | ConvertTo-UnixTimestamp)"
                    $Separator = '&'
                }
                if ($expand) {
                    $Uri += "$($Separator)expand=$expand"
                }
            }

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result
        }
    }
}

## other ##

<#
    .SYNOPSIS
    Search for OCI Objects
    .DESCRIPTION
    Search for OCI Objects
    .PARAMETER query
    Query parameter
#>

function Global:Search-Oci {
    [CmdletBinding()]

    PARAM (
            [parameter(Mandatory=$true,
                    Position=0,
                    HelpMessage="The search query expression parameter",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][string[]]$query,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        foreach ($query in $query) {
            $Uri = $Server.BaseUri + "/rest/v1/search?query=$query"

            try {
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
            }
            catch {
                $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
            }

            if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
                $Result = ParseJsonString -json $Result.Trim()
            }

            Write-Output $Result.resultsByCategory
        }
    }
}

## identifications ##

<#
    .SYNOPSIS
    Retrieve FC Identify
    .DESCRIPTION
    Retrieve FC Identify
    .PARAMETER expand
    Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciFcIdentify {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                    Position=0,
                    HelpMessage="Expand parameter for underlying JSON object (e.g. expand=acquisitionUnit)")][String]$expand,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/identifications/fc"

        if ($expand) {
            $Uri += "?$($Separator)expand=$expand"
        }

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim
        }

        #$Datasources = ParseDatasources -Datasources $Result -Timezone $Server.Timezone
        Write-Output $Result
    }
}

### Experimental Cmdlets ###

<#
    .SYNOPSIS
    Retrieve OCI Server health status
    .DESCRIPTION
    Retrieve OCI Server health status
#>

function Global:Get-OciHealth {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/health"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        foreach ($Item in $Result) {
            $Item.time = $Item.time | ConvertFrom-UnixTimestamp
        }

        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Restore OCI Backup
    .DESCRIPTION
    Restore OCI Backup
#>

function Global:Restore-OciBackup {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Full path of OnCommand Insight Backup, either locally or on OnCommand Insight Server.",
                   ValueFromPipeline=$True,
                   ValueFromPipelineByPropertyName=$True)][Alias("Path")][String[]]$FilePath,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $FilePath = @($FilePath)

        $StartTime = Get-Date

        foreach ($FilePath in $FilePath) {
            $Uri = $Server.BaseUri + "/rest/v1/admin/restore"

            $FilePath = Get-Item $FilePath

            if (Test-Path $FilePath) {
                Write-Host "Found local OCI Backup in $FilePath which will be restored"

                Write-Host "Starting Restore job. This can take several hours..."

                $Job = Start-Job {
                    Import-Module OnCommand-Insight

                    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

                    Invoke-MultipartFormDataUpload -InFile $args[0] -Name "backupFile" -Uri $args[1] -Header $args[2]
                } -ArgumentList $FilePath,$URI,$Server.Headers

            }
            else {
                Write-Host "No local Backup in $FilePath, trying to restore backup residing on OnCommand Insight Server"

                # create boundary
                $boundary = [System.Guid]::NewGuid().ToString()

                # Linefeed character
                $LF = "`r`n"

                # Build Body for form-data manually since PS does not support multipart/form-data out of the box
                $Body = (
                    "--$boundary",
                    "Content-Disposition: form-data; name=`"backupFilePath`"$LF",
                    $FilePath,
                    "--$boundary--$LF"
                ) -join $LF

                Write-Host "Starting Restore job..."

                $Job = Start-Job {

                    Import-Module OnCommand-Insight

                    [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

                    Invoke-RestMethod -WebSession $Server.Session -Uri $args[0] -Timeout 864000000000 -Method Post -ContentType "multipart/form-data; boundary=`"$($args[1])`"" -Body $args[2] -Headers $args[3]
                } -ArgumentList $URI,$boundary,$Body,$Server.Headers
            }

            $percentComplete = 10
            $activity = "Restore started"
            $status = "Uploading"
            Write-Progress -Activity $activity -status $status -percentComplete $percentComplete
            Start-Sleep -Seconds 2
            $i = 0
            while ($true) {
                $ProgressUri = $Uri + "?_=" + (get-date | ConvertTo-UnixTimestamp)
                $i++
                try {
                    $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $ProgressUri -Headers $Server.Headers -ErrorAction SilentlyContinue
                }
                catch {
                    $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
                    Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
                }
                if ($i -eq 1440) {
                    Write-Host ''
                    throw 'Restore did not finish within 24 hours'
                }
                if ($Result.status -eq 'SUCCESSFUL') {
                    Write-Host "finished"
                    return
                }
                elseif ($Result.status -eq 'FAILED' -and ($Result.currentStep.startTime | get-date) -ge $StartTime -or $Job.State -ne 'Running') {
                    return
                }
                elseif (($Result.currentStep.startTime | get-date) -ge $StartTime) {
                    if ($Result.currentStep.operationText) {
                        $activity = $Result.currentStep.operationText
                    }
                    $status = $Result.components.name | Select-Object -last 1
                    if (!$status) {
                        $status = $Result.status
                    }
                }
                switch ($Result.currentStep.phaseText) {
                    "Restoring" { $percentComplete = 20 }
                    "Waiting" { $percentComplete = 30 }
                }
                Write-Progress -Activity $activity -status $status -percentComplete $percentComplete
                Start-Sleep -Seconds 5
            }
            Write-Progress -Activity $Result.currentStep.phaseText -status $Result.currentStep.operationText -percentComplete 100
            Start-Sleep -Seconds 1
        }
        Write-Output $Result
    }
}

<#
    .SYNOPSIS
    Get OCI Backup
    .DESCRIPTION
    Get OCI Backup
#>

function Global:Get-OciBackup {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                   Position=0,
                   HelpMessage="Path where to store OnCommand Insight Backup.")][Alias("FilePath")][PSObject]$Path,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="Time in minutes to wait for backup to complete (Default = 60 minutes).")][PSObject]$Timeout=60,
        [parameter(Mandatory=$False,
                   Position=2,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $URI = $Server.BaseUri + "/rest/v1/admin/backups/current"

        Write-Host "Starting Backup"
        $Job = Start-Job {
            add-type @"
                    using System.Net;
                    using System.Security.Cryptography.X509Certificates;
                    public class TrustAllCertsPolicy : ICertificatePolicy {
                       public bool CheckValidationResult(
                            ServicePoint srvPoint, X509Certificate certificate,
                            WebRequest request, int certificateProblem) {
                            return true;
                        }
                    }
"@


            [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

            Write-Verbose "Test"
            Write-Verbose $args[0]
            Write-Verbose $args[1]

            Invoke-RestMethod -WebSession $Server.Session -TimeoutSec ([int32]::MaxValue) -Method POST -Uri $args[0] -Headers $args[1] -Verbose
        } -ArgumentList $URI,$Server.Headers

        Start-Sleep -Seconds 5

        try {
            Write-Progress -Activity "Backup started" -status "Backing up" -percentComplete 0
            $i = 0
            while ($true) {
                $i++
                $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
                if ($i -eq ($Timeout * 12) -or $Job.State -ne 'Running') {
                    Write-Progress -Activity "Backup did not complete in $Timeout minutes" -status "Backing failed" -percentComplete 100
                }
                if ($Result.status -eq 'SUCCESSFUL') {
                    Write-Progress -Activity $Result -status $Result -percentComplete 100
                    Start-Sleep -Seconds 1
                    break
                }
                Write-Progress -Activity "Backup started" -status $Result.status -percentComplete (100*$i/($Timeout*12))
                Start-Sleep -Seconds 5
            }
            $Uri = $($Server.BaseUri) + $Result.Url
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        $FilePath = $Path + '\' + (($Uri -split '/') | Select-Object -last 1)
        $Date = [datetime]::ParseExact($($FilePath -replace '.+_D(.*)_[0-9]+.zip','$1'),"yyyyMMdd_HHmm",$null)

        try {
            Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers -OutFile $FilePath
            Write-Host "Backup Saved to $FilePath"

            $Result = [PSCustomObject]@{FilePath=$FilePath;Date=$Date;URI=$Uri}

            Write-Output $Result
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }
    }
}

<#
    .SYNOPSIS
    Get OCI Backups
    .DESCRIPTION
    Get OCI Backups
#>

function Global:Get-OciBackups {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/backups"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers

            $Result = $Result | ForEach-Object { [PSCustomObject]@{FilePath=$_.path;Date=($_.date | get-date)} }

            Write-Output $Result
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }
    }
}

<#
    .SYNOPSIS
    Retrieve queries
    .DESCRIPTION
    Retrieve queries
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciQueries {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/queries"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # TODO: implement parsing
        $Queries = $Result
        Write-Output $Queries
    }
}

<#
    .SYNOPSIS
    Retrieve queries
    .DESCRIPTION
    Retrieve queries
    .PARAMETER id
    ID of query to retrieve
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciQuery {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="ID of query to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/queries/$id"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # TODO: implement parsing
        $Query = $Result
        Write-Output $Query
    }
}

<#
    .SYNOPSIS
    Delete query
    .DESCRIPTION
    Delete query
    .PARAMETER id
    ID of query to delete
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Delete-OciQuery {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="ID of query to delete",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/queries/$id"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method DELETE -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "DELETE to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # TODO: implement parsing
        $Query = $Result
        Write-Output $Query
    }
}

<#
    .SYNOPSIS
    Retrieve annotation rules
    .DESCRIPTION
    Retrieve annotation rules
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationRules {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$False,
                   Position=0,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/rules"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # TODO: implement parsing
        $Queries = $Result
        Write-Output $Queries
    }
}

<#
    .SYNOPSIS
    Retrieve queries
    .DESCRIPTION
    Retrieve queries
    .PARAMETER server
    OCI Server to connect to
#>

function Global:Get-OciAnnotationRule {
    [CmdletBinding()]

    PARAM (
        [parameter(Mandatory=$True,
                    Position=0,
                    HelpMessage="Id of query to retrieve",
                    ValueFromPipeline=$True,
                    ValueFromPipelineByPropertyName=$True)][Long[]]$id,
        [parameter(Mandatory=$False,
                   Position=1,
                   HelpMessage="OnCommand Insight Server.")]$Server=$CurrentOciServer
    )

    Begin {
        Write-Warning "This Cmdlet uses an undocumented API call which may change in the future. Thus this Cmdlet is marked as experimental!"
        $Result = $null
        if (!$Server) {
            throw "Server parameter not specified and no global OCI Server available. Run Connect-OciServer first!"
        }
    }

    Process {
        $Uri = $Server.BaseUri + "/rest/v1/admin/rules/$id"

        try {
            $Result = Invoke-RestMethod -WebSession $Server.Session -TimeoutSec $Server.Timeout -Method GET -Uri $Uri -Headers $Server.Headers
        }
        catch {
            $ResponseBody = ParseExceptionBody -Response $_.Exception.Response
            Write-Error "GET to $Uri failed with Exception $($_.Exception.Message) `n $responseBody"
        }

        if (([String]$Result).Trim().startsWith('{') -or ([String]$Result).toString().Trim().startsWith('[')) {
            $Result = ParseJsonString -json $Result.Trim()
        }

        # TODO: implement parsing
        $Query = $Result
        Write-Output $Query
    }
}

# SIG # Begin signature block
# MIIVAAYJKoZIhvcNAQcCoIIU8TCCFO0CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUKm2b4dkUWtoDa3KuPr7rEDao
# IQKggg/vMIIEmTCCA4GgAwIBAgIPFojwOSVeY45pFDkH5jMLMA0GCSqGSIb3DQEB
# BQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQg
# TGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNV
# BAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJG
# aXJzdC1PYmplY3QwHhcNMTUxMjMxMDAwMDAwWhcNMTkwNzA5MTg0MDM2WjCBhDEL
# MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
# BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKjAoBgNVBAMT
# IUNPTU9ETyBTSEEtMSBUaW1lIFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAOnpPd/XNwjJHjiyUlNCbSLxscQGBGue/YJ0UEN9
# xqC7H075AnEmse9D2IOMSPznD5d6muuc3qajDjscRBh1jnilF2n+SRik4rtcTv6O
# KlR6UPDV9syR55l51955lNeWM/4Og74iv2MWLKPdKBuvPavql9LxvwQQ5z1IRf0f
# aGXBf1mZacAiMQxibqdcZQEhsGPEIhgn7ub80gA9Ry6ouIZWXQTcExclbhzfRA8V
# zbfbpVd2Qm8AaIKZ0uPB3vCLlFdM7AiQIiHOIiuYDELmQpOUmJPv/QbZP7xbm1Q8
# ILHuatZHesWrgOkwmt7xpD9VTQoJNIp1KdJprZcPUL/4ygkCAwEAAaOB9DCB8TAf
# BgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQUjmstM2v0
# M6eTsxOapeAK9xI1aogwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny
# bC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDA1BggrBgEF
# BQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w
# DQYJKoZIhvcNAQEFBQADggEBALozJEBAjHzbWJ+zYJiy9cAx/usfblD2CuDk5oGt
# Joei3/2z2vRz8wD7KRuJGxU+22tSkyvErDmB1zxnV5o5NuAoCJrjOU+biQl/e8Vh
# f1mJMiUKaq4aPvCiJ6i2w7iH9xYESEE9XNjsn00gMQTZZaHtzWkHUxY93TYCCojr
# QOUGMAu4Fkvc77xVCf/GPhIudrPczkLv+XZX4bcKBUCYWJpdcRaTcYxlgepv84n3
# +3OttOe/2Y5vqgtPJfO44dXddZhogfiqwNGAwsTEOYnB9smebNd0+dmX+E/CmgrN
# Xo/4GengpZ/E8JIh5i15Jcki+cPwOoRXrToW9GOUEB1d0MYwggVqMIIEUqADAgEC
# AhEAsPVV6jnRNgfABcUA7um0CDANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJH
# QjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3Jk
# MRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJT
# QSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTcwNjI4MDAwMDAwWhcNMjAwNjI3MjM1OTU5
# WjCBqzELMAkGA1UEBhMCREUxDjAMBgNVBBEMBTg1NTUxMRwwGgYDVQQIDBNOb3Jk
# cmhlaW4tV2VzdGZhbGVuMRIwEAYDVQQHDAlLaXJjaGhlaW0xFjAUBgNVBAkMDVNv
# bm5lbmFsbGVlIDExIDAeBgNVBAoMF05ldEFwcCBEZXV0c2NobGFuZCBHbWJIMSAw
# HgYDVQQDDBdOZXRBcHAgRGV1dHNjaGxhbmQgR21iSDCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAKnyWe0IrmZ8r6hU9qhoH7pNv9HTv67xaWRFcmeQilAS
# F72E9oyFa65OTxdXoOpLD129692Rbaswbqy57P+qkj6MgBvTYFqBX9BZpnCOlCjw
# YGQVWTj34fSxUtzxKISRI4wjvYT212T0deqhpJ/Oy1BlDik7WNiNncVZRHD2RfbH
# qVZI37LaFGlSytG4z6VS7nUTGZLGay/IWEQIEwQ6AktWm696mSTKono680z7ZK2U
# OGFneQVKagfzOIqD5ZFvlZjvC6z5181/oSEFtn5MMp71HoNd4ABYOrzldFUy0CPI
# ruBB7yagUomtvLPFWux3OcA/pbJMK6EdAowrTQxxG1UCAwEAAaOCAbQwggGwMB8G
# A1UdIwQYMBaAFCmRYP+KTfrr+aZquM/55ku9Sc4SMB0GA1UdDgQWBBTChARqgCg3
# JCwDL3vvWQz8tzA8XjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNV
# HSUEDDAKBggrBgEFBQcDAzARBglghkgBhvhCAQEEBAMCBBAwRgYDVR0gBD8wPTA7
# BgwrBgEEAbIxAQIBAwIwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29t
# b2RvLm5ldC9DUFMwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9j
# YS5jb20vQ09NT0RPUlNBQ29kZVNpZ25pbmdDQS5jcmwwdAYIKwYBBQUHAQEEaDBm
# MD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FD
# b2RlU2lnbmluZ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2Rv
# Y2EuY29tMCUGA1UdEQQeMByBGmZsb3JpYW4uZmVsZGhhdXNAZ21haWwuY29tMA0G
# CSqGSIb3DQEBCwUAA4IBAQBPLYiedwvRO7FPhAkDLqCKNWwRgRWaP5fA6X/bYjcu
# eV2oAAaPGdhee5mZgpjqvzLDxLCZiLJ/Z9wCAhiK9C42Lgahbe7XOIM8NDV/MmGn
# Mo2Ba+X9KYmyVlRV6bQsNDpnW4t7mWkh4JpV2LZbLluSrJ88SAqCsrZb1C49H5m5
# YdwFZUSIL8P19MSCDxPr0OC/3qX0dFcSEBIIBKtKF3mm9/Yind3SgkxoPfxViX2D
# eK80uOmm2Gb7bOhSuzqjkvDG0INsF4zyTX4HldBJmQfKeQiD8RlF6DpUcm0AoChM
# qCLwiJOHaHHYOOS7Busif3LkvIKd+tWtrg5fw7gZ0fU3MIIF4DCCA8igAwIBAgIQ
# LnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UEBhMCR0Ix
# GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEa
# MBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0Eg
# Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5MDAwMDAwWhcNMjgwNTA4
# MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVz
# dGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRl
# ZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqG
# SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR3elnMRHrzB79MR2zuWJX
# P5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvthe4YJs+P9omidHCydv3Lj
# 5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3e9V5kAoUGFEs5v7BEvAc
# P2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQc5hc9IVKaw+A3V7Wvf2p
# L8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPiXzjbxghdR7ODQfAuADcU
# uRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmLAgaff9ULAgMBAAGjggFR
# MIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs2TIy1DAdBgNVHQ4EFgQU
# KZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQI
# MAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYDVR0gBAowCDAGBgRVHSAA
# MEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9E
# T1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEGCCsGAQUFBwEBBGUwYzA7
# BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQWRk
# VHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNv
# bTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4MbU2x8U6ST6/COCwEzMVj
# EasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQciGlEcOtTh6Qm/5iR0rx57
# FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHfWGshqknUfDdOvf+2dVRA
# GDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HITfK7ZU2o94VFB696aSdl
# kClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46BLqioXwfy2M6FafUFRun
# UkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gbqjSm/Iz13X9ljIwxVzHQ
# NuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm5LLY5TjCqO3GgZw1a6lY
# YUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQFhv/K53b0CDKieoofjKO
# Gd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5sL6iPDAZQ+4wns3bJ9ObX
# wzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55ZmjoIs2475iFTZYRPAmK
# 0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6Q++6Z2H/fUnguzB9XIDj
# 5hY5S6cxggR7MIIEdwIBATCBkjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
# YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
# RE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25pbmcg
# Q0ECEQCw9VXqOdE2B8AFxQDu6bQIMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEM
# MQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQB
# gjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBTWePzDSrBGsdDZ
# PUo3CYGnqvjNVDANBgkqhkiG9w0BAQEFAASCAQBpT+KqMoWygl982y5Db7QzRsra
# 5vYLX3Z1bii7TFDUmONBKT8N0tkWjYZ7WXDLU/0dZ0trAt1A/j0PrZhZdbCsf916
# qdTxkK8YvnpLjyAfBxvYdVscnKfASoaGJCpBiZiqrF4dqcz1m4CbZmTbodVjvNes
# q22YFn1dR0qKPvbru+3uqo+TSuHlXvcG/cSie4KGg1qf7sDmUBUUf6W7VKMq3UHm
# nruN1uDxdQFhmKGekVNnbGlXK5fngQFCiK5+azL64FrO1VBiF/tLk7jK8umZCkhB
# 6Y0ZNV8wvpT8GjTItWlkp/QgwFcELwL53WVxTqHCd7oPQFV64lNKrOp3AwAPoYIC
# QzCCAj8GCSqGSIb3DQEJBjGCAjAwggIsAgEBMIGpMIGVMQswCQYDVQQGEwJVUzEL
# MAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVU
# aGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
# dXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJGaXJzdC1PYmplY3QCDxaI8DklXmOO
# aRQ5B+YzCzAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc
# BgkqhkiG9w0BCQUxDxcNMTgxMjE4MTU0ODE4WjAjBgkqhkiG9w0BCQQxFgQUhI79
# eU9ivFWcGki958Tee+3VrWowDQYJKoZIhvcNAQEBBQAEggEA5OQ9Bxvs960MUope
# e/OTq+OOvO5VuWTWSqChU8R+K16XZE6h+liqmUbk71kUcq1p1qxIut06fhdLGIGC
# RSfRGFAWQevH7TaHqSeXPNObpouWxWe0ujI/BKKt61vN9NhU00hToe7/zwHan8zT
# fGxniHF19QcUSYEhTthnO6v4c/7f+OvjkwdVaFuxP2aN/OGX1UuUjRdqMponLYGv
# yItUzgNT0kK6SXaxsrURGP/JP2FmufTu+ZVpOO3LbIvs2lPNhURup/rWW9PZOq7l
# 2tUd+qRy4D5ZLN7F3D6MGAkFX3kXuO2hMyADox6aAXejVEqXvhS4ogGimWgpqChP
# v5Budw==
# SIG # End signature block