Skip to content

Code Examples

bk-cs edited this page Mar 21, 2023 · 67 revisions

CrowdStrike Falcon


The examples provided below are for example purposes only and are offered 'as is' with no support.


Authentication

Ingesting Data

Manipulating Objects


Authentication

Request authorization token and run commands

An example of how to include OAuth2 API Client information as parameters and perform an authorization token request to the associated CID or "member" CID.

#Requires -Version 5.1
using module @{ModuleName='PSFalcon';ModuleVersion='2.2'}
[CmdletBinding()]
param(
    [Parameter(Mandatory,Position=1)]
    [ValidatePattern('^[a-fA-F0-9]{32}$')]
    [string]$ClientId,
    [Parameter(Mandatory,Position=2)]
    [ValidatePattern('^\w{40}$')]
    [string]$ClientSecret,
    [Parameter(Position=3)]
    [ValidatePattern('^[a-fA-F0-9]{32}$')]
    [string]$MemberCid,
    [Parameter(Position=4)]
    [ValidateSet('us-1','us-2','us-gov-1','eu-1')]
    [string]$Cloud
)
begin {
    $Token = @{}
    @('ClientId','ClientSecret','Cloud','MemberCid').foreach{
        if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ }
    }
}
process {
    try {
        Request-FalconToken @Token
        if ((Test-FalconToken).Token -eq $true) {
            # Insert code to run and output data here
        }
    } catch {
        throw $_
    } finally {
        if ((Test-FalconToken).Token -eq $true) { Revoke-FalconToken }
    }
}

Authorize and run commands in member CIDs

In multi-CID configurations, you can create an OAuth2 API Client Id/Secret in the "parent" CID that has access to the "child" or "member" CIDs. Some data is visible at the parent level, but some data is only visible within the child. After creating an API Client, you can use that to retrieve a list of all available member CIDs (or provide specific members using MemberCid) and run PSFalcon commands within each child, while pausing between authorization token request attempts to avoid rate limiting.

#Requires -Version 5.1
using module @{ModuleName='PSFalcon';ModuleVersion='2.2'}
[CmdletBinding()]
param(
    [Parameter(Mandatory,Position=1)]
    [ValidatePattern('^[a-fA-F0-9]{32}$')]
    [string]$ClientId,
    [Parameter(Mandatory,Position=2)]
    [ValidatePattern('^\w{40}$')]
    [string]$ClientSecret,
    [Parameter(Position=3)]
    [ValidatePattern('^[a-fA-F0-9]{32}$')]
    [string[]]$MemberCid,
    [Parameter(Position=4)]
    [ValidateSet('us-1','us-2','us-gov-1','eu-1')]
    [string]$Cloud
)
begin {
    $Token = @{}
    @('ClientId','ClientSecret','Cloud').foreach{
        if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ }
    }
    if (!$MemberCid) {
        Request-FalconToken @Token
        if ((Test-FalconToken).Token -eq $true) {
            # Gather available Member CIDs
            [string[]]$MemberCid = Get-FalconMemberCid -Detailed -All | Where-Object {
                $_.status -eq 'active' } | Select-Object -ExpandProperty child_cid
            Revoke-FalconToken
        }
    }
}
process {
    foreach ($Cid in $MemberCid) {
        try {
            Request-FalconToken @Token -MemberCid $Cid
            if ((Test-FalconToken).Token -eq $true) {
                # Insert code to run and output data from each CID here
            }
        } catch {
            Write-Error $_
        } finally {
            if ((Test-FalconToken).Token -eq $true) {
                Revoke-FalconToken
                Start-Sleep -Seconds 5
            }
        }
    }
}

Ingesting data

Retrieve items from a text file or CSV

Collect a list of items (identifiers, hostnames, group names, etc.) from a text file, exclude blank values and save to the variable $List, which can be used with a PSFalcon command.

#Requires -Version 5.1
param(
    [Parameter(Mandatory)]
    [ValidateScript({
        if (Test-Path -Path $_ -PathType Leaf) {
            $true
        } else {
            throw "Cannot find path '$_' because it does not exist or is a directory."
        }
    })]
    [string]$Path
)
[string]$FilePath = if (![IO.Path]::IsPathRooted($PSBoundParameters.Path)) {
    $FullPath = Join-Path (Get-Location).Path $PSBoundParameters.Path
    $FullPath = Join-Path $FullPath '.'
    [IO.Path]::GetFullPath($FullPath)
} else {
    $PSBoundParameters.Path
}
[string[]]$List = @((Get-Content -Path $FilePath).Normalize()).foreach{ if (![string]::IsNullOrEmpty($_)) { $_ }}

