PublicAPI.ps1

class LogetoException : Exception {
    [string] $Code
    [System.Management.Automation.ErrorRecord] $InnerErrorRecord

    LogetoException($Code, $Message, $InnerErrorRecord) : base($Message) {
        $this.Code = $Code
        $this.InnerErrorRecord = $InnerErrorRecord
    }
}

function Get-LogetoEntity {
[CmdletBinding()]
Param (
    [Parameter(Mandatory=$true)] [string]$AccountName,
    [Parameter(Mandatory=$true)] [string]$AccessKey,
    [Parameter(Mandatory=$true)] [string]$Entity,
    $Params,
    [int]$RetryCount = 1,
    [int]$ApiVersion = 1,
    [switch]$PostAccountNameInHeader,
    [switch]$SingleSegment

)
    if (!$Params)
    {
        $Params = @{}
    }

    $headers = @{'SecurityToken' = "$($AccountName):$($AccessKey)"}

    $accountName = $AccountName.ToLower()

    $domain = "https://$($accountName).logeto.com"

    if ($PostAccountNameInHeader)
    {
        if ($accountName.StartsWith("systemart") -or $accountName.StartsWith("betadb"))
        {
            $domain = "https://beta.logeto.com"    
        }
        elseif ($accountName.StartsWith("alfadb"))
        {
            $domain = "https://alfa.logeto.com"    
        }
        else
        {
            $domain = "https://app.logeto.com" 
        }
    }
    else
    {
        $domain = "https://$($accountName).logeto.com"
    }

    $uriBuilder = [System.UriBuilder]::new("$($domain)/api/v$($ApiVersion)/$($Entity)")

    $items = $null

    $progressId = 1

    $waitTime = 2
    $maxWaitTime = 300

    do
    {
        Write-Progress -PercentComplete -1 -Status "Records downloaded $($items.Count)" -Activity "Retrieving records" -Id $progressId

        try
        {
            [System.Collections.ArrayList] $query = @()
            foreach ($param in $Params.GetEnumerator()) {
                $value =  $param.Value
                if ($value -is [DateTime])
                {
                    $value = $value.ToString("yyyy-MM-dd")
                }
                $key = [System.Net.WebUtility]::UrlEncode($param.Name)
                $value = [System.Net.WebUtility]::UrlEncode($value)
                $query.Add("${key}=${value}") | Out-Null
            }

            $uriBuilder.Query = ($query -join '&')
            $uri = $uriBuilder.ToString()

            while ($RetryCount -gt 0)
            {
                try
                {
                    $result = Invoke-RestMethod -Method Get -Uri $uri -ErrorVariable $errorResult -Headers $headers
                    break
                }
                catch [System.Net.WebException]
                {
                    if ((--$RetryCount) -eq 0)
                    {
                        throw
                    }
                    Start-Sleep -Seconds $waitTime
                    if ($waitTime -lt $maxWaitTime)
                    {
                        $waitTime = $waitTime * 2
                    }
                }
            }
        }
        catch
        {
            Write-Progress -Completed -Activity "Retrieving records failed" -Id $progressId
            if ($null -eq $_.Exception.Response)
            {
                throw
            }
            else
            {
                throw New-LogetoException
            }
        }

        if ($SingleSegment)
        {
            Write-Progress -Completed -Activity "Retrieving records" -Id $progressId
            return $result
        }

        if ($result.Items)
        {
            $items = $items + $result.Items
            Write-Progress -PercentComplete -1 -Status "Records downloaded $($items.Count)" -Activity "Retrieving records" -Id $progressId
        }

        if ($result.ContinuationToken)
        {
            $params["ContinuationToken"] = $result.ContinuationToken
        }
    } 
    while ($result -and $result.ContinuationToken)

    Write-Progress -Completed -Activity "Retrieving records" -Id $progressId

    return $items
}

