public/psf-sensors.ps1
function Invoke-TagScript { param( [Parameter(Mandatory,Position=1)] [object]$Object, [Parameter(Mandatory,Position=2)] [ValidateSet('Add','Remove','Set',IgnoreCase=$false)] [string]$Action, [Parameter(Mandatory,Position=3)] [boolean]$QueueOffline, [Parameter(Position=4)] [string[]]$String ) process { [string]$ScriptPath = Join-Path (Show-FalconModule).ModulePath 'script' [string[]]$Tag = $String -replace 'SensorGroupingTags/',$null $Output = [PSCustomObject]@{ cid = $Object.cid device_id = $Object.device_id tags = $null offline_queued = $false session_id = $null cloud_request_id = $null status = $null } if (@('Linux','Mac','Windows') -notcontains $Object.platform_name) { $Output.status = 'UNSUPPORTED_PLATFORM' } else { try { # Determine if uninstallation token is required, if host is online, and current SensorTag values [string]$Protection = $Object.device_policies.sensor_update.uninstall_protection [string]$State = (Get-FalconHost -Id $Object.device_id -State).state [string[]]$Existing = @($Object.tags).Where({$_ -match 'SensorGroupingTags/'}) -replace 'SensorGroupingTags/',$null [string]$TagString = if ($Existing -and $Action -ne 'Set') { if ($Action -eq 'Add') { # Select tag(s) to append [boolean]$Append = $false @($Tag).foreach{ if ($Append -eq $false -and $Existing -notcontains $_) { $Append = $true } } if ($Append -eq $true) { (@($Existing + $Tag) | Select-Object -Unique) -join ',' } } elseif ($Action -eq 'Remove') { # Select tag(s) to remove [boolean]$Remove = $false @($Tag).foreach{ if ($Remove -eq $false -and $Existing -contains $_) { $Remove = $true } } if ($Remove -eq $true) { (@($Existing).Where({$Tag -notcontains $_}) | Select-Object -Unique) -join ',' } } } else { # Use new tag(s) when none are currently assigned, or when using 'Set-FalconSensorTag' ($Tag | Select-Object -Unique) -join ',' } if ((!$TagString -and $Tag) -or (!$Existing -and !$Tag) -or ($Object.platform_name -ne 'Windows' -and $Protection -eq 'ENABLED')) { # Output host properties and 'tags' value when no changes are made $Output.tags = $Existing -join ',' $Output.status = if ($Object.platform_name -ne 'Windows' -and $Protection -eq 'ENABLED') { # Abort when uninstallation token is required but 'platform_name' is not Windows 'NO_TOKEN_SUPPORT_FOR_OS' } elseif ($Action -eq 'Add' -and $Tag) { 'TAG_PRESENT' } elseif ($Action -eq 'Remove' -and !$Tag) { 'NO_TAG_SET' } else { 'TAG_NOT_PRESENT' } } elseif ($QueueOffline -eq $true -or ($QueueOffline -eq $false -and $State -eq 'online')) { # Add quotes around tag value string for Windows script use if ($Object.platform_name -eq 'Windows' -and $TagString) { $TagString = ('"{0}"' -f $TagString) } [string]$CmdLine = if ($Protection -eq 'ENABLED') { # Retrieve uninstallation token and add to 'CommandLine' when host is 'online' [string]$Token = (Get-FalconUninstallToken -Id $Object.device_id -AuditMessage (($Action, 'FalconSensorTag' -join '-'),"[$((Show-FalconModule).UserAgent)]" -join ' ')).uninstall_token if ($TagString) { $TagString,$Token -join ' ' } else { $Token } } elseif ($TagString) { $TagString } # Import RTR script content and run script via RTR [string]$ScriptName = if ($Action -eq 'Remove' -and !$TagString) { 'clear_sensortag' } else { if ($Action -eq 'Set') { 'add_sensortag' } else { ($Action.ToLower(),'sensortag' -join '_') } } [string]$Extension = switch ($Object.platform_name) { 'Linux' { 'sh' } 'Mac' { 'zsh' } 'Windows' { 'ps1' } } [string]$ScriptFile = (Join-Path $ScriptPath ($ScriptName,$Extension -join '.')) Write-Log ($Action,'FalconSensorTag' -join '-') "Importing '$ScriptFile'..." $Script = Get-Content $ScriptFile -Raw $Param = @{ Command = 'runscript' Argument = '-Raw=```{0}```' -f $Script HostId = $Object.device_id QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } } if ($CmdLine) { $Param.Argument += (' -CommandLine=```{0}```' -f $CmdLine) } @(Invoke-FalconRtr @Param).foreach{ $Output.tags = if ($_.errors) { $_.errors } elseif ($_.stderr) { $_.stderr } elseif ($_.offline_queued -eq $true) { $Output.status = 'PENDING_QUEUE' $Existing -join ',' } else { $Output.status = if ($Action -eq 'Add') { 'TAG_ADDED' } elseif ($Action -eq 'Remove') { if ($TagString) { 'TAG_REMOVED' } else { 'TAG_CLEARED' } } else { 'TAG_SET' } $Result = ($_.stdout).Trim() if ($Result -match 'Maintenance Token>') { ($TagString).Trim('"') } else { $Result } } foreach ($Property in @('offline_queued','session_id','cloud_request_id')) { $Output.$Property = $_.$Property } } } else { # Output existing tags when device is offline and not queued $Output.tags = $Existing -join ',' $Output.status = 'HOST_OFFLINE_AND_NOT_QUEUED' } } catch { Write-Error $_ } } $Output } } function Add-FalconSensorTag { <# .SYNOPSIS Use Real-time Response to add SensorGroupingTags to a host .DESCRIPTION Provided SensorGroupingTag values will be appended to any existing tags. If no new tag values are supplied, a list of the current tags will be output for the target host. To overwrite existing values, use 'Set-FalconSensorTag'. Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and 'Real time response (admin): Write'. .PARAMETER Tag SensorGroupingTag value ['SensorGroupingTags/<string>'] .PARAMETER QueueOffline Add command request to the offline queue .PARAMETER Id Host identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Add-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory,Position=1)] [ValidateScript({ @($_).foreach{ if ((Test-RegexValue $_) -eq 'tag') { $true } else { throw "Valid values include letters numbers, hyphens, unscores and forward slashes. ['$_']" } } })] [Alias('Tags')] [string[]]$Tag, [Parameter(Position=2)] [boolean]$QueueOffline, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { foreach ($i in @(Get-FalconHost -Id $List | Select-Object cid,device_id,platform_name,device_policies, tags)) { Invoke-TagScript $i 'Add' $QueueOffline $Tag } } } } function Get-FalconSensorTag { <# .SYNOPSIS Display SensorGroupingTags assigned to hosts .DESCRIPTION Returns 'cid', 'device_id', and any SensorGroupingTags listed under 'tags' within a 'Get-FalconHost' result. Requires 'Hosts: Read'. .PARAMETER Id Host identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { @(Get-FalconHost -Id $List | Select-Object cid,device_id,tags).foreach{ [PSCustomObject]@{ cid = $_.cid device_id = $_.device_id tags = @($_.tags).Where({$_ -match 'SensorGroupingTags/'}) -replace 'SensorGroupingTags/', $null -join ',' } } } } } function Remove-FalconSensorTag { <# .SYNOPSIS Use Real-time Response to remove SensorGroupingTags from a host .DESCRIPTION When provided, SensorGroupingTag values will be removed from list of existing tags and others will be left unmodified. If no tags are provided, all existing tags will be removed. Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and 'Real time response (admin): Write'. .PARAMETER Tag SensorGroupingTag value ['SensorGroupingTags/<string>'] .PARAMETER Id Host identifier .PARAMETER QueueOffline Add command request to the offline queue .LINK https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] [OutputType([PSCustomObject])] param( [Parameter(Position=1)] [ValidateScript({ @($_).foreach{ if ((Test-RegexValue $_) -eq 'tag') { $true } else { throw "Valid values include letters, numbers, hyphens, unscores and forward slashes. ['$_']" } } })] [Alias('Tags')] [string[]]$Tag, [Parameter(Position=2)] [boolean]$QueueOffline, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { foreach ($i in @(Get-FalconHost -Id $List | Select-Object cid,device_id,platform_name,device_policies, tags)) { Invoke-TagScript $i 'Remove' $QueueOffline $Tag } } } } function Set-FalconSensorTag { <# .SYNOPSIS Use Real-time Response to set SensorGroupingTags on a host .DESCRIPTION Provided SensorGroupingTag values will overwrite any existing tags. To append to existing values, use 'Add-FalconSensorTag'. Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and 'Real time response (admin): Write'. .PARAMETER Tag SensorGroupingTag value ['FalconSensorTags/<string>'] .PARAMETER QueueOffline Add command request to the offline queue .PARAMETER Id Host identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Set-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] [OutputType([PSCustomObject])] param( [Parameter(Mandatory,Position=1)] [ValidateScript({ @($_).foreach{ if ((Test-RegexValue $_) -eq 'tag') { $true } else { throw "Valid values include letters numbers, hyphens, unscores and forward slashes. ['$_']" } } })] [Alias('Tags')] [string[]]$Tag, [Parameter(Position=2)] [boolean]$QueueOffline, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { foreach ($i in @(Get-FalconHost -Id $List | Select-Object cid,device_id,platform_name,device_policies, tags)) { Invoke-TagScript $i 'Set' $QueueOffline $Tag } } } } function Uninstall-FalconSensor { <# .SYNOPSIS Use Real-time Response to uninstall the Falcon sensor from a host .DESCRIPTION This command uses information from the registry and/or relevant Falcon command line utilities of the target host to uninstall the Falcon sensor. If the sensor is damaged or malfunctioning, Real-time Response may not work properly and/or the uninstallation may not succeed. Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and 'Real Time Response (Admin): Write'. .PARAMETER QueueOffline Add command request to the offline queue .PARAMETER Include Include additional properties .PARAMETER Id Host identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Uninstall-FalconSensor #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Position=1)] [boolean]$QueueOffline, [Parameter(Position=2)] [ValidateSet('agent_version','cid','external_ip','first_seen','hostname','last_seen','local_ip', 'mac_address','os_build','os_version','platform_name','product_type','product_type_desc', 'serial_number','system_manufacturer','system_product_name','tags',IgnoreCase=$false)] [string[]]$Include, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('HostId','device_id','host_ids','aid')] [string]$Id ) process { try { [string[]]$Select = 'cid','device_id','platform_name','device_policies' if ($Include) { $Select += $Include } $HostList = Get-FalconHost -Id $Id | Select-Object $Select if ($HostList.platform_name -notmatch '^(Windows|Linux)$') { throw 'Only Windows and Linux hosts are currently supported for uninstallation using PSFalcon.' } [string]$Filename = if ($Platform -eq 'Linux') { 'uninstall_sensor.sh' } else { 'uninstall_sensor.ps1' } [string]$Script = Get-Content (Join-Path (Join-Path (Show-FalconModule).ModulePath 'script') $Filename) -Raw $Param = @{ Command = 'runscript' Argument = '-Raw=```{0}```' -f $Script Timeout = 120 QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } } [string]$IdValue = switch ($HostList.device_policies.sensor_update.uninstall_protection) { 'ENABLED' { $HostList.device_id } 'MAINTENANCE_MODE' { 'MAINTENANCE' } } if ($IdValue) { [string]$Token = ($IdValue | Get-FalconUninstallToken -AuditMessage ("Uninstall-FalconSensor [$( (Show-FalconModule).UserAgent)]")).uninstall_token if ($Token) { $Param.Argument += (' -CommandLine=```{0}```' -f $Token) } } $Request = $HostList | Invoke-FalconRtr @Param if ($Request) { [string[]]$Select = 'cid','device_id' if ($Include) { $Select += $Include } @($HostList | Select-Object $Select).foreach{ $Status = if ($Request.stdout) { ($Request.stdout).Trim() } elseif (!$Request.stdout -and $QueueOffline -eq $true) { 'Uninstall request queued' } else { $Request.stderr } Set-Property $_ 'status' $Status $_ } } } catch { throw $_ } } } |