public/identity-protection.ps1

function Invoke-FalconIdentityGraph {
<#
.SYNOPSIS
Interact with Falcon Identity using GraphQL
.DESCRIPTION
The 'All' parameter requires that your GraphQL statement contain an 'after' cursor variable definition and
'pageInfo { hasNextPage endCursor }'.
 
Requires 'Identity Protection GraphQL: Write', and other 'Identity Protection' permission(s) depending on query.
.PARAMETER String
A complete GraphQL statement
.PARAMETER Variable
A hashtable containing variables used in your GraphQL statement
.PARAMETER All
Repeat requests until all available results are retrieved
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconIdentityGraph
#>

  [CmdletBinding(SupportsShouldProcess)]
  param(
    [Parameter(Mandatory,ValueFromPipeline,Position=1)]
    [Alias('query','mutation')]
    [string]$String,
    [Parameter(ValueFromPipeline,Position=2)]
    [Alias('variables')]
    [hashtable]$Variable,
    [switch]$All
  )
  begin {
    function Assert-CursorVariable ($UserInput,$EndCursor) {
      # Use variable definition to ensure 'Cursor' is within 'Variable' hashtable
      if ($UserInput.query -match '^(\s+)?query\s+?\(.+Cursor') {
        @([regex]::Matches($UserInput.query,
          '(?<=query\s+?\()(\$\w+:.[^\)]+)').Value -replace '\$',$null).foreach{
          $Array = ($_ -split ':',2).Trim()
          if ($Array[1] -eq 'Cursor') {
            if (!$UserInput.variables) {
              $UserInput.Add('variables',@{ $Array[0] = $EndCursor })
            } elseif ($UserInput.variables.($Array[0])) {
              $UserInput.variables.($Array[0]) = $EndCursor
            }
          }
        }
      }
      return $UserInput
    }
    function Invoke-GraphLoop ($Object,$Splat,$UserInput) {
      $RegEx = @{
        # Patterns to validate statement for 'pageInfo' and 'Cursor' variable
        CursorVariable = '^(\s+)?query\s+?\(.+Cursor'
        PageInfo = 'pageInfo(\s+)?{(\s+)?(hasNextPage([,\s]+)?|endCursor([,\s]+)?){2}(\s+)?}'
      }
      [string]$Message = if ($UserInput.query -notmatch $RegEx.CursorVariable) {
        "'-All' parameter was specified but 'Cursor' definition is missing from statement."
      } elseif ($UserInput.query -notmatch $RegEx.PageInfo) {
        "'-All' parameter was specified but 'pageInfo' is missing from statement."
      }
      if ($Message) {
        $PSCmdlet.WriteWarning(("[$($Splat.Command)]",$Message -join ' '))
      } else {
        do {
          if ($Object.entities.pageInfo.endCursor) {
            # Update 'Cursor' and repeat
            $UserInput = Assert-CursorVariable $UserInput $Object.entities.pageInfo.endCursor
            Write-GraphResult (Invoke-Falcon @Splat -UserInput $UserInput -OutVariable Object)
          }
        } while (
          $Object.entities.pageInfo.hasNextPage -eq $true -and $null -ne
            $Object.entities.pageInfo.endCursor
        )
      }
    }
    function Write-GraphResult ($Object) {
      if ($Object.entities.pageInfo) {
        # Output verbose 'pageInfo' detail
        [string]$Message = (@($Object.entities.pageInfo.PSObject.Properties).foreach{
          $_.Name,$_.Value -join '='
        }) -join ', '
        Write-Log 'Invoke-FalconIdentityGraph' ($Message -join ' ')
      }
      # Output 'nodes'
      if ($Object.entities.nodes) { $Object.entities.nodes } else { $Object }
    }
    $Param = @{
      Command = $MyInvocation.MyCommand.Name
      Endpoint = '/identity-protection/combined/graphql/v1:post'
      Format = @{ Body = @{ root = @('query','variables') }}
    }
  }
  process {
    if ($PSBoundParameters.All) {
      Write-GraphResult (Invoke-Falcon @Param -UserInput $PSBoundParameters -OutVariable Request)
    } else {
      Invoke-Falcon @Param -UserInput $PSBoundParameters
    }
  }
  end { if ($Request -and $PSBoundParameters.All) { Invoke-GraphLoop $Request $Param $PSBoundParameters }}
}
function Get-FalconIdentityHost {
<#
.SYNOPSIS
Search for Falcon Identity hosts
.DESCRIPTION
Requires 'Identity Protection Entities: Read'.
.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-FalconIdentityHost
#>

  [CmdletBinding(DefaultParameterSetName='/identity-protection/queries/devices/v1:get',SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/identity-protection/entities/devices/GET/v1:post',
      ValueFromPipelineByPropertyName,ValueFromPipeline,Mandatory)]
    [ValidatePattern('^[a-fA-F0-9]{32}$')]
    [Alias('ids','device_id','host_ids','aid')]
    [string[]]$Id,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get',Position=1)]
    [ValidateScript({ Test-FqlStatement $_ })]
    [string]$Filter,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get',Position=2)]
    [string]$Sort,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get',Position=3)]
    [ValidateRange(1,200)]
    [int]$Limit,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get')]
    [int]$Offset,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get')]
    [switch]$Detailed,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get')]
    [switch]$All,
    [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get')]
    [switch]$Total
  )
  begin {
    $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }
    [System.Collections.Generic.List[string]]$List = @()
  }
  process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
  end {
    if ($List) {
      $Param['Max'] = 5000
      $PSBoundParameters['Id'] = @($List)
    }
    Invoke-Falcon @Param -UserInput $PSBoundParameters
  }
}
function Get-FalconIdentityRule {
<#
.SYNOPSIS
Search for Falcon Identity Protection policy rules
.DESCRIPTION
Requires 'Identity Protection Policy Rules: Read'.
.PARAMETER Id
Falcon Identity Protection policy rule identifier
.PARAMETER Name
Filter by rule name
.PARAMETER Enabled
Filter by rule enablement status
.PARAMETER SimulationMode
Filter by simulation mode
.PARAMETER Detailed
Retrieve detailed information
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIdentityRule
#>

  [CmdletBinding(DefaultParameterSetName='/identity-protection/queries/policy-rules/v1:get',SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:get',Mandatory,
      ValueFromPipelineByPropertyName,ValueFromPipeline)]
    [Alias('ids')]
    [string[]]$Id,
    [Parameter(ParameterSetName='/identity-protection/queries/policy-rules/v1:get',Position=1)]
    [string]$Name,
    [Parameter(ParameterSetName='/identity-protection/queries/policy-rules/v1:get',Position=2)]
    [boolean]$Enabled,
    [Parameter(ParameterSetName='/identity-protection/queries/policy-rules/v1:get',Position=3)]
    [Alias('simulation_mode')]
    [boolean]$SimulationMode,
    [Parameter(ParameterSetName='/identity-protection/queries/policy-rules/v1:get')]
    [switch]$Detailed
  )
  begin {
    $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }
    [System.Collections.Generic.List[string]]$List = @()
  }
  process {
    if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters }
  }
  end {
    if ($List) {
      $Param['Max'] = 70
      $PSBoundParameters['Id'] = @($List)
      Invoke-Falcon @Param -UserInput $PSBoundParameters
    }
  }
}
function New-FalconIdentityRule {
<#
.SYNOPSIS
Create Falcon Identity Protection policy rules
.DESCRIPTION
Requires 'Identity Protection Policy Rules: Write'.
.PARAMETER Name
Rule name
.PARAMETER Action
Rule action
.PARAMETER Trigger
Rule trigger
.PARAMETER Enabled
Rule enablement status
.PARAMETER SimulationMode
Enable simulation mode
.PARAMETER Activity
Object containing 'accessType' and/or 'accessTypeCustom', for rule conditions based on access
.PARAMETER Destination
Object containing 'entityId' and/or 'groupMembership', for rule conditions based on destination
.PARAMETER SourceEndpoint
Object containing 'entityId' and/or 'groupMembership', for define rule conditions based on source endpoints
.PARAMETER SourceUser
Object containing 'entityId' and/or 'groupMembership', for define rule conditions based on source users
.LINK
https://github.com/crowdstrike/psfalcon/wiki/New-FalconIdentityRule
#>

  [CmdletBinding(DefaultParameterSetName='/identity-protection/entities/policy-rules/v1:post',
    SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Mandatory,Position=1)]
    [string]$Name,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Mandatory,Position=2)]
    [ValidateSet('ADD_TO_WATCH_LIST','ALLOW','APPLY_SSO_POLICY','BLOCK','FORCE_PASSWORD_CHANGE','MFA',
      IgnoreCase=$false)]
    [string]$Action,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Mandatory,Position=3)]
    [ValidateSet('access','accountEvent','alert','federatedAccess',IgnoreCase=$false)]
    [string]$Trigger,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Mandatory,Position=4)]
    [boolean]$Enabled,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Mandatory,Position=5)]
    [boolean]$SimulationMode,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Position=6)]
    [object]$Activity,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Position=7)]
    [object]$Destination,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Position=8)]
    [object]$SourceEndpoint,
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:post',Position=9)]
    [object]$SourceUser
  )
  begin {
    $Param = @{
      Command = $MyInvocation.MyCommand.Name
      Endpoint = $PSCmdlet.ParameterSetName
      Format = @{ Body = @{ root = @('action','enabled','name','simulationMode','trigger','activity','destination',
        'sourceEndpoint','sourceUser') }}
    }
  }
  process {
    # Create 'JsonBody' for submission to ensure camelCase is used
    $JsonBody = @{}
    @($Param.Format.Body.root).foreach{
      if ($null -ne $PSBoundParameters.$_) { $JsonBody[$_] = $PSBoundParameters.$_ }
    }
    $Param['JsonBody'] = $JsonBody | ConvertTo-Json -Depth 32 -Compress
    Invoke-Falcon @Param
  }
}
function Remove-FalconIdentityRule {
<#
.SYNOPSIS
Remove Falcon Identity Protection policy rules
.DESCRIPTION
Requires 'Identity Protection Policy Rules: Write'.
.PARAMETER Id
Policy rule identifier
.LINK
https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIdentityRule
#>

  [CmdletBinding(DefaultParameterSetName='/identity-protection/entities/policy-rules/v1:delete',
    SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='/identity-protection/entities/policy-rules/v1:delete',Mandatory,
      ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)]
    [Alias('ids')]
    [string[]]$Id
  )
  begin {
    $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 100 }
    [System.Collections.Generic.List[string]]$List = @()
  }
  process { if ($Id) { @($Id).foreach{ $List.Add($_) }}}
  end {
    if ($List) { $PSBoundParameters['Id'] = @($List) }
    Invoke-Falcon @Param -UserInput $PSBoundParameters
  }
}