function Set-LogetoEntity {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)] [string]$AccountName,
        [Parameter(Mandatory=$true)] [string]$AccessKey,
        [Parameter(Mandatory=$true)] [string]$Entity,
        $Params,
        $Data,
        [int]$RetryCount = 1,
        [int]$ApiVersion = 1,
        [switch]$PostAccountNameInHeader
    )

    if (!$Params)
    {
        $Params = @{}
    }

    $headers = @{
        'SecurityToken' = "$($AccountName):$($AccessKey)"
        'Content-Type' = "application/json"
    }

    $accountName = $AccountName.ToLower()

    $domain = "https://$($accountName).logeto.com"

    if ($PostAccountNameInHeader)
    {
        if ($accountName.StartsWith("systemart") -or $accountName.StartsWith("betadb"))
        {
            $domain = "https://beta.logeto.com"    
        }
        elseif ($accountName.StartsWith("alfadb"))
        {
            $domain = "https://alfa.logeto.com"    
        }
        else
        {
            $domain = "https://app.logeto.com" 
        }
    }
    else
    {
        $domain = "https://$($accountName).logeto.com"
    }
    
    $uriBuilder = [System.UriBuilder]::new("$($domain)/api/v$($ApiVersion)/$($Entity)")

    $waitTime = 2
    $maxWaitTime = 300

    try
    {
        [System.Collections.ArrayList] $query = @()
        foreach ($param in $Params.GetEnumerator()) {
            $value =  $param.Value
            if ($value -is [DateTime])
            {
                $value = $value.ToString("yyyy-MM-dd")
            }
            $key = [System.Net.WebUtility]::UrlEncode($param.Name)
            $value = [System.Net.WebUtility]::UrlEncode($value)
            $query.Add("${key}=${value}") | Out-Null
        }

        $uriBuilder.Query = ($query -join '&')
        $uri = $uriBuilder.ToString()

        $jsonBody = ($Data | ConvertTo-Json)

        while ($RetryCount -gt 0)
        {
            try
            {
                $result = Invoke-RestMethod -Method Post -Uri $uri -ErrorVariable $errorResult -ContentType "application/json; charset=utf-8" -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($jsonBody))
                break
            }
            catch [System.Net.WebException]
            {
                if ((--$RetryCount) -eq 0)
                {
                    throw
                }
                Start-Sleep -Seconds $waitTime
                if ($waitTime -lt $maxWaitTime)
                {
                    $waitTime = $waitTime * 2
                }
            }
        }
    }
    catch
    {
        if ($null -eq $_.Exception.Response)
        {
            throw
        }
        else
        {
            throw New-LogetoException
        }
    }

    return $result
}

function Edit-LogetoEntity {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)] [string]$AccountName,
        [Parameter(Mandatory=$true)] [string]$AccessKey,
        [Parameter(Mandatory=$true)] [string]$Entity,
        [Parameter(Mandatory=$true)] [Guid]$Guid,
        $Params,
        $Data,
        [int]$RetryCount = 1,
        [int]$ApiVersion = 1,
        [switch]$PostAccountNameInHeader
    )

    if (!$Params)
    {
        $Params = @{}
    }

    $headers = @{
        'SecurityToken' = "$($AccountName):$($AccessKey)"
        'Content-Type' = "application/json"
    }

    $accountName = $AccountName.ToLower()
    
    $domain = "https://$($accountName).logeto.com"

    if ($PostAccountNameInHeader)
    {
        if ($accountName.StartsWith("systemart") -or $accountName.StartsWith("betadb"))
        {
            $domain = "https://beta.logeto.com"    
        }
        elseif ($accountName.StartsWith("alfadb"))
        {
            $domain = "https://alfa.logeto.com"    
        }
        else
        {
            $domain = "https://app.logeto.com" 
        }
    }
    else
    {
        $domain = "https://$($accountName).logeto.com"
    }
    
    $uriBuilder = [System.UriBuilder]::new("$($domain)/api/v$($ApiVersion)/$($Entity)/$($Guid)")

    $waitTime = 2
    $maxWaitTime = 300

    try
    {
        [System.Collections.ArrayList] $query = @()
        foreach ($param in $Params.GetEnumerator()) {
            $value =  $param.Value
            if ($value -is [DateTime])
            {
                $value = $value.ToString("yyyy-MM-dd")
            }
            $key = [System.Net.WebUtility]::UrlEncode($param.Name)
            $value = [System.Net.WebUtility]::UrlEncode($value)
            $query.Add("${key}=${value}") | Out-Null
        }

        $uriBuilder.Query = ($query -join '&')
        $uri = $uriBuilder.ToString()

        $jsonBody = ($Data | ConvertTo-Json)

        while ($RetryCount -gt 0)
        {
            try
            {
                $result = Invoke-RestMethod -Method Patch -Uri $uri -ErrorVariable $errorResult -ContentType "application/json; charset=utf-8" -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($jsonBody))
                break
            }
            catch [System.Net.WebException]
            {
                if ((--$RetryCount) -eq 0)
                {
                    throw
                }
                Start-Sleep -Seconds $waitTime
                if ($waitTime -lt $maxWaitTime)
                {
                    $waitTime = $waitTime * 2
                }
            }
        }
    }
    catch
    {
        if ($null -eq $_.Exception.Response)
        {
            throw
        }
        else
        {
            throw New-LogetoException
        }
    }
    
    return $result
}