Collecting a list of hostnames (using the column Hostname) from a CSV can be done by modifying the $List line.

[string[]]$List = ((Import-Csv -Path $FilePath).Hostname).foreach{ if (![string]::IsNullOrEmpty($_)) { $_ }}

Retrieve identifiers using a list

The Filter parameter (a Falcon Query Language statement) will accept a limited number of conditions at a time. If you have a list of hostnames that you need to match with their identifiers, you can use the Find-FalconHostname command.

(Get-Content -Path $FilePath).Normalize() | Find-FalconHostname

Manipulating Objects

Add properties to an object

Most PSFalcon commands return [PSCustomObject] results. One of the fastest ways to add properties to a [PSCustomObject] can be converted into a simple function that you can re-use.

#Requires -Version 5.1
function Set-Property {
    [CmdletBinding()]
    [OutputType([void])]
    param([object]$Object,[string]$Name,[object]$Value)
    process {
        if ($Object.$Name) {
            # Update existing property
            $Object.$Name = $Value
        } else {
            # Add property to [PSCustomObject]
            $Object.PSObject.Properties.Add((New-Object PSNoteProperty($Name,$Value)))
        }
    }
}

For example, if you wanted to add property test with value abc to a Get-FalconHost result:

$HostObject = Get-FalconHost -Filter "hostname:'EXAMPLE-PC'" -Detailed
Set-Property -Object $HostObject -Name 'test' -Value 'abc'

Iterate properties of an object

Different types of objects require different methods to figure out what properties are available in an object. Most PSFalcon command results are arrays of [PSCustomObject] values, which allows manipulation in several different ways, but they're not always easy to understand to someone inexperienced with PowerShell.

It's easiest to start with your result saved to a variable:

$HostList = Get-FalconHost -Detailed

From there, you can use Select-Object to choose certain properties:

$HostList | Select-Object device_id,hostname,local_ip

device_id   hostname     local_ip
---------   --------     --------
<redacted>  EXAMPLE-PC1  192.168.0.10
<redacted>  EXAMPLE-PC2  192.168.0.11

Where-Object can be used to filter for results with specific properties, using an exact match, or a RegEx match:

$HostList | Where-Object { $_.hostname -eq 'EXAMPLE-PC2' } | Select-Object device_id,hostname,local_ip

device_id   hostname     local_ip
---------   --------     --------
<redacted>  EXAMPLE-PC2  192.168.0.11

$HostList | Where-Object { $_.hostname -match 'PC2' } | Select-Object device_id,hostname,local_ip

device_id   hostname     local_ip
---------   --------     --------
<redacted>  EXAMPLE-PC2  192.168.0.11

Group-Object can help determine counts, like devices by agent_version, or devices by os_version:

$HostList | Group-Object agent_version

Count Name                      Group
----- ----                      -----
    2 6.26.14003.0              {@{device_id=...

$HostList | Group-Object os_version

Count Name                      Group
----- ----                      -----
    2 Windows 10                {@{device_id=...

Things become more complex when you don't know what properties are available, and it can be made more difficult when those properties aren't part of the object. For example, the Falcon APIs will omit properties when they aren't present, like when a device is not joined to a domain:

$HostList | Select-Object device_id,hostname,machine_domain

device_id   hostname     machine_domain
---------   --------     --------
<redacted>  EXAMPLE-PC1  
<redacted>  EXAMPLE-PC2  example.com

To determine the number of properties that are present on both objects, it's easy to count the array itself. Unfortunately, PowerShell will only display the properties of the first object in the array. Properties for each object are only displayed when checking each object individually:

($HostList | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' }).Count
42

$HostList | ForEach-Object { ($_ | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' }).Count }
42
45

Checking each object for the property names, then grouping them and selecting the unique properties can provide a list of the available property names across all objects in the array:

($HostList | ForEach-Object { ($_ | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' }).Name } | Group-Object).Name
agent_load_flags
agent_local_time
agent_version
...

The examples provided above are for example purposes only and are offered 'as is' with no support.


Clone this wiki locally