IdentityCommand.CEM.psm1

# .ExternalHelp IdentityCommand.CEM-help.xml
function Find-CEMWorkspaceDelegation {
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('AWS', 'AZURE', 'GCP')]
        [String[]]$cloud_platforms,

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

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('account', 'root', 'ou', 'directory', 'management_group', 'subscription', 'gcp_organization', 'folder', 'project')]
        [String[]]$workspace_types,

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

        [parameter(
            Mandatory = $false,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateLength(3, [int]::MaxValue)]
        [String]$searchString,

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

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/delegations/workspace/search"

        $Filters = $PSBoundParameters | Get-Parameter -ParametersToKeep cloud_platforms, workspace_names, workspace_types, owners

        $body = $PSBoundParameters | Get-Parameter -ParametersToRemove cloud_platforms, workspace_names, workspace_types, owners

        if ($Filters.Keys.Count -gt 0) {
            $body['filters'] = $Filters
        }

        $body['offset'] = 0
        if (-not $PSBoundParameters.ContainsKey('limit')) { $body['limit'] = 50 }

        $result = Invoke-IDRestMethod -Uri $URI -Method POST -Body ($body | ConvertTo-Json -Depth 4)

        if ($null -ne $result) {

            Get-PagedResult -InitialResult $result -URI $URI -Style Offset -ResultProperty items `
                -TotalResponseKey count -OffsetRequestKey offset -Method POST -BodyTemplate $body

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function Get-CEMModuleData {

    [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.CEM-help.xml
function Get-CEMWorkspaceDelegation {
    [CmdletBinding()]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('AWS', 'AZURE', 'GCP')]
        [String]$cloud_platform,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [String]$workspace_id,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('account', 'root', 'ou', 'directory', 'management_group', 'subscription', 'gcp_organization', 'folder', 'project')]
        [String]$workspace_type
    )

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/delegations/workspace/details"

        $body = $PSBoundParameters | Get-Parameter

        #Fetching delegation details is a read - the API models it as a POST because the lookup key
        #is a compound object, not because anything changes.
        $result = Invoke-IDRestMethod -Uri $URI -Method POST -Body ($body | ConvertTo-Json -Depth 4)

        if ($null -ne $result) {

            $result

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function New-CEMDelegateDefinition {
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Function builds a definition object and does not change state')]
    [CmdletBinding()]
    [OutputType('IdCmd.CEM.Definition.Delegate')]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('User', 'Role')]
        [String]$entity_type,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [String]$entity_name,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [String]$user_principal,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('workspace_admin', 'business_owner')]
        [String[]]$tags,

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

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

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

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

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

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

        [parameter(Mandatory = $false)]
        [psobject[]]$DelegateDefinition
    )

    begin { }#begin

    process {

        $Delegate = $PSBoundParameters | Get-Parameter -ParametersToRemove DelegateDefinition

        $Output = @($DelegateDefinition) + @([pscustomobject]$Delegate) | Where-Object { $null -ne $_ }

        $Output | Add-CustomType -Type 'IdCmd.CEM.Definition.Delegate'

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function New-CEMWorkspaceDefinition {
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Function builds a definition object and does not change state')]
    [CmdletBinding()]
    [OutputType('IdCmd.CEM.Definition.Workspace')]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [String]$organization,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('account', 'root', 'ou', 'directory', 'management_group', 'subscription', 'gcp_organization', 'folder', 'project')]
        [String]$workspace_type,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateNotNullOrEmpty()]
        [String]$workspace_id,

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

        [parameter(Mandatory = $false)]
        [psobject[]]$WorkspaceDefinition
    )

    begin { }#begin

    process {

        $Workspace = $PSBoundParameters | Get-Parameter -ParametersToRemove WorkspaceDefinition

        $Output = @($WorkspaceDefinition) + @([pscustomobject]$Workspace) | Where-Object { $null -ne $_ }

        $Output | Add-CustomType -Type 'IdCmd.CEM.Definition.Workspace'

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function New-CEMWorkspaceDelegation {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateSet('AWS', 'AZURE', 'GCP')]
        [String]$cloud_platform,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateCount(1, 5)]
        [psobject[]]$WorkspaceDefinition,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateCount(1, 10)]
        [psobject[]]$DelegateDefinition
    )

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/delegations/workspace/$cloud_platform"

        $body = [ordered]@{
            workspaces = @($WorkspaceDefinition)
            entities   = @($DelegateDefinition)
        }

        if ($PSCmdlet.ShouldProcess($cloud_platform, 'Add workspace delegation')) {

            #The response carries no body - the created delegation's id is not returned here, only
            #from a later Find-CEMWorkspaceDelegation or Get-CEMWorkspaceDelegation lookup.
            Invoke-IDRestMethod -Uri $URI -Method POST -Body ($body | ConvertTo-Json -Depth 8)

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function Remove-CEMWorkspaceDelegation {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateRange(1, [int]::MaxValue)]
        [int]$id
    )

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/delegations/workspace/delegation/$id"

        #Deletes every delegate from every workspace the delegation covers - there is no partial
        #removal, only deleting the whole delegation.
        if ($PSCmdlet.ShouldProcess($id, 'Remove workspace delegation')) {

            Invoke-IDRestMethod -Uri $URI -Method DELETE

        }

    }#process

    end { }#end

}

# .ExternalHelp IdentityCommand.CEM-help.xml
function Set-CEMWorkspaceDelegation {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateRange(1, [int]::MaxValue)]
        [int]$id,

        [parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $true
        )]
        [ValidateCount(1, 10)]
        [psobject[]]$DelegateDefinition
    )

    begin { }#begin

    process {

        $URI = "$(Resolve-RequestUrl)/api/delegations/workspace/update/$id"

        #Fully replaces the delegates on every workspace the delegation covers - the workspaces
        #themselves are not part of this request and are left as they are.
        $body = [ordered]@{
            entities = @($DelegateDefinition)
        }

        if ($PSCmdlet.ShouldProcess($id, 'Update workspace delegation')) {

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

        }

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

#Delegation ids are only known once a search has been run - offer them from the most recent
#Find-CEMWorkspaceDelegation results, labelled by workspace name.
Register-ArgumentCompleter -ParameterName 'id' -ScriptBlock (
    Get-ArgumentCompleter -RetrievalCommand 'Find-CEMWorkspaceDelegation' -ValueProperty 'id' -LabelProperty 'workspace_name'
) -CommandName 'Set-CEMWorkspaceDelegation', 'Remove-CEMWorkspaceDelegation'

#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

#Platform discovery key and endpoint of the service, used to resolve the service URL from the IdentityCommand session.
#Cloud Visibility is served from the tenant-scoped bootstrap URL (<subdomain>-cem.cyberark.cloud), not the regional api URL.
New-Variable -Name ServiceKey -Value 'cem' -Scope Script -Force
New-Variable -Name ServiceEndpoint -Value 'bootstrap' -Scope Script -Force