function Remove-LogetoEntity {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)] [string]$AccountName,
        [Parameter(Mandatory=$true)] [string]$AccessKey,
        [Parameter(Mandatory=$true)] [string]$Entity,
        [Parameter(Mandatory=$true)] [Guid]$Guid,
        [int]$RetryCount = 1,
        [int]$ApiVersion = 1,
        [switch]$PostAccountNameInHeader
    )

    $headers = @{
        'SecurityToken' = "$($AccountName):$($AccessKey)"
    }

    $accountName = $AccountName.ToLower()
    
    $domain = "https://$($accountName).logeto.com"

    if ($PostAccountNameInHeader)
    {
        if ($accountName.StartsWith("systemart") -or $accountName.StartsWith("betadb"))
        {
            $domain = "https://beta.logeto.com"    
        }
        elseif ($accountName.StartsWith("alfadb"))
        {
            $domain = "https://alfa.logeto.com"    
        }
        else
        {
            $domain = "https://app.logeto.com" 
        }
    }
    else
    {
        $domain = "https://$($accountName).logeto.com"
    }
    
    $uriBuilder = [System.UriBuilder]::new("$($domain)/api/v$($ApiVersion)/$($Entity)/$($Guid)")

    $waitTime = 2
    $maxWaitTime = 300

    try
    {
        $uri = $uriBuilder.ToString()
        while ($RetryCount -gt 0)
        {
            try
            {
                $result = Invoke-RestMethod -Method Delete -Uri $uri -ErrorVariable $errorResult -Headers $headers
                break
            }
            catch [System.Net.WebException]
            {
                if ((--$RetryCount) -eq 0)
                {
                    throw
                }
                Start-Sleep -Seconds $waitTime
                if ($waitTime -lt $maxWaitTime)
                {
                    $waitTime = $waitTime * 2
                }
            }
        }
    }
    catch
    {
        if ($null -eq $_.Exception.Response)
        {
            throw
        }
        else
        {
            throw New-LogetoException
        }
    }
    
    return $result
}

function ConvertTo-LogetoIndexedTable
{
[CmdletBinding()]
Param (
    [Parameter(Mandatory=$true, Position=0)][AllowNull()] $Items,
    [Parameter(Mandatory=$true)] $LookupProperty
)
    if(!$Items)
    {
        return $null
    }

    $result = @{}
    foreach ($item in $Items)
    {
        $result[$item.$LookupProperty] = $item    
    }
    return $result
}

function Get-LogetoFormatedError
{
[CmdletBinding()]
Param (
    [Parameter(Mandatory=$true)] $ErrorRecord
)
    $body = ""

    if ($ErrorRecord.Exception.Code)
    {
        $body += $ErrorRecord.Exception.Code + ": "
    }
    $body += $ErrorRecord.Exception.Message + "`n"

    if (!$ErrorRecord.Exception.InnerErrorRecord)
    {
        $body += $ErrorRecord.ScriptStackTrace + "`n"
    }
    else
    {
        $body += $ErrorRecord.Exception.InnerErrorRecord.ScriptStackTrace + "`n"
    }

    return $body
}

function New-LogetoException
{
    $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
    $streamReader.BaseStream.Position = 0
    $errorStruct = $streamReader.ReadToEnd() | ConvertFrom-Json
    $streamReader.Close()

    return [LogetoException]::new($errorStruct.Error.Code, $errorStruct.Error.Message, $_)
}