IdentityCommand.UserPortal.psm1

# .ExternalHelp IdentityCommand.UserPortal-help.xml
function Get-UPAsset {
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('vaulted', 'zsp')]
        [String]$accessMethod,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [switch]$favoritesOnly,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [switch]$recentsOnly,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateRange(1, 1000)]
        [int]$limit,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [String]$search,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [String]$sort
    )

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/assets"

        $boundparameters = $PSBoundParameters | Get-Parameter

        #Switches must travel as the true/false the API expects, not as the switch object
        foreach ($Switch in 'favoritesOnly', 'recentsOnly') {
            if ($boundparameters.ContainsKey($Switch)) {
                $boundparameters[$Switch] = $PSBoundParameters[$Switch].IsPresent
            }
        }

        $URI = Add-QueryString -URI $URI -Parameter $boundparameters

        #Send Request
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {

            #The API reports partial_success when it could not reach every source, and returns the
            #assets it did find - surface that rather than quietly handing back a short list.
            if (($null -ne $result.diagnostics) -and ($result.diagnostics.status -ne 'success')) {

                Write-Warning "Asset retrieval reported status '$($result.diagnostics.status)': the list may be incomplete"

            }

            $result.assets

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.UserPortal-help.xml
function Get-UPAssetSecret {
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [Alias('id')]
        [String]$assetId,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateLength(1, 3699)]
        [String]$reason,

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [psobject]$workflowStatus
    )

    begin { }#begin

    process {

        if (($workflowStatus.require_reason -eq $true) -and (-not $PSBoundParameters.ContainsKey('reason'))) {
            Write-Error -Message "Asset '$assetId' requires a reason: specify -reason" -Category InvalidArgument -TargetObject $assetId
            return
        }

        $URI = "$(Resolve-RequestUrl)/api/assets/$assetId/secret"

        #The endpoint is a POST which takes an optional reason for the retrieval, recorded in the audit
        $body = [ordered]@{}

        if ($PSBoundParameters.ContainsKey('reason')) {
            $body['reason'] = $reason
        }

        #Send Request
        $result = Invoke-IDRestMethod -Uri $URI -Method POST -Body ($body | ConvertTo-Json -Depth 2)

        if ($null -ne $result) {

            $result

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.UserPortal-help.xml
function Get-UPModuleData {

    [CmdletBinding()]
    param()

    begin { }#begin

    process {

        #Calculate the time elapsed since the start of the session and include in return data
        if ($null -ne $ISPSSSession.StartTime) {
            $ISPSSSession.ElapsedTime = '{0:HH:mm:ss}' -f ([datetime]$($(Get-Date) - $($ISPSSSession.StartTime)).Ticks)
        } else { $ISPSSSession.ElapsedTime = $null }

        #Deep Copy the $ISPSSSession session object and return as IdCmd Session type.
        Get-SessionClone -InputObject $ISPSSSession | Add-CustomType -Type IdCmd.Session

    }#process

    end { }#end

}

#Copy IdentityCommand's private helpers into this module: this module's functions call them, and
#the argument completer registrations below do so at import time.
#Each copy is created from the function definition, so it runs in this module's scope and uses this
#module's $ISPSSSession, whether IdentityCommand loaded from source or from its combined psm1.
#Resolve a single IdentityCommand module: with more than one version loaded, Get-Module returns
#an array.
$Module = Get-Module -Name IdentityCommand | Sort-Object Version -Descending | Select-Object -First 1

if ($null -eq $Module) {
    throw 'The IdentityCommand module is not loaded. Import IdentityCommand and try again.'
}

& $Module { Get-ChildItem -Path Function: } |

    Where-Object { $_.ModuleName -eq $Module.Name -and -not $Module.ExportedFunctions.ContainsKey($_.Name) } |

    ForEach-Object {

        . ([scriptblock]::Create("function $($_.Name) {$($_.Definition)}"))

    }

#region Registration

#Assets carry an address for infrastructure and a name for Identity applications, so label with
#whichever is populated rather than picking one and showing blanks for half the estate.
Register-ArgumentCompleter -ParameterName 'assetId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-UPAsset' -ValueProperty 'assetId' -LabelProperty 'address'
) -CommandName 'Get-UPAssetSecret'

#endregion Registration

# Script scope session object for session data
$ISPSSSession = [ordered]@{
    tenant_url         = $null
    User               = $null
    TenantId           = $null
    SessionId          = $null
    Subdomain          = $null
    WebSession         = $null
    StartTime          = $null
    ElapsedTime        = $null
    LastCommand        = $null
    LastCommandTime    = $null
    LastCommandResults = $null
    LastError          = $null
    LastErrorTime      = $null
} | Add-CustomType -Type IdCmd.Session

New-Variable -Name ISPSSSession -Value $ISPSSSession -Scope Script -Force

#Discovery key for Resolve-RequestUrl
New-Variable -Name ServiceKey -Value 'userportal' -Scope Script -Force

#Discovery endpoint for Resolve-RequestUrl
New-Variable -Name ServiceEndpoint -Value 'bootstrap' -Scope Script -Force