IdentityCommand.RemoteAccess.psm1

function ConvertTo-RAEpochMillisecond {
    <#
    .SYNOPSIS
    Converts a [datetime] to milliseconds since the Unix epoch.
 
    .DESCRIPTION
    Every Remote Access timestamp (accessStartDate, fromTime, invitationExpirationTime, etc) is
    documented as an int64 count of milliseconds since Epoch, not an ISO 8601 string. Commands accept
    a native [datetime] parameter and convert it to this shape at the API boundary via this helper.
 
    .PARAMETER DateTime
    The date/time to convert.
 
    .EXAMPLE
    ConvertTo-RAEpochMillisecond -DateTime (Get-Date)
    #>

    [CmdletBinding()]
    [OutputType([long])]
    param(
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [datetime]$DateTime
    )

    process {

        [long][System.DateTimeOffset]::new($DateTime.ToUniversalTime()).ToUnixTimeMilliseconds()

    }

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Add-RATeamMember {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId,

        #The unique ID of the user to add to the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams/$([uri]::EscapeDataString($teamId))/members"

        $Body = $PSBoundParameters | Get-Parameter -ParametersToRemove teamId

        if ($PSCmdlet.ShouldProcess($teamId, "Add member '$userId'")) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Add-RAUserToTeam {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user. Will become a vendor manager when added to the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/teams/$([uri]::EscapeDataString($teamId))"

        if ($PSCmdlet.ShouldProcess($userId, "Add to team '$teamId' as vendor manager")) {

            Invoke-IDRestMethod -Uri $URI -Method POST

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Approve-RASelfServiceRequest {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the request.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$id,

        #Indicates whether the vendor's account is activated automatically or manually.
        [parameter(Mandatory = $true)]
        [ValidateSet('Activated', 'RequiresAdminConfirmation')]
        [String]$initialStatus,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $true)]
        [datetime]$accessStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $true)]
        [datetime]$accessEndDate,

        #Indicates whether the vendor can invite other vendors.
        [parameter(Mandatory = $true)]
        [bool]$canInvite,

        #The applications that the vendor can access through Remote Access, as objects with siteId/applicationId properties.
        [parameter(Mandatory = $true)]
        [Object[]]$applications,

        #Comments about the vendor, including the purpose of the invitation.
        [parameter(Mandatory = $false)]
        [String]$comments,

        #The provisioning type of the invitee.
        [parameter(Mandatory = $false)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$provisioningType,

        #The Vault user in the Idira PAM environment to be created for the vendor.
        [parameter(Mandatory = $false)]
        [String]$provisioningUsername,

        #The groups that the vendor is added to.
        [parameter(Mandatory = $false)]
        [String[]]$provisioningGroups,

        #The name of a predefined invitation template added to the vendor invitation.
        [parameter(Mandatory = $false)]
        [String]$customText,

        #The number of subvendors that the vendor can invite. 0 for unlimited.
        [parameter(Mandatory = $false)]
        [int]$maxNumOfInvitedVendors,

        #Indicates whether the vendor authenticates with an SMS code or phone call plus an emailed token, instead of scanning a QR code.
        [parameter(Mandatory = $false)]
        [bool]$phoneAndEmailAuth,

        #Indicates whether additional vendors invited by the vendor are activated automatically or manually.
        [parameter(Mandatory = $false)]
        [ValidateSet('Activated', 'RequiresAdminConfirmation')]
        [String]$invitedVendorsInitialStatus

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/selfServiceRequests/$([uri]::EscapeDataString($id))"

        $Body = $PSBoundParameters | Get-Parameter -ParametersToRemove id

        switch ($PSBoundParameters.Keys) {
            'accessStartDate' { $Body.accessStartDate = $accessStartDate | ConvertTo-RAEpochMillisecond }
            'accessEndDate' { $Body.accessEndDate = $accessEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($id, 'Approve self-service request')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Connect-RATenant {

    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'Re-securing a plaintext secret read from a service account file the caller already controls, for consistent in-memory handling with the ClientCredentials parameter set')]
    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ClientCredentials')]
    param(

        #The Remote Access datacenter hosting the tenant (alero.io, alero.eu, ca.alero.io, etc) -
        #forms both the token endpoint (auth.<datacenter>) and the API endpoint (api.<datacenter>).
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ClientCredentials')]
        [ValidateNotNullOrEmpty()]
        [String]$Datacenter,

        #The service account Client ID.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ClientCredentials')]
        [ValidateNotNullOrEmpty()]
        [String]$ClientID,

        #The service account Client Secret.
        [parameter(Mandatory = $true, ParameterSetName = 'ClientCredentials')]
        [ValidateNotNullOrEmpty()]
        [SecureString]$ClientSecret,

        #Path to a Remote Access service account JSON file (ClientID, ClientSecret, discoveryURI),
        #as issued from the Remote Access admin portal.
        [parameter(Mandatory = $true, ParameterSetName = 'ServiceAccountFile')]
        [ValidateNotNullOrEmpty()]
        [System.IO.FileInfo]$Path

    )

    begin { }#begin

    process {

        if ($PSCmdlet.ParameterSetName -eq 'ServiceAccountFile') {

            $ServiceAccount = Get-Content -Path $Path -Raw | ConvertFrom-Json

            $Datacenter = ($ServiceAccount.discoveryURI -split '/')[2] -replace '^auth\.', ''
            $ClientID = $ServiceAccount.ClientID
            $ClientSecret = ConvertTo-SecureString -String $ServiceAccount.ClientSecret -AsPlainText -Force

        }

        $TokenUrl = "https://auth.$Datacenter/auth/realms/serviceaccounts/protocol/openid-connect/token"

        if ($PSCmdlet.ShouldProcess($Datacenter, 'Authenticate Remote Access service account')) {

            $PlainClientSecret = ConvertTo-InsecureString -SecureString $ClientSecret

            $FormBody = -join (
                'grant_type=client_credentials',
                '&client_assertion_type=', [uri]::EscapeDataString('urn:ietf:params:oauth:client-assertion-type:jwt-bearer'),
                '&client_id=', [uri]::EscapeDataString($ClientID),
                '&client_secret=', [uri]::EscapeDataString($PlainClientSecret)
            )

            $TokenResponse = Invoke-IDRestMethod -Method POST -URI $TokenUrl -Body $FormBody -ContentType 'application/x-www-form-urlencoded'

            #Remote Access authenticates with its own service-account client-credentials flow, not the
            #CyberArk Identity bearer session every other companion module shares - building an
            #independent WebRequestSession here (rather than anything derived from Get-IDSession) keeps
            #this module's calls from ever mutating, or being mutated by, the shared Identity session.
            $WebSession = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
            $WebSession.Headers['Authorization'] = "Bearer $($TokenResponse.access_token)"

            $ISPSSSession.WebSession = $WebSession
            $ISPSSSession.tenant_url = "https://api.$Datacenter"
            $ISPSSSession.StartTime = Get-Date

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Deny-RASelfServiceRequest {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the request.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$id

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/selfServiceRequests/$([uri]::EscapeDataString($id))"

        if ($PSCmdlet.ShouldProcess($id, 'Reject self-service request')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAActivity {

    [CmdletBinding()]
    param(

        #The list of activity types to retrieve.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateSet(
            'ApplicationCreated', 'ApplicationDeleted', 'ApplicationUpdated', 'ApplicationEnabled',
            'ApplicationDisabled', 'ApplicationUserLogin', 'ConnectorCreated', 'ConnectorDeleted',
            'ConnectorInitializationExtended', 'ConnectorInitialized', 'ConnectorUpdated',
            'ConnectorLdapUpdated', 'ConnectorLdapInitialized', 'ConnectorLdapStopped',
            'GroupsCreated', 'GroupsDeleted', 'GroupsUpdated', 'SettingsUpdated', 'SiteCreated',
            'SiteDeleted', 'SiteUpdated', 'TenantAliasUpdated', 'TenantCreated', 'TenantLogin',
            'UserActivated', 'UserDeactivated', 'VendorActivated', 'VendorDeactivated',
            'VendorUpdated', 'UserDeleteFromTenant', 'VendorDeleteFromTenant', 'UserJoinTenant',
            'VendorJoinTenant', 'UserCreated', 'UserUpdated', 'UserRoleChanged',
            'ApplicationVendorLogin', 'AppCertificateCreated', 'AppCertificateDeleted',
            'AppCertificateUpdated', 'CompanyUserInvitationCreate', 'VendorInvitationCreate',
            'ServiceAccountCreated', 'ServiceAccountDeleted', 'ServiceAccountActivated',
            'ServiceAccountDeactivated', 'ApplicationLoginBlocked', 'DirectAccessUserResponse',
            'DirectAccessConnectionDenied', 'OfflineAccessUserViewedPassword', 'IdaptiveVendorSync',
            'IdaptiveRoleSync', 'CompanyInviterUpdated'
        )]
        [String[]]$activityTypes,

        #The start of the time range filter.
        [parameter(Mandatory = $false)]
        [datetime]$fromTime,

        #The end of the time range filter.
        [parameter(Mandatory = $false)]
        [datetime]$toTime,

        #The number of entries to skip.
        [parameter(Mandatory = $false)]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false)]
        [int]$limit

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/activities"

        $boundparameters = $PSBoundParameters | Get-Parameter

        switch ($PSBoundParameters.Keys) {
            'fromTime' { $boundparameters.fromTime = $fromTime | ConvertTo-RAEpochMillisecond }
            'toTime' { $boundparameters.toTime = $toTime | ConvertTo-RAEpochMillisecond }
        }

        $URI = Add-QueryString -URI $URI -Parameter $boundparameters
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'activities'
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAApplication {

    [CmdletBinding()]
    param(

        #The unique ID of the site.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$siteId,

        #The number of entries to skip.
        [parameter(Mandatory = $false)]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false)]
        [int]$limit

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/sites/$([uri]::EscapeDataString($siteId))/applications"

        $boundparameters = $PSBoundParameters | Get-Parameter -ParametersToRemove 'siteId'
        $URI = Add-QueryString -URI $URI -Parameter $boundparameters
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'applications'
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAConnector {

    [CmdletBinding()]
    param(

        #The unique ID of the site.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$siteId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/connectors/$([uri]::EscapeDataString($siteId))"

        #No offset/limit query parameters are documented for this endpoint - a single call returns
        #every connector for the site.
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            $result.connectors
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAGroup {

    [CmdletBinding(DefaultParameterSetName = 'List')]
    param(

        #The unique ID of the VendorLDAP group.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$groupId,

        #The string to use in the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchString,

        #The field in which to perform the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchIn,

        #The number of entries to skip.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$limit

    )

    begin { }#begin

    process {

        switch ($PSCmdlet.ParameterSetName) {

            'ById' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/groups/$([uri]::EscapeDataString($groupId))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'List' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/groups"
                $boundparameters = $PSBoundParameters | Get-Parameter
                $URI = Add-QueryString -URI $URI -Parameter $boundparameters
                $result = Invoke-IDRestMethod -Uri $URI -Method GET

                if ($null -ne $result) {
                    Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'groups'
                }

            }

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAModuleData {

    [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

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RASelfServiceRequest {

    [CmdletBinding()]
    param(

        #The string to use in the search.
        [parameter(Mandatory = $false)]
        [String]$searchString,

        #The field in which to perform the search.
        [parameter(Mandatory = $false)]
        [String]$searchIn,

        #The start of the time range filter.
        [parameter(Mandatory = $false)]
        [datetime]$fromTime,

        #The end of the time range filter.
        [parameter(Mandatory = $false)]
        [datetime]$toTime,

        #The number of entries to skip.
        [parameter(Mandatory = $false)]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false)]
        [int]$limit

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/selfServiceRequests/"

        $boundparameters = $PSBoundParameters | Get-Parameter

        switch ($PSBoundParameters.Keys) {
            'fromTime' { $boundparameters.fromTime = $fromTime | ConvertTo-RAEpochMillisecond }
            'toTime' { $boundparameters.toTime = $toTime | ConvertTo-RAEpochMillisecond }
        }

        $URI = Add-QueryString -URI $URI -Parameter $boundparameters
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'requests'
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RASite {

    [CmdletBinding()]
    param(

        #The number of entries to skip.
        [parameter(Mandatory = $false)]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false)]
        [int]$limit

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/sites"

        $boundparameters = $PSBoundParameters | Get-Parameter
        $URI = Add-QueryString -URI $URI -Parameter $boundparameters
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'sites'
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RATeam {

    [CmdletBinding(DefaultParameterSetName = 'List')]
    param(

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$teamId,

        #Search string to filter teams by name.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchString,

        #The number of entries to skip.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$limit,

        #Field to sort by.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [ValidateSet('NAME', 'INVITED_AT', 'INVITED_BY_NAME')]
        [String]$sortBy,

        #Sort direction.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [ValidateSet('ASC', 'DESC')]
        [String]$sortDirection

    )

    begin { }#begin

    process {

        switch ($PSCmdlet.ParameterSetName) {

            'ById' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams/$([uri]::EscapeDataString($teamId))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'List' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams"
                $boundparameters = $PSBoundParameters | Get-Parameter
                $URI = Add-QueryString -URI $URI -Parameter $boundparameters
                $result = Invoke-IDRestMethod -Uri $URI -Method GET

                if ($null -ne $result) {
                    Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'teams'
                }

            }

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RATeamMember {

    [CmdletBinding()]
    param(

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId,

        #Search string to filter members by name.
        [parameter(Mandatory = $false)]
        [String]$searchString,

        #The number of entries to skip.
        [parameter(Mandatory = $false)]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false)]
        [int]$limit,

        #Field to sort by.
        [parameter(Mandatory = $false)]
        [ValidateSet('FULLNAME')]
        [String]$sortBy,

        #Sort direction.
        [parameter(Mandatory = $false)]
        [ValidateSet('ASC', 'DESC')]
        [String]$sortDirection

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams/$([uri]::EscapeDataString($teamId))/members"

        $boundparameters = $PSBoundParameters | Get-Parameter -ParametersToRemove 'teamId'
        $URI = Add-QueryString -URI $URI -Parameter $boundparameters
        $result = Invoke-IDRestMethod -Uri $URI -Method GET

        if ($null -ne $result) {
            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'members'
        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAUser {

    [CmdletBinding(DefaultParameterSetName = 'List')]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The name of the user to include in the returned list, or part of the name.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$name,

        #The number of entries to skip.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$limit

    )

    begin { }#begin

    process {

        switch ($PSCmdlet.ParameterSetName) {

            'ById' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'List' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/"
                $boundparameters = $PSBoundParameters | Get-Parameter
                $URI = Add-QueryString -URI $URI -Parameter $boundparameters
                $result = Invoke-IDRestMethod -Uri $URI -Method GET

                if ($null -ne $result) {
                    Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'users'
                }

            }

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAUserTeam {

    [CmdletBinding()]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/teams"

        #Response is a bare array (maxItems 500), with no offset/limit query parameters documented.
        Invoke-IDRestMethod -Uri $URI -Method GET

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAVendor {

    [CmdletBinding(DefaultParameterSetName = 'List')]
    param(

        #The unique ID of the vendor.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$vendorId,

        #The phone number that the vendor set when they registered for Remote Access, in international format.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByPhone')]
        [ValidateNotNullOrEmpty()]
        [String]$phoneNumber,

        #The ID of the Remote Access user who invited the vendor.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$invitedBy,

        #The string to use in the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchString,

        #The field in which to perform the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchIn,

        #The number of entries to skip.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$limit

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/vendors"

        switch ($PSCmdlet.ParameterSetName) {

            'ById' {

                $URI = "$URI/$([uri]::EscapeDataString($vendorId))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'ByPhone' {

                $URI = "$URI/phone/$([uri]::EscapeDataString($phoneNumber))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'List' {

                $boundparameters = $PSBoundParameters | Get-Parameter
                $URI = Add-QueryString -URI $URI -Parameter $boundparameters
                $result = Invoke-IDRestMethod -Uri $URI -Method GET

                if ($null -ne $result) {
                    Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'vendors'
                }

            }

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Get-RAVendorInvitation {

    [CmdletBinding(DefaultParameterSetName = 'List')]
    param(

        #The unique ID of the vendor invitation.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$invitationId,

        #The ID of the Remote Access user who created the invitation.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$createdBy,

        #The string to use in the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchString,

        #The field in which to perform the search.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [String]$searchIn,

        #The number of entries to skip.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$offset,

        #The maximum number of entries to return.
        [parameter(Mandatory = $false, ParameterSetName = 'List')]
        [int]$limit

    )

    begin { }#begin

    process {

        switch ($PSCmdlet.ParameterSetName) {

            'ById' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/invitations/vendor-invitations/$([uri]::EscapeDataString($invitationId))"
                Invoke-IDRestMethod -Uri $URI -Method GET

            }

            'List' {

                $URI = "$($ISPSSSession.tenant_url)/v2-edge/invitations/vendor-invitations/"
                $boundparameters = $PSBoundParameters | Get-Parameter
                $URI = Add-QueryString -URI $URI -Parameter $boundparameters
                $result = Invoke-IDRestMethod -Uri $URI -Method GET

                if ($null -ne $result) {
                    Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty 'invitations'
                }

            }

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Grant-RAVendorManagerPermission {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user to delegate vendor manager permissions to.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodEndDate,

        #The account activation type.
        [parameter(Mandatory = $true)]
        [ValidateSet('AUTOMATIC', 'REQUIRES_ADMIN_CONFIRMATION', 'REQUIRES_INTERNAL_VENDOR_MANAGER_CONFIRMATION')]
        [String]$accountActivation,

        #A Vault user must be created to represent invited vendors in the Idira PAM environment.
        [parameter(Mandatory = $true)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$userProvisioning,

        #Indicates whether the vendor manager can invite vendors to web applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToWebApps,

        #Indicates whether the vendor manager can delegate permissions to other external vendor managers.
        [parameter(Mandatory = $true)]
        [bool]$canDelegatePermissionsToExternalVendorManagers,

        #Indicates whether the vendor manager can create groups.
        [parameter(Mandatory = $true)]
        [bool]$canCreateGroups,

        #Indicates whether the vendor manager can invite vendors to all groups.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllGroups,

        #Indicates whether the vendor manager can invite vendors to all applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllApps,

        #The applications that the vendor can access through Remote Access, as objects with id/siteId properties.
        [parameter(Mandatory = $false)]
        [Object[]]$allowedApps,

        #The number of vendors that the vendor manager can invite. 0 for unlimited.
        [parameter(Mandatory = $false)]
        [int]$maxInvitedVendors,

        #The groups that invited vendors should belong to.
        [parameter(Mandatory = $false)]
        [String[]]$userGroups,

        #The identity roles that invited vendors should have.
        [parameter(Mandatory = $false)]
        [String[]]$idaptiveRoles,

        #The Vault user in the Idira PAM environment to be created for the vendor.
        [parameter(Mandatory = $false)]
        [String]$provisioningUsername,

        #Allowed email domains for invited vendors.
        [parameter(Mandatory = $false)]
        [String[]]$allowedEmailDomains

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/vendor-manager-permission"

        $Body = $PSBoundParameters | Get-Parameter -ParametersToRemove userId

        switch ($PSBoundParameters.Keys) {
            'accessPeriodStartDate' { $Body.accessPeriodStartDate = $accessPeriodStartDate | ConvertTo-RAEpochMillisecond }
            'accessPeriodEndDate' { $Body.accessPeriodEndDate = $accessPeriodEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($userId, 'Delegate internal vendor manager permissions')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function New-RAGroup {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The name of the VendorLDAP group to be added as a member to PAM Safes.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$name,

        #The description of the VendorLDAP group.
        [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [String]$description

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/groups"

        $Body = $PSBoundParameters | Get-Parameter

        if ($PSCmdlet.ShouldProcess($name, 'Create group')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function New-RATeam {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The name of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$name,

        #An optional description for the team.
        [parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)]
        [String]$description,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodEndDate,

        #The account activation type.
        [parameter(Mandatory = $true)]
        [ValidateSet('AUTOMATIC', 'REQUIRES_ADMIN_CONFIRMATION', 'REQUIRES_INTERNAL_VENDOR_MANAGER_CONFIRMATION')]
        [String]$accountActivation,

        #A Vault user must be created to represent invited vendors in the Idira PAM environment.
        [parameter(Mandatory = $true)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$userProvisioning,

        #Indicates whether the vendor manager can invite vendors to web applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToWebApps,

        #Indicates whether the vendor manager can delegate permissions to other external vendor managers.
        [parameter(Mandatory = $true)]
        [bool]$canDelegatePermissionsToExternalVendorManagers,

        #Indicates whether the vendor manager can create groups.
        [parameter(Mandatory = $true)]
        [bool]$canCreateGroups,

        #Indicates whether the vendor manager can invite vendors to all groups.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllGroups,

        #Indicates whether the vendor manager can invite vendors to all applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllApps,

        #The applications that the vendor can access through Remote Access, as objects with id/siteId properties.
        [parameter(Mandatory = $false)]
        [Object[]]$allowedApps,

        #The number of vendors that the vendor manager can invite. 0 for unlimited.
        [parameter(Mandatory = $false)]
        [int]$maxInvitedVendors,

        #The groups that invited vendors should belong to.
        [parameter(Mandatory = $false)]
        [String[]]$userGroups,

        #The identity roles that invited vendors should have.
        [parameter(Mandatory = $false)]
        [String[]]$idaptiveRoles,

        #The Vault user in the Idira PAM environment to be created for the vendor.
        [parameter(Mandatory = $false)]
        [String]$provisioningUsername,

        #Allowed email domains for invited vendors.
        [parameter(Mandatory = $false)]
        [String[]]$allowedEmailDomains

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams"

        $Body = $PSBoundParameters | Get-Parameter

        switch ($PSBoundParameters.Keys) {
            'accessPeriodStartDate' { $Body.accessPeriodStartDate = $accessPeriodStartDate | ConvertTo-RAEpochMillisecond }
            'accessPeriodEndDate' { $Body.accessPeriodEndDate = $accessPeriodEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($name, 'Create team')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function New-RAUserInvitation {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The users to invite, as objects with name/emailAddress properties.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Object[]]$usersToInvite,

        #The date and time when the invitation expires. After this time, invited users can no longer accept it.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [datetime]$invitationExpirationTime,

        #The initial activation status for users created from the invitation. The only supported value is Deactivated.
        [parameter(Mandatory = $false)]
        [ValidateSet('Deactivated', 'Activated')]
        [String]$initialStatus

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/invitations/user-invitations"

        $Body = $PSBoundParameters | Get-Parameter
        $Body.invitationExpirationTime = $invitationExpirationTime | ConvertTo-RAEpochMillisecond

        if ($PSCmdlet.ShouldProcess(($usersToInvite | ForEach-Object { $_.emailAddress }) -join ', ', 'Create user invitation')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function New-RAVendorInvitation {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The name of the company that the user represents as a Remote Access user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$companyName,

        #The user's email address in the company they represent.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$emailAddress,

        #The vendor's first name.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$firstName,

        #The vendor's last name.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$lastName,

        #The phone number that the user set when they registered for Remote Access, in international format.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$phoneNumber,

        #Indicates whether the vendor's account is activated automatically or manually.
        [parameter(Mandatory = $true)]
        [ValidateSet('Activated', 'RequiresAdminConfirmation')]
        [String]$initialStatus,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $true)]
        [datetime]$accessStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $true)]
        [datetime]$accessEndDate,

        #Indicates whether the vendor can invite other vendors.
        [parameter(Mandatory = $true)]
        [bool]$canInvite,

        #The applications that the vendor can access through Remote Access, as objects with siteId/applicationId properties.
        [parameter(Mandatory = $true)]
        [Object[]]$applications,

        #Time-based access restrictions, as an object with timeZone/allowedDays/allDay/workingHoursStartSeconds/workingHoursEndSeconds properties.
        [parameter(Mandatory = $false)]
        [Object]$accessTimeDetails,

        #Comments about the vendor, including the purpose of the invitation.
        [parameter(Mandatory = $false)]
        [String]$comments,

        #The provisioning type of the invitee.
        [parameter(Mandatory = $false)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$provisioningType,

        #The Vault user in the Idira PAM environment to be created for the vendor.
        [parameter(Mandatory = $false)]
        [String]$provisioningUsername,

        #The groups that the vendor is added to.
        [parameter(Mandatory = $false)]
        [String[]]$provisioningGroups,

        #The identity roles that the vendor is added to.
        [parameter(Mandatory = $false)]
        [String[]]$idaptiveRoles,

        #The name of a predefined invitation template added to the vendor invitation.
        [parameter(Mandatory = $false)]
        [String]$customText,

        #The number of subvendors that the vendor can invite. 0 for unlimited.
        [parameter(Mandatory = $false)]
        [int]$maxNumOfInvitedVendors,

        #Indicates whether the vendor authenticates with an SMS code or phone call plus an emailed token, instead of scanning a QR code.
        [parameter(Mandatory = $false)]
        [bool]$phoneAndEmailAuth,

        #Indicates whether additional vendors invited by the vendor are activated automatically or manually.
        [parameter(Mandatory = $false)]
        [ValidateSet('Activated', 'RequiresAdminConfirmation')]
        [String]$invitedVendorsInitialStatus,

        #Indicates whether the vendor can access web applications.
        [parameter(Mandatory = $false)]
        [bool]$enableWebAppsAccess

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/invitations/vendor-invitations"

        $Body = $PSBoundParameters | Get-Parameter

        switch ($PSBoundParameters.Keys) {
            'accessStartDate' { $Body.accessStartDate = $accessStartDate | ConvertTo-RAEpochMillisecond }
            'accessEndDate' { $Body.accessEndDate = $accessEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($emailAddress, 'Create vendor invitation')) {

            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RAGroup {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the VendorLDAP group. Groups that contain members or pending invitations cannot be deleted.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$groupId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/groups/$([uri]::EscapeDataString($groupId))"

        if ($PSCmdlet.ShouldProcess($groupId, 'Delete group')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RATeam {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams/$([uri]::EscapeDataString($teamId))"

        if ($PSCmdlet.ShouldProcess($teamId, 'Delete team')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RATeamMember {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId,

        #The unique ID of the user to remove.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/teams/$([uri]::EscapeDataString($teamId))/members/$([uri]::EscapeDataString($userId))"

        if ($PSCmdlet.ShouldProcess($teamId, "Remove member '$userId'")) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RAUser {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))"

        if ($PSCmdlet.ShouldProcess($userId, 'Delete user')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RAUserFromTeam {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The unique ID of the team.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$teamId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/teams/$([uri]::EscapeDataString($teamId))"

        if ($PSCmdlet.ShouldProcess($userId, "Remove vendor manager from team '$teamId'")) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RAVendor {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the vendor.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$vendorId,

        #The phone number that the vendor set when they registered for Remote Access, in international format.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByPhone')]
        [ValidateNotNullOrEmpty()]
        [String]$phoneNumber

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/vendors"

        $URI = switch ($PSCmdlet.ParameterSetName) {
            'ById' { "$URI/$([uri]::EscapeDataString($vendorId))" }
            'ByPhone' { "$URI/phone/$([uri]::EscapeDataString($phoneNumber))" }
        }

        if ($PSCmdlet.ShouldProcess($(if ($vendorId) { $vendorId } else { $phoneNumber }), 'Delete vendor')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Remove-RAVendorInvitation {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the vendor invitation.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$invitationId

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/invitations/vendor-invitations/$([uri]::EscapeDataString($invitationId))"

        if ($PSCmdlet.ShouldProcess($invitationId, 'Delete vendor invitation')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAGroup {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the VendorLDAP group.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$groupId,

        #The description of the VendorLDAP group.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [String]$description

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/groups/$([uri]::EscapeDataString($groupId))"

        if ($PSCmdlet.ShouldProcess($groupId, 'Update group')) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($description | ConvertTo-Json)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAUserRole {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The user role.
        [parameter(Mandatory = $true)]
        [ValidateSet('TenantAdmin', 'User', 'VendorManager')]
        [String]$role

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/role"

        if ($PSCmdlet.ShouldProcess($userId, "Set user role: $role")) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($role | ConvertTo-Json)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAUserStatus {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The updated status of the user's account. PendingActivation is not allowed here.
        [parameter(Mandatory = $true)]
        [ValidateSet('Deactivated', 'Activated')]
        [String]$status

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/status"

        if ($PSCmdlet.ShouldProcess($userId, "Set user status: $status")) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($status | ConvertTo-Json)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAVendor {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the vendor.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ById')]
        [ValidateNotNullOrEmpty()]
        [String]$vendorId,

        #The phone number that the vendor set when they registered for Remote Access, in international format.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'ByPhone')]
        [ValidateNotNullOrEmpty()]
        [String]$phoneNumber,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $false)]
        [datetime]$accessStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $false)]
        [datetime]$accessEndDate,

        #Indicates whether the vendor can invite other vendors.
        [parameter(Mandatory = $false)]
        [bool]$canInvite,

        #Indicates whether additional vendors invited by the vendor are activated automatically or manually.
        [parameter(Mandatory = $false)]
        [ValidateSet('Activated', 'RequiresAdminConfirmation')]
        [String]$invitedVendorsInitialStatus,

        #The number of subvendors that the vendor can invite.
        [parameter(Mandatory = $false)]
        [int]$maxNumInvitedVendors,

        #The provisioning type of the invitee.
        [parameter(Mandatory = $false)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$provisioningType,

        #The Vault user in the Idira PAM environment for the vendor.
        [parameter(Mandatory = $false)]
        [String]$username,

        #The groups that the vendor belongs to.
        [parameter(Mandatory = $false)]
        [String[]]$groups,

        #The identity roles that the vendor is added to.
        [parameter(Mandatory = $false)]
        [String[]]$idaptiveRoles,

        #Comments about the vendor, including the purpose of the invitation.
        [parameter(Mandatory = $false)]
        [String]$comments,

        #The applications and sites to update, as objects with siteId/applicationId properties.
        [parameter(Mandatory = $false)]
        [Object[]]$applications,

        #Indicates whether the vendor can access web applications.
        [parameter(Mandatory = $false)]
        [bool]$pvwaApplications

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/vendors"

        $URI = switch ($PSCmdlet.ParameterSetName) {
            'ById' { "$URI/$([uri]::EscapeDataString($vendorId))" }
            'ByPhone' { "$URI/phone/$([uri]::EscapeDataString($phoneNumber))" }
        }

        $Body = $PSBoundParameters | Get-Parameter -ParametersToRemove vendorId, phoneNumber

        switch ($PSBoundParameters.Keys) {
            'accessStartDate' { $Body.accessStartDate = $accessStartDate | ConvertTo-RAEpochMillisecond }
            'accessEndDate' { $Body.accessEndDate = $accessEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($(if ($vendorId) { $vendorId } else { $phoneNumber }), 'Update vendor')) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAVendorManagerPermission {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the user.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$userId,

        #The date when the vendor's access to Remote Access begins.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodStartDate,

        #The date when the vendor's access to Remote Access ends.
        [parameter(Mandatory = $true)]
        [datetime]$accessPeriodEndDate,

        #The account activation type.
        [parameter(Mandatory = $true)]
        [ValidateSet('AUTOMATIC', 'REQUIRES_ADMIN_CONFIRMATION', 'REQUIRES_INTERNAL_VENDOR_MANAGER_CONFIRMATION')]
        [String]$accountActivation,

        #A Vault user must be created to represent invited vendors in the Idira PAM environment.
        [parameter(Mandatory = $true)]
        [ValidateSet('ProvisionedByAlero', 'ManagedByAdmin', 'None')]
        [String]$userProvisioning,

        #Indicates whether the vendor manager can invite vendors to web applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToWebApps,

        #Indicates whether the vendor manager can delegate permissions to other external vendor managers.
        [parameter(Mandatory = $true)]
        [bool]$canDelegatePermissionsToExternalVendorManagers,

        #Indicates whether the vendor manager can create groups.
        [parameter(Mandatory = $true)]
        [bool]$canCreateGroups,

        #Indicates whether the vendor manager can invite vendors to all groups.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllGroups,

        #Indicates whether the vendor manager can invite vendors to all applications.
        [parameter(Mandatory = $true)]
        [bool]$canInviteToAllApps,

        #The applications that the vendor can access through Remote Access, as objects with id/siteId properties.
        [parameter(Mandatory = $false)]
        [Object[]]$allowedApps,

        #The number of vendors that the vendor manager can invite. 0 for unlimited.
        [parameter(Mandatory = $false)]
        [int]$maxInvitedVendors,

        #The groups that invited vendors should belong to.
        [parameter(Mandatory = $false)]
        [String[]]$userGroups,

        #The identity roles that invited vendors should have.
        [parameter(Mandatory = $false)]
        [String[]]$idaptiveRoles,

        #The Vault user in the Idira PAM environment to be created for the vendor.
        [parameter(Mandatory = $false)]
        [String]$provisioningUsername,

        #Allowed email domains for invited vendors.
        [parameter(Mandatory = $false)]
        [String[]]$allowedEmailDomains

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/users/$([uri]::EscapeDataString($userId))/vendor-manager-permission"

        $Body = $PSBoundParameters | Get-Parameter -ParametersToRemove userId

        switch ($PSBoundParameters.Keys) {
            'accessPeriodStartDate' { $Body.accessPeriodStartDate = $accessPeriodStartDate | ConvertTo-RAEpochMillisecond }
            'accessPeriodEndDate' { $Body.accessPeriodEndDate = $accessPeriodEndDate | ConvertTo-RAEpochMillisecond }
        }

        if ($PSCmdlet.ShouldProcess($userId, 'Update internal vendor manager permissions')) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($Body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.RemoteAccess-help.xml
function Set-RAVendorStatus {

    [CmdletBinding(SupportsShouldProcess)]
    param(

        #The unique ID of the vendor.
        [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [String]$vendorId,

        #The updated status of the vendor's account. PendingActivation is not allowed here.
        [parameter(Mandatory = $true)]
        [ValidateSet('Activated', 'Deactivated')]
        [String]$status

    )

    begin { }#begin

    process {

        $URI = "$($ISPSSSession.tenant_url)/v2-edge/vendors/$([uri]::EscapeDataString($vendorId))/status"

        if ($PSCmdlet.ShouldProcess($vendorId, "Set vendor status: $status")) {

            Invoke-IDRestMethod -Uri $URI -Method PUT -Body ($status | ConvertTo-Json)

        }

    }#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

Register-ArgumentCompleter -ParameterName 'vendorId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RAVendor' -ValueProperty 'id' -LabelProperty 'fullName'
) -CommandName @(
    'Get-RAVendor'
    'Set-RAVendor'
    'Remove-RAVendor'
    'Set-RAVendorStatus'
)

Register-ArgumentCompleter -ParameterName 'userId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RAUser' -ValueProperty 'id' -LabelProperty 'username'
) -CommandName @(
    'Get-RAUser'
    'Remove-RAUser'
    'Set-RAUserStatus'
    'Set-RAUserRole'
    'Get-RAUserTeam'
    'Add-RAUserToTeam'
    'Remove-RAUserFromTeam'
    'Set-RAVendorManagerPermission'
    'Grant-RAVendorManagerPermission'
    'Add-RATeamMember'
    'Remove-RATeamMember'
)

Register-ArgumentCompleter -ParameterName 'groupId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RAGroup' -ValueProperty 'id' -LabelProperty 'name'
) -CommandName @(
    'Get-RAGroup'
    'Set-RAGroup'
    'Remove-RAGroup'
)

Register-ArgumentCompleter -ParameterName 'teamId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RATeam' -ValueProperty 'id' -LabelProperty 'name'
) -CommandName @(
    'Get-RATeam'
    'Remove-RATeam'
    'Get-RATeamMember'
    'Add-RATeamMember'
    'Remove-RATeamMember'
    'Add-RAUserToTeam'
    'Remove-RAUserFromTeam'
)

Register-ArgumentCompleter -ParameterName 'siteId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RASite' -ValueProperty 'id' -LabelProperty 'displayName'
) -CommandName @(
    'Get-RAApplication'
    'Get-RAConnector'
)

Register-ArgumentCompleter -ParameterName 'invitationId' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Get-RAVendorInvitation' -ValueProperty 'invitationId' -LabelProperty 'fullName'
) -CommandName @(
    'Get-RAVendorInvitation'
    'Remove-RAVendorInvitation'
)

#endregion

# Script scope session object for session data
$ISPSSSession = [ordered]@{
    tenant_url         = $null
    User               = $null
    TenantId           = $null
    SessionId          = $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