Public/real-time-response.ps1

function Confirm-FalconAdminCommand {
<#
.SYNOPSIS
Verify the status of a Real-time Response 'admin' command issued to a single-host session
.DESCRIPTION
Confirms the status of an executed 'admin' command. The single-host Real-time Response APIs require that commands
be confirmed to 'acknowledge' that they have been processed as part of your API-based workflow. Failing to confirm
after commands can lead to unexpected results.
 
A 'sequence_id' value of 0 is added if the parameter is not specified.
 
Requires 'Real Time Response (Admin): Write'.
.PARAMETER SequenceId
Sequence identifier
.PARAMETER CloudRequestId
Command request identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconAdminCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/admin-command/v1:get',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:get',Position=1)]
        [Alias('sequence_id')]
        [int32]$SequenceId,
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:get',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('cloud_request_id','task_id')]
        [string]$CloudRequestId
    )
    begin {
        if (!$PSBoundParameters.SequenceId) { $PSBoundParameters['SequenceId'] = 0 }
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('cloud_request_id','sequence_id') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Confirm-FalconCommand {
<#
.SYNOPSIS
Verify the status of a Real-time Response 'read-only' command issued to a single-host session
.DESCRIPTION
Confirms the status of an executed 'read-only' command. The single-host Real-time Response APIs require that
commands be confirmed to 'acknowledge' that they have been processed as part of your API-based workflow. Failing
to confirm after commands can lead to unexpected results.
 
A 'sequence_id' value of 0 is added if the parameter is not specified.
 
Requires 'Real Time Response: Read'.
.PARAMETER SequenceId
Sequence identifier
.PARAMETER CloudRequestId
Command request identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/command/v1:get',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:get',Position=1)]
        [Alias('sequence_id')]
        [int32]$SequenceId,
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:get',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('cloud_request_id','task_id')]
        [string]$CloudRequestId
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('cloud_request_id','sequence_id') }
        }
        if (!$PSBoundParameters.SequenceId) { $PSBoundParameters['sequence_id'] = 0 }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Confirm-FalconGetFile {
<#
.SYNOPSIS
Verify the status of a Real-time Response 'get' command
.DESCRIPTION
Requires 'Real Time Response: Write'.
.PARAMETER SessionId
Session identifier
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER BatchGetCmdReqId
Batch 'get' command identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconGetFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-get-command/v1:get',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/file/v2:get',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:get',Position=1)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:get',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_get_cmd_req_id')]
        [string]$BatchGetCmdReqId
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{ Query = @('session_id','batch_get_cmd_req_id','timeout') }
        }
    }
    process {
        # Verify 'Endpoint' using SessionId/BatchGetCmdReqId
        $Endpoint = if ($PSBoundParameters.SessionId) {
            '/real-time-response/entities/file/v2:get'
        } else {
            '/real-time-response/combined/batch-get-command/v1:get'
        }
        @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
            if ($BatchGetCmdReqId) {
                $_.PSObject.Properties | ForEach-Object {
                    # Append 'aid' and 'batch_get_cmd_req_id' to each host result and output
                    Set-Property $_.Value aid $_.Name
                    Set-Property $_.Value batch_get_cmd_req_id $BatchGetCmdReqId
                    $_.Value
                }
            } else {
                $_
            }
        }
    }
}
function Confirm-FalconResponderCommand {
<#
.SYNOPSIS
Verify the status of a Real-time Response 'active-responder' command issued to a single-host session
.DESCRIPTION
Confirms the status of an executed 'active-responder' command. The single-host Real-time Response APIs require
that commands be confirmed to 'acknowledge' that they have been processed as part of your API-based workflow.
Failing to confirm after commands can lead to unexpected results.
 
A 'sequence_id' value of 0 is added if the parameter is not specified.
 
Requires 'Real Time Response: Write'.
.PARAMETER SequenceId
Sequence identifier
.PARAMETER CloudRequestId
Command request identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconResponderCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/active-responder-command/v1:get',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:get',Position=1)]
        [Alias('sequence_id')]
        [int32]$SequenceId,
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:get',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('cloud_request_id','task_id')]
        [string]$CloudRequestId
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('cloud_request_id','sequence_id') }
        }
        if (!$PSBoundParameters.SequenceId) { $PSBoundParameters['sequence_id'] = 0 }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Edit-FalconScript {
<#
.SYNOPSIS
Modify a Real-time Response script
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Platform
Operating system platform
.PARAMETER PermissionType
Permission level [public: 'Administrators' and 'Active Responders', group: 'Administrators', private: creator]
.PARAMETER Name
Script name
.PARAMETER Description
Script description
.PARAMETER Comment
Audit log comment
.PARAMETER Path
Path to script file
.PARAMETER Id
Script identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconScript
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/scripts/v1:patch',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',
            ValueFromPipelineByPropertyName,Position=1)]
        [ValidateSet('windows','mac','linux',IgnoreCase=$false)]
        [string[]]$Platform,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',
            ValueFromPipelineByPropertyName,Position=2)]
        [ValidateSet('private','group','public',IgnoreCase=$false)]
        [Alias('permission_type')]
        [string]$PermissionType,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',
            ValueFromPipelineByPropertyName,Position=3)]
        [string]$Name,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',
            ValueFromPipelineByPropertyName,Position=4)]
        [string]$Description,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',
            ValueFromPipelineByPropertyName,Position=5)]
        [ValidateLength(1,4096)]
        [Alias('comments_for_audit_log')]
        [string]$Comment,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',Mandatory,
            ValueFromPipelineByPropertyName,Position=6)]
        [Alias('content','FullName')]
        [string]$Path,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:patch',Mandatory,
            ValueFromPipelineByPropertyName,Position=7)]
        [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')]
        [string]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Headers = @{ ContentType = 'multipart/form-data' }
            Format = @{
                Formdata = @('id','platform','permission_type','name','description','comments_for_audit_log',
                    'content')
            }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Get-FalconPutFile {
<#
.SYNOPSIS
Search for Real-time Response 'put' files
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Id
'Put' file identifier
.PARAMETER Filter
Falcon Query Language expression to limit results
.PARAMETER Sort
Property and direction to sort results
.PARAMETER Limit
Maximum number of results per request
.PARAMETER Offset
Position to begin retrieving results
.PARAMETER Detailed
Retrieve detailed information
.PARAMETER All
Repeat requests until all available results are retrieved
.PARAMETER Total
Display total result count instead of results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconPutFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/queries/put-files/v1:get',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v2:get',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')]
        [Alias('Ids')]
        [string[]]$Id,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get',Position=1)]
        [ValidateScript({ Test-FqlStatement $_ })]
        [string]$Filter,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get',Position=2)]
        [string]$Sort,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get',Position=3)]
        [ValidateRange(1,100)]
        [int32]$Limit,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get')]
        [int32]$Offset,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get')]
        [switch]$Detailed,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get')]
        [switch]$All,
        [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get')]
        [switch]$Total
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('sort','ids','offset','filter','limit') }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process {
        if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -Inputs $PSBoundParameters }
    }
    end {
        if ($List) {
            $PSBoundParameters['Id'] = @($List | Select-Object -Unique)
            Invoke-Falcon @Param -Inputs $PSBoundParameters
        }
    }
}
function Get-FalconScript {
<#
.SYNOPSIS
Search for custom Real-time Response scripts
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Id
Script identifier
.PARAMETER Filter
Falcon Query Language expression to limit results
.PARAMETER Sort
Property and direction to sort results
.PARAMETER Limit
Maximum number of results per request
.PARAMETER Offset
Position to begin retrieving results
.PARAMETER Detailed
Retrieve detailed information
.PARAMETER All
Repeat requests until all available results are retrieved
.PARAMETER Total
Display total result count instead of results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScript
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/queries/scripts/v1:get',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v2:get',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')]
        [Alias('Ids')]
        [string[]]$Id,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get',Position=1)]
        [ValidateScript({ Test-FqlStatement $_ })]
        [string]$Filter,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get',Position=2)]
        [string]$Sort,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get',Position=3)]
        [ValidateRange(1,100)]
        [int32]$Limit,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get')]
        [int32]$Offset,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get')]
        [switch]$Detailed,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get')]
        [switch]$All,
        [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get')]
        [switch]$Total
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('sort','ids','offset','filter','limit') }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process {
        if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -Inputs $PSBoundParameters }
    }
    end {
        if ($List) {
            $PSBoundParameters['Id'] = @($List | Select-Object -Unique)
            Invoke-Falcon @Param -Inputs $PSBoundParameters
        }
    }
}
function Get-FalconSession {
<#
.SYNOPSIS
Search for Real-time Response sessions
.DESCRIPTION
Real-time Response sessions are segmented by permission,meaning that only sessions that were created using
your OAuth2 API Client will be visible.
 
'Get-FalconQueue' can be used to find and export information about sessions in the 'offline queue'.
 
Requires 'Real Time Response: Read'.
.PARAMETER Id
Session identifier
.PARAMETER Filter
Falcon Query Language expression to limit results
.PARAMETER Sort
Property and direction to sort results
.PARAMETER Limit
Maximum number of results per request
.PARAMETER Offset
Position to begin retrieving results
.PARAMETER Queue
Restrict search to sessions that have been queued
.PARAMETER Detailed
Retrieve detailed information
.PARAMETER All
Repeat requests until all available results are retrieved
.PARAMETER Total
Display total result count instead of results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSession
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/queries/sessions/v1:get',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/queued-sessions/GET/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [Parameter(ParameterSetName='/real-time-response/entities/sessions/GET/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('Ids')]
        [string[]]$Id,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get',Position=1)]
        [ValidateScript({ Test-FqlStatement $_ })]
        [string]$Filter,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get',Position=2)]
        [string]$Sort,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get',Position=3)]
        [ValidateRange(1,100)]
        [int32]$Limit,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get')]
        [int32]$Offset,
        [Parameter(ParameterSetName='/real-time-response/entities/queued-sessions/GET/v1:post',Mandatory)]
        [switch]$Queue,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get')]
        [switch]$Detailed,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get')]
        [switch]$All,
        [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get')]
        [switch]$Total
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{
                Query = @('sort','offset','limit','filter')
                Body = @{ root = @('ids') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
    end {
        if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) }
        Invoke-Falcon @Param -Inputs $PSBoundParameters
    }
}
function Invoke-FalconAdminCommand {
<#
.SYNOPSIS
Issue a Real-time Response admin command to an existing single-host or batch session
.DESCRIPTION
Sessions can be started using 'Start-FalconSession'. A successfully created session will contain a 'session_id'
or 'batch_id' value which can be used with the '-SessionId' or '-BatchId' parameters.
 
The 'Wait' parameter will use 'Confirm-FalconAdminCommand' or 'Confirm-FalconGetFile' to check for command
results every 5 seconds for a total of 60 seconds.
 
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Command
Real-time Response command
.PARAMETER Argument
Arguments to include with the command
.PARAMETER OptionalHostId
Restrict execution to specific host identifiers
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostTimeout
Length of time to wait for a result from target host(s), in seconds
.PARAMETER SessionId
Session identifier
.PARAMETER BatchId
Batch session identifier
.PARAMETER Wait
Use 'Confirm-FalconAdminCommand' or 'Confirm-FalconGetFile' to retrieve command results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconAdminCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:post',Mandatory,Position=1)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Mandatory,
            Position=1)]
        [ValidateSet('cat','cd','clear','cp','csrutil','cswindiag','encrypt','env','eventlog backup',
            'eventlog export','eventlog list','eventlog view','filehash','get','getsid','help','history',
            'ifconfig','ipconfig','kill','ls','map','memdump','mkdir','mount','mv','netstat','ps','put',
            'put-and-run','reg delete','reg load','reg query','reg set','reg unload','restart','rm','run',
            'runscript','shutdown','umount','unmap','update history','update install','update list',
            'update install','users','xmemdump','zip',IgnoreCase=$false)]
        [Alias('base_command')]
        [string]$Command,
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:post',Position=2)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Position=2)]
        [Alias('Arguments')]
        [string]$Argument,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Position=3)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('optional_hosts','OptionalHostIds')]
        [string[]]$OptionalHostId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Position=4)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Position=5)]
        [ValidateRange(1,600)]
        [Alias('host_timeout_duration')]
        [int32]$HostTimeout,
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_id')]
        [string]$BatchId,
        [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:post')]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-admin-command/v1:post')]
        [switch]$Wait
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{
                Query = @('timeout','host_timeout_duration')
                Body = @{ root = @('session_id','base_command','command_string','optional_hosts','batch_id') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($OptionalHostId) { @($OptionalHostId).foreach{ $List.Add($_) }}}
    end {
        if ($PSBoundParameters.BatchId -and $PSBoundParameters.Command -eq 'get') {
            # Redirect to 'Invoke-FalconBatchGet' for multi-host 'get' requests
            $GetParam = @{
                FilePath = $PSBoundParameters.Argument
                BatchId = $PSBoundParameters.BatchId
                Wait = $PSBoundParameters.Wait
            }
            if ($Timeout) { $GetParam['Timeout'] = $PSBoundParameters.Timeout }
            if ($List) { $GetParam['OptionalHostId'] = @($List | Select-Object -Unique) }
            Invoke-FalconBatchGet @GetParam
        } else {
            # Verify 'Endpoint' using BatchId/SessionId
            [string]$Endpoint = if ($PSBoundParameters.BatchId) {
                if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) }
                '/real-time-response/combined/batch-admin-command/v1:post'
            } elseif ($PSBoundParameters.SessionId) {
                '/real-time-response/entities/admin-command/v1:post'
            }
            if ($Endpoint) {
                if ($PSBoundParameters.HostTimeout) {
                    # Add 's' to denote seconds for 'host_timeout_duration'
                    $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null
                }
                $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) {
                    # Join 'Command' and 'Argument' into 'command_string'
                    @($PSBoundParameters.Command,$PSBoundParameters.Argument) -join ' '
                    [void]$PSBoundParameters.Remove('Argument')
                } else {
                    $PSBoundParameters.Command
                }
                @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
                    if ($BatchId) {
                        # Add 'batch_id' to each result and output
                        Set-Property $_ batch_id $BatchId
                        $_
                    } elseif ($SessionId -and $Wait) {
                        for ($i = 0; $i -lt 60 -and $Result.Complete -ne $true -and !$Result.sha256; $i += 5) {
                            # Attempt to 'confirm' for 60 seconds
                            Start-Sleep 5
                            $Result = if ($Command -eq 'get') {
                                $_ | Confirm-FalconGetFile
                            } else {
                                $_ | Confirm-FalconAdminCommand
                            }
                        }
                        $Result
                    } else {
                        $_
                    }
                }
            }
        }
    }
}
function Invoke-FalconBatchGet {
<#
.SYNOPSIS
Issue a Real-time Response batch 'get' command to an existing batch session
.DESCRIPTION
When a 'get' command has been issued, the 'batch_get_cmd_req_id' property will be returned. That value is used
to verify the completion of the file transfer using 'Confirm-FalconBatchGet'.
 
The 'Wait' parameter will use 'Confirm-FalconGetFile' to check for command results every 5 seconds for a total
of 60 seconds.
 
Requires 'Real Time Response: Write'.
.PARAMETER FilePath
Path to file on target host
.PARAMETER OptionalHostId
Restrict execution to specific host identifiers
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostTimeout
Length of time to wait for a result from target host(s), in seconds
.PARAMETER BatchId
Batch session identifier
.PARAMETER Wait
Use 'Confirm-FalconGetFile' to attempt to retrieve results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconBatchGet
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-get-command/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post',Mandatory,Position=1)]
        [Alias('file_path')]
        [string]$FilePath,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post',Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('optional_hosts','OptionalHostIds')]
        [string[]]$OptionalHostId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post',Position=3)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post',Position=4)]
        [ValidateRange(1,600)]
        [Alias('host_timeout_duration')]
        [int32]$HostTimeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_id')]
        [string]$BatchId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post')]
        [switch]$Wait
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{
                Query = @('timeout','host_timeout_duration')
                Body = @{ root = @('batch_id','file_path','optional_hosts') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($OptionalHostId) { @($OptionalHostId).foreach{ $List.Add($_) }}}
    end {
        if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) }
        if ($PSBoundParameters.HostTimeout) {
            # Add 's' to denote seconds for 'host_timeout_duration'
            $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null
        }
        @(Invoke-Falcon @Param -Inputs $PSBoundParameters).foreach{
            if ($_.batch_get_cmd_req_id -and $_.combined.resources) {
                # Output result with 'batch_get_cmd_req_id' and 'hosts' values
                $BatchGetCmdReqId = $_.batch_get_cmd_req_id
                $Request = [PSCustomObject]@{
                    batch_get_cmd_req_id = $BatchGetCmdReqId
                    hosts = @($_.combined.resources.PSObject.Properties.Value).foreach{
                        # Append 'batch_get_cmd_req_id'
                        Set-Property $_ batch_get_cmd_req_id $BatchGetCmdReqId
                        $_
                    }
                }
                @($Request.hosts).Where({ $_.errors }).foreach{
                    # Write warning for hosts in batch that produced errors
                    $PSCmdlet.WriteWarning("[Invoke-FalconBatchGet] $(@($_.errors.code,
                        $_.errors.message) -join ': ') [aid: $($_.aid)]"
)
                }
                @($Request.hosts).Where({ $_.stderr }).foreach{
                    # Write warning for hosts in batch that produced 'stderr'
                    $PSCmdlet.WriteWarning("[Invoke-FalconBatchGet] $($_.stderr) [aid: $($_.aid)]")
                }
                if ($Wait) {
                    for ($i = 0; $i -lt 60 -and !$Result.sha256; $i += 5) {
                        # Attempt to 'confirm' for 60 seconds
                        Start-Sleep 5
                        $Result = $Request | Confirm-FalconGetFile
                    }
                    $Result
                } else {
                    $Request
                }
            } else {
                $_
            }
        }
    }
}
function Invoke-FalconCommand {
<#
.SYNOPSIS
Issue a Real-time Response read-only command to an existing single-host or batch session
.DESCRIPTION
Sessions can be started using 'Start-FalconSession'. A successfully created session will contain a 'session_id'
or 'batch_id' value which can be used with the '-SessionId' or '-BatchId' parameters.
 
The 'Wait' parameter will use 'Confirm-FalconCommand' to check for command results every 5 seconds for a total
of 60 seconds.
 
Requires 'Real Time Response: Read'.
.PARAMETER Command
Real-time Response command
.PARAMETER Argument
Arguments to include with the command
.PARAMETER OptionalHostId
Restrict execution to specific host identifiers
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostTimeout
Length of time to wait for a result from target host(s), in seconds
.PARAMETER SessionId
Session identifier
.PARAMETER BatchId
Batch session identifier
.PARAMETER Wait
Use 'Confirm-FalconCommand' to retrieve single-host command results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-command/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:post',Mandatory,Position=1)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Mandatory,Position=1)]
        [ValidateSet('cat','cd','clear','csrutil','env','eventlog backup','eventlog export','eventlog list',
            'eventlog view','filehash','getsid','help','history','ifconfig','ipconfig','ls','mount','netstat',
            'ps','reg query','users',IgnoreCase=$false)]
        [Alias('base_command')]
        [string]$Command,
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:post',Position=2)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Position=2)]
        [Alias('Arguments')]
        [string]$Argument,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Position=3)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('optional_hosts','OptionalHostIds')]
        [string[]]$OptionalHostId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Position=4)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Position=5)]
        [ValidateRange(1,600)]
        [Alias('host_timeout_duration')]
        [int32]$HostTimeout,
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_id')]
        [string]$BatchId,
        [Parameter(ParameterSetName='/real-time-response/entities/command/v1:post')]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-command/v1:post')]
        [switch]$Wait
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{
                Query = @('timeout','host_timeout_duration')
                Body = @{ root = @('session_id','base_command','command_string','optional_hosts','batch_id') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($OptionalHostId) { @($OptionalHostId).foreach{ $List.Add($_) }}}
    end {
        # Verify 'Endpoint' using BatchId/SessionId
        $Endpoint = if ($PSBoundParameters.BatchId) {
            if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) }
            '/real-time-response/combined/batch-command/v1:post'
        } else {
            '/real-time-response/entities/command/v1:post'
        }
        if ($Endpoint) {
            if ($PSBoundParameters.HostTimeout) {
                # Add 's' to denote seconds for 'host_timeout_duration'
                $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null
            }
            $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) {
                # Join 'Command' and 'Argument' into 'command_string'
                @($PSBoundParameters.Command,$PSBoundParameters.Argument) -join ' '
                [void]$PSBoundParameters.Remove('Argument')
            } else {
                $PSBoundParameters.Command
            }
            @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
                if ($BatchId) {
                    # Add 'batch_id' to each result and output
                    Set-Property $_ batch_id $BatchId
                    $_
                } elseif ($SessionId -and $Wait) {
                    for ($i = 0; $i -lt 60 -and $Result.Complete -ne $true -and !$Result.sha256; $i += 5) {
                        # Attempt to 'confirm' for 60 seconds
                        Start-Sleep 5
                        $Result = $_ | Confirm-FalconCommand
                    }
                    $Result
                } else {
                    $_
                }
            }
        }
    }
}
function Invoke-FalconResponderCommand {
<#
.SYNOPSIS
Issue a Real-time Response active-responder command to an existing single-host or batch session
.DESCRIPTION
Sessions can be started using 'Start-FalconSession'. A successfully created session will contain a 'session_id'
or 'batch_id' value which can be used with the '-SessionId' or '-BatchId' parameters.
 
The 'Wait' parameter will use 'Confirm-FalconResponderCommand' to check for command results every 5 seconds for
a total of 60 seconds.
 
Requires 'Real Time Response: Write'.
.PARAMETER Command
Real-time Response command
.PARAMETER Argument
Arguments to include with the command
.PARAMETER OptionalHostId
Restrict execution to specific host identifiers
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostTimeout
Length of time to wait for a result from target host(s), in seconds
.PARAMETER SessionId
Session identifier
.PARAMETER BatchId
Batch session identifier
.PARAMETER Wait
Use 'Confirm-FalconResponderCommand' to retrieve single-host command results
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconResponderCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:post',Mandatory,
            Position=1)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
            Mandatory,Position=1)]
        [ValidateSet('cat','cd','clear','cp','csrutil','encrypt','env','eventlog backup','eventlog export',
            'eventlog list','eventlog view','filehash','get','getsid','help','history','ifconfig','ipconfig',
            'kill','ls','map','memdump','mkdir','mount','mv','netstat','ps','reg delete','reg load','reg query',
            'reg set','reg unload','restart','rm','runscript','shutdown','umount','unmap','update history',
            'update install','update list','update install','users','xmemdump','zip',IgnoreCase=$false)]
        [Alias('base_command')]
        [string]$Command,
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:post',Position=2)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
           Position=2)]
        [Alias('Arguments')]
        [string]$Argument,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
            Position=3)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('optional_hosts','OptionalHostIds')]
        [string[]]$OptionalHostId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
           Position=4)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
           Position=5)]
        [ValidateRange(1,600)]
        [Alias('host_timeout_duration')]
        [int32]$HostTimeout,
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post',
            Mandatory,ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_id')]
        [string]$BatchId,
        [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:post')]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-active-responder-command/v1:post')]
        [switch]$Wait
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{
                Query = @('timeout','host_timeout_duration')
                Body = @{ root = @('session_id','base_command','command_string','optional_hosts','batch_id') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($OptionalHostId) { @($OptionalHostId).foreach{ $List.Add($_) }}}
    end {
        if ($PSBoundParameters.BatchId -and $PSBoundParameters.Command -eq 'get') {
            # Redirect to 'Invoke-FalconBatchGet' for multi-host 'get' requests
            $GetParam = @{
                FilePath = $PSBoundParameters.Argument
                BatchId = $PSBoundParameters.BatchId
                Wait = $PSBoundParameters.Wait
            }
            if ($Timeout) { $GetParam['Timeout'] = $PSBoundParameters.Timeout }
            if ($List) { $GetParam['OptionalHostId'] = @($List | Select-Object -Unique) }
            Invoke-FalconBatchGet @GetParam
        } else {
            # Verify 'Endpoint' using BatchId/SessionId
            $Endpoint = if ($PSBoundParameters.BatchId) {
                if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) }
                '/real-time-response/combined/batch-active-responder-command/v1:post'
            } elseif ($PSBoundParameters.SessionId) {
                '/real-time-response/entities/active-responder-command/v1:post'
            }
            if ($Endpoint) {
                if ($PSBoundParameters.HostTimeout) {
                    # Add 's' to denote seconds for 'host_timeout_duration'
                    $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null
                }
                $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) {
                    # Join 'Command' and 'Argument' into 'command_string'
                    @($PSBoundParameters.Command,$PSBoundParameters.Argument) -join ' '
                    [void]$PSBoundParameters.Remove('Argument')
                } else {
                    $PSBoundParameters.Command
                }
                @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
                    if ($BatchId) {
                        # Add 'batch_id' to each result and output
                        Set-Property $_ batch_id $BatchId
                        $_
                    } elseif ($SessionId -and $Wait) {
                        for ($i = 0; $i -lt 60 -and $Result.Complete -ne $true -and !$Result.sha256; $i += 5) {
                            # Attempt to 'confirm' for 60 seconds
                            Start-Sleep 5
                            $Result = if ($Command -eq 'get') {
                                $_ | Confirm-FalconGetFile
                            } else {
                                $_ | Confirm-FalconResponderCommand
                            }
                        }
                        $Result
                    } else {
                        $_
                    }
                }
            }
        }
    }
}
function Receive-FalconGetFile {
<#
.SYNOPSIS
Download a password protected .7z archive containing a Real-time Response 'get' file [password: 'infected']
.DESCRIPTION
'Sha256' and 'SessionId' values can be found using 'Confirm-FalconGetFile'. 'Invoke-FalconResponderCommand' or
'Invoke-FalconAdminCommand' can be used to issue a 'get' command to a single-host, and 'Invoke-FalconBatchGet' can
be used for multiple hosts within existing Real-time Response session.
 
Requires 'Real Time Response: Write'.
.PARAMETER Path
Destination path
.PARAMETER Sha256
Sha256 hash value
.PARAMETER SessionId
Session identifier
.PARAMETER Force
Overwrite an existing file when present
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconGetFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get',Position=1)]
        [string]$Path,
        [Parameter(ParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get',Mandatory,
            ValueFromPipelineByPropertyName,Position=2)]
        [ValidatePattern('^[A-Fa-f0-9]{64}$')]
        [string]$Sha256,
        [Parameter(ParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get',Mandatory,
            ValueFromPipelineByPropertyName,Position=3)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get')]
        [switch]$Force
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Headers = @{ Accept = 'application/x-7z-compressed' }
            Format = @{
                Query = @('session_id','sha256')
                Outfile = 'path'
            }
        }
    }
    process {
        if (!$PSBoundParameters.Path -and $PSBoundParameters.Sha256) {
            # When 'Path' is not specified, use 'sha256' from a 'Confirm-FalconGetFile' result
            $PSBoundParameters['Path'] = Join-Path (Get-Location).Path $PSBoundParameters.Sha256
        }
        $PSBoundParameters.Path = Assert-Extension $PSBoundParameters.Path '7z'
        $OutPath = Test-OutFile $PSBoundParameters.Path
        if ($OutPath.Category -eq 'ObjectNotFound') {
            Write-Error @OutPath
        } elseif ($PSBoundParameters.Path) {
            if ($OutPath.Category -eq 'WriteError' -and !$Force) {
                Write-Error @OutPath
            } elseif ($PSBoundParameters.SessionId -and $PSBoundParameters.Sha256) {
                Invoke-Falcon @Param -Inputs $PSBoundParameters
            }
        }
    }
}
function Remove-FalconCommand {
<#
.SYNOPSIS
Remove a command from a queued Real-time Response session
.DESCRIPTION
Requires 'Real Time Response: Read'.
.PARAMETER SessionId
Session identifier
.PARAMETER CloudRequestId
Cloud request identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCommand
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/queued-sessions/command/v1:delete',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/queued-sessions/command/v1:delete',Mandatory,
            ValueFromPipelineByPropertyName,Position=1)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/entities/queued-sessions/command/v1:delete',Mandatory,
            ValueFromPipelineByPropertyName,Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('cloud_request_id','task_id')]
        [string]$CloudRequestId
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('session_id','cloud_request_id') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Remove-FalconGetFile {
<#
.SYNOPSIS
Remove Real-time Response 'get' files
.DESCRIPTION
Delete files previously retrieved during a Real-time Response session. The required 'Id' and 'SessionId' values
are contained in the results of 'Start-FalconSession' and 'Invoke-FalconAdminCommand' or 'Invoke-FalconBatchGet'
commands.
 
Requires 'Real Time Response: Write'.
.PARAMETER SessionId
Session identifier
.PARAMETER Id
Real-time Response 'get' file identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconGetFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/file/v2:delete',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/file/v2:delete',Mandatory,
            ValueFromPipelineByPropertyName,Position=1)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$SessionId,
        [Parameter(ParameterSetName='/real-time-response/entities/file/v2:delete',Mandatory,
            ValueFromPipelineByPropertyName,Position=2)]
        [ValidatePattern('^[A-Fa-f0-9]{64}$')]
        [Alias('Ids','sha256')]
        [string]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('session_id','ids') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Remove-FalconPutFile {
<#
.SYNOPSIS
Remove a Real-time Response 'put' file
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Id
Real-time Response 'put' file identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconPutFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/put-files/v1:delete',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v1:delete',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)]
        [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')]
        [Alias('Ids')]
        [string]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('ids') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Remove-FalconScript {
<#
.SYNOPSIS
Remove a custom Real-time Response script
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Id
Script identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconScript
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/scripts/v1:delete',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:delete',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)]
        [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')]
        [Alias('Ids')]
        [string]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('ids') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Remove-FalconSession {
<#
.SYNOPSIS
Remove a Real-time Response session
.DESCRIPTION
Requires 'Real Time Response: Read'.
.PARAMETER Id
Session identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSession
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/sessions/v1:delete',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/sessions/v1:delete',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('session_id')]
        [string]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Format = @{ Query = @('session_id') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Send-FalconPutFile {
<#
.SYNOPSIS
Upload a Real-time Response 'put' file
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Name
File name
.PARAMETER Description
File description
.PARAMETER Comment
Comment for audit log
.PARAMETER Path
Path to local file
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Send-FalconPutFile
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/put-files/v1:post',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v1:post',
            ValueFromPipelineByPropertyName,Position=1)]
        [string]$Name,
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v1:post',Position=2)]
        [string]$Description,
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v1:post',Position=3)]
        [ValidateLength(1,4096)]
        [Alias('comments_for_audit_log')]
        [string]$Comment,
        [Parameter(ParameterSetName='/real-time-response/entities/put-files/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,Position=4)]
        [ValidateScript({
            if (Test-Path $_ -PathType Leaf) {
                $true
            } else {
                throw "Cannot find path '$_' because it does not exist or is a directory."
            }
        })]
        [Alias('file','FullName')]
        [string]$Path
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Headers = @{ ContentType = 'multipart/form-data' }
            Format = @{ Formdata = @('file','name','description','comments_for_audit_log') }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Send-FalconScript {
<#
.SYNOPSIS
Upload a custom Real-time Response script
.DESCRIPTION
Requires 'Real Time Response (Admin): Write'.
.PARAMETER Platform
Operating system platform
.PARAMETER PermissionType
Permission level [public: 'Administrators' and 'Active Responders', group: 'Administrators', private: creator]
.PARAMETER Name
Script name
.PARAMETER Description
Script description
.PARAMETER Comment
Audit log comment
.PARAMETER Path
Path to local file or string-based script content
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Send-FalconScript
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/scripts/v1:post',SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,Position=1)]
        [ValidateSet('windows','mac','linux',IgnoreCase=$false)]
        [string[]]$Platform,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,Position=2)]
        [ValidateSet('private','group','public',IgnoreCase=$false)]
        [Alias('permission_type')]
        [string]$PermissionType,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',ValueFromPipelineByPropertyName,
            Position=3)]
        [string]$Name,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',ValueFromPipelineByPropertyName,
            Position=4)]
        [string]$Description,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',ValueFromPipelineByPropertyName,
            Position=5)]
        [ValidateLength(1,4096)]
        [Alias('comments_for_audit_log')]
        [string]$Comment,
        [Parameter(ParameterSetName='/real-time-response/entities/scripts/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,Position=6)]
        [Alias('content','FullName')]
        [string]$Path
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Endpoint = $PSCmdlet.ParameterSetName
            Headers = @{ ContentType = 'multipart/form-data' }
            Format = @{
                Formdata = @('platform','permission_type','name','description','comments_for_audit_log',
                    'content')
            }
        }
    }
    process { Invoke-Falcon @Param -Inputs $PSBoundParameters }
}
function Start-FalconSession {
<#
.SYNOPSIS
Initialize a single-host or batch Real-time Response session
.DESCRIPTION
Real-time Response sessions require Host identifier values. Sessions that are successfully started return a
'session_id' (for single hosts) or 'batch_id' (multiple hosts) value which can be used to issue commands that
will be processed by the host(s) in the session.
 
Commands can be issued using 'Invoke-FalconCommand', 'Invoke-FalconResponderCommand', 'Invoke-FalconAdminCommand'
and 'Invoke-FalconBatchGet'.
 
Requires 'Real Time Response: Read'.
.PARAMETER QueueOffline
Add non-responsive hosts to the offline queue
.PARAMETER ExistingBatchId
Add hosts to an existing batch session
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostTimeout
Length of time to wait for a result from target host(s), in seconds
.PARAMETER Id
Host identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Start-FalconSession
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/combined/batch-init-session/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/sessions/v1:post',Position=1)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Position=1)]
        [Alias('queue_offline')]
        [boolean]$QueueOffline,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('existing_batch_id')]
        [string]$ExistingBatchId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Position=3)]
        [Parameter(ParameterSetName='/real-time-response/entities/sessions/v1:post',Position=2)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Position=4)]
        [ValidateRange(1,600)]
        [Alias('host_timeout_duration')]
        [int32]$HostTimeout,
        [Parameter(ParameterSetName='/real-time-response/entities/sessions/v1:post',Mandatory)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [ValidateLength(1,10000)]
        [Alias('host_ids','device_id','device_ids','aid','HostId','HostIds')]
        [string[]]$Id
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{
                Query = @('timeout','host_timeout_duration')
                Body = @{ root = @('existing_batch_id','host_ids','queue_offline','device_id') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
    end {
        if ($List) {
            # Verify 'Endpoint' using BatchId/SessionId and select hosts
            [void]$PSBoundParameters.Remove('Id')
            $Endpoint = if ($List.Count -eq 1 -and !$HostTimeout -and !$ExistingBatchId) {
                $PSBoundParameters['device_id'] = $List[0]
                '/real-time-response/entities/sessions/v1:post'
            } else {
                if ($PSBoundParameters.HostTimeout) {
                    # Add 's' to denote seconds for 'host_timeout_duration'
                    $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null
                }
                $PSBoundParameters['host_ids'] = @($List | Select-Object -Unique)
                '/real-time-response/combined/batch-init-session/v1:post'
            }
            @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
                if ($_.batch_id -and $_.resources) {
                    [string]$BatchId = $_.batch_id
                    @($_.resources.PSObject.Properties.Value).Where({ $_.errors }).foreach{
                        # Write warning for hosts in batch that produced errors
                        $PSCmdlet.WriteWarning("[Start-FalconSession] $(
                            @($_.errors.code,$_.errors.message) -join ': ') [aid: $($_.aid)]"
)
                    }
                    @($_.resources.PSObject.Properties.Value).Where({ $_.session_id }).foreach{
                        # Append 'batch_id' for hosts with a 'session_id'
                        Set-Property $_ batch_id $BatchId
                    }
                    [PSCustomObject]@{
                        batch_id = $_.batch_id
                        hosts = $_.resources.PSObject.Properties.Value
                    }
                } else {
                    # Append 'aid' to single host session result
                    Set-Property $_ aid $List[0]
                    $_
                }
            }
        }
    }
}
function Update-FalconSession {
<#
.SYNOPSIS
Refresh a single-host or batch Real-time Response session to prevent expiration
.DESCRIPTION
Real-time Response sessions expire after 5 minutes by default. Any commands that were issued to a session that
take longer than 5 minutes will not return results without refreshing the session to keep it alive until the
command process completes.
 
Requires 'Real Time Response: Read'.
.PARAMETER QueueOffline
Add non-responsive hosts to the offline queue
.PARAMETER HostToRemove
Host identifier(s) to remove from a batch Real-time Response session
.PARAMETER Timeout
Length of time to wait for a result, in seconds [default: 30]
.PARAMETER HostId
Host identifier, for a single-host session
.PARAMETER BatchId
Batch session identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Update-FalconSession
#>

    [CmdletBinding(DefaultParameterSetName='/real-time-response/entities/refresh-session/v1:post',
        SupportsShouldProcess)]
    param(
        [Parameter(ParameterSetName='/real-time-response/entities/refresh-session/v1:post',Position=1)]
        [Parameter(ParameterSetName='/real-time-response/combined/batch-refresh-session/v1:post',Position=1)]
        [Alias('queue_offline')]
        [boolean]$QueueOffline,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-refresh-session/v1:post',Position=2)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('hosts_to_remove','HostsToRemove')]
        [string[]]$HostToRemove,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-refresh-session/v1:post',Position=3)]
        [ValidateRange(1,600)]
        [int32]$Timeout,
        [Parameter(ParameterSetName='/real-time-response/entities/refresh-session/v1:post',Mandatory,
            ValueFromPipelineByPropertyName,ValueFromPipeline)]
        [ValidatePattern('^[a-fA-F0-9]{32}$')]
        [Alias('device_id','host_ids','aid')]
        [string]$HostId,
        [Parameter(ParameterSetName='/real-time-response/combined/batch-refresh-session/v1:post',Mandatory,
            ValueFromPipelineByPropertyName)]
        [ValidatePattern('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')]
        [Alias('batch_id')]
        [string]$BatchId
    )
    begin {
        $Param = @{
            Command = $MyInvocation.MyCommand.Name
            Format = @{
                Query = @('timeout')
                Body = @{ root = @('queue_offline','device_id','batch_id','hosts_to_remove') }
            }
        }
        [System.Collections.Generic.List[string]]$List = @()
    }
    process { if ($HostToRemove) { @($HostToRemove).foreach{ $List.Add($_) }}}
    end {
        # Verify 'Endpoint' using HostId/BatchId
        [string]$Endpoint = if ($PSBoundParameters.HostId) {
            '/real-time-response/entities/refresh-session/v1:post'
        } elseif ($PSBoundParameters.BatchId) {
            if ($List) { $PSBoundParameters['HostToRemove'] = @($List | Select-Object -Unique) }
            '/real-time-response/combined/batch-refresh-session/v1:post'
        }
        @(Invoke-Falcon @Param -Endpoint $Endpoint -Inputs $PSBoundParameters).foreach{
            if ($Endpoint -eq '/real-time-response/combined/batch-refresh-session/v1:post') {
                @($_.PSObject.Properties.Value).Where({ $_.errors }).foreach{
                    # Write warning for hosts in batch that produced errors
                    $PSCmdlet.WriteWarning("[Update-FalconSession] $(
                        @($_.errors.code,$_.errors.message) -join ': ') [aid: $($_.aid)]"
)
                }
                # Output 'batch_id' and 'hosts' containing result
                [PSCustomObject]@{
                    batch_id = $BatchId
                    hosts = $_.PSObject.Properties.Value
                }
            } else {
                # Append 'aid' to single host session result
                Set-Property $_ aid $HostId
                $_
            }
        }
    }
}