diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8813f681 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +update_check.json diff --git a/PSFalcon.psd1 b/PSFalcon.psd1 index 754d594e..dae618c1 100644 --- a/PSFalcon.psd1 +++ b/PSFalcon.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSFalcon.psm1' - ModuleVersion = '2.2.6' + ModuleVersion = '2.2.7' CompatiblePSEditions = @('Desktop','Core') GUID = 'd893eb9f-f6bb-4a40-9caf-aaff0e42acd1' Author = 'Brendan Kremian' @@ -23,42 +23,86 @@ 'Send-FalconSampleArchive' # cloud-connect-cspm-aws - 'Edit-FalconHorizonAwsAccount' - 'Get-FalconHorizonAwsAccount' - 'Get-FalconHorizonAwsLink' - 'New-FalconHorizonAwsAccount' - 'Receive-FalconHorizonAwsScript' - 'Remove-FalconHorizonAwsAccount' + 'Edit-FalconCloudAwsAccount' + 'Get-FalconCloudAwsAccount' + 'Get-FalconCloudAwsLink' + 'New-FalconCloudAwsAccount' + 'Receive-FalconCloudAwsScript' + 'Remove-FalconCloudAwsAccount' # cloud-connect-cspm-azure - 'Edit-FalconHorizonAzureAccount' - 'Get-FalconHorizonAzureAccount' - 'Get-FalconHorizonAzureCertificate' - 'New-FalconHorizonAzureAccount' - 'Receive-FalconHorizonAzureScript' - 'Remove-FalconHorizonAzureAccount' + 'Edit-FalconCloudAzureAccount' + 'Get-FalconCloudAzureAccount' + 'Get-FalconCloudAzureCertificate' + 'Get-FalconCloudAzureGroup' + 'New-FalconCloudAzureAccount' + 'New-FalconCloudAzureGroup' + 'Receive-FalconCloudAzureScript' + 'Remove-FalconCloudAzureAccount' + 'Remove-FalconCloudAzureGroup' + + # cloud-connect-cspm-gcp + 'Edit-FalconCloudGcpAccount' + 'Edit-FalconCloudGcpServiceAccount' + 'Get-FalconCloudGcpAccount' + 'Get-FalconCloudGcpServiceAccount' + 'Invoke-FalconCloudGcpHealthCheck' + 'New-FalconCloudGcpAccount' + 'Receive-FalconCloudGcpScript' + 'Remove-FalconCloudGcpAccount' + 'Test-FalconCloudGcpServiceAccount' # configuration-assessment 'Get-FalconConfigAssessment' 'Get-FalconConfigAssessmentLogic' + 'Get-FalconConfigAssessmentRule' # container-security + 'Edit-FalconContainerPolicy' + 'Edit-FalconContainerPolicyGroup' 'Edit-FalconContainerRegistry' + 'Get-FalconContainer' + 'Get-FalconContainerAlert' 'Get-FalconContainerAssessment' + 'Get-FalconContainerDeployment' + 'Get-FalconContainerDetection' + 'Get-FalconContainerCluster' + 'Get-FalconContainerCount' + 'Get-FalconContainerDriftIndicator' + 'Get-FalconContainerImage' + 'Get-FalconContainerIom' + 'Get-FalconContainerNode' + 'Get-FalconContainerPackage' + 'Get-FalconContainerPod' + 'Get-FalconContainerPolicy' + 'Get-FalconContainerPolicyExclusion' + 'Get-FalconContainerPolicyGroup' 'Get-FalconContainerRegistry' 'Get-FalconContainerSensor' + 'Get-FalconContainerVulnerability' + 'New-FalconContainerImage' + 'New-FalconContainerPolicy' + 'New-FalconContainerPolicyExclusion' + 'New-FalconContainerPolicyGroup' 'New-FalconContainerRegistry' + 'Remove-FalconContainerImage' 'Remove-FalconContainerRegistry' + 'Remove-FalconContainerPolicy' + 'Remove-FalconContainerPolicyGroup' 'Remove-FalconRegistryCredential' 'Request-FalconRegistryCredential' - 'Remove-FalconContainerImage' + 'Set-FalconContainerPolicyPrecedence' 'Show-FalconRegistryCredential' + # delivery-settings + 'Get-FalconChannelControl' + 'Set-FalconChannelControl' + # detects 'Edit-FalconDetection' 'Get-FalconDetection' - 'Get-FalconHorizonIoa' - 'Get-FalconHorizonIom' + 'Get-FalconCloudIoa' + 'Get-FalconCloudIom' # devices 'Add-FalconGroupingTag' @@ -78,6 +122,13 @@ # enrollments 'Invoke-FalconMobileAction' + # exclusions + 'Edit-FalconCertificateExclusion' + 'Get-FalconCertificate' + 'Get-FalconCertificateExclusion' + 'New-FalconCertificateExclusion' + 'Remove-FalconCertificateExclusion' + # falcon-complete-dashboards 'Get-FalconCompleteAlert' 'Get-FalconCompleteAllowlist' @@ -97,6 +148,9 @@ 'Receive-FalconMemoryDump' 'Remove-FalconReport' + # fem + 'Edit-FalconAsset' + # fdr 'Get-FalconReplicatorEvent' 'Get-FalconReplicatorField' @@ -109,11 +163,15 @@ 'Edit-FalconFileVantagePolicy' 'Edit-FalconFileVantageRule' 'Edit-FalconFileVantageRuleGroup' + 'Get-FalconFileVantageAction' 'Get-FalconFileVantageChange' + 'Get-FalconFileVantageContent' 'Get-FalconFileVantageExclusion' 'Get-FalconFileVantagePolicy' 'Get-FalconFileVantageRule' 'Get-FalconFileVantageRuleGroup' + 'Invoke-FalconFileVantageAction' + 'Invoke-FalconFileVantageWorkflow' 'New-FalconFileVantageExclusion' 'New-FalconFileVantagePolicy' 'New-FalconFileVantageRule' @@ -146,6 +204,17 @@ 'Set-FalconFirewallLocationPrecedence' 'Test-FalconFirewallPath' + # host-migration + 'Get-FalconMigration' + 'Get-FalconMigrationCid' + 'Get-FalconMigrationHost' + 'Invoke-FalconMigrationAction' + 'New-FalconMigration' + 'Start-FalconMigration' + 'Stop-FalconMigration' + 'Rename-FalconMigration' + 'Remove-FalconMigration' + # identity-protection 'Invoke-FalconIdentityGraph' 'Get-FalconIdentityHost' @@ -169,6 +238,7 @@ 'Get-FalconCve' 'Get-FalconIndicator' 'Get-FalconIntel' + 'Get-FalconMalwareFamily' 'Get-FalconRule' 'Receive-FalconAttck' 'Receive-FalconIntel' @@ -184,8 +254,8 @@ 'Remove-FalconInstallToken' # ioa - 'Get-FalconHorizonIoaEvent' - 'Get-FalconHorizonIoaUser' + 'Get-FalconCloudIoaEvent' + 'Get-FalconCloudIoaUser' # ioarules 'Edit-FalconIoaGroup' @@ -221,7 +291,6 @@ 'Get-FalconContainerAzureScript' 'Get-FalconContainerAzureTenant' 'Get-FalconContainerCloud' - 'Get-FalconContainerCluster' 'Get-FalconContainerScript' 'Invoke-FalconContainerScan' 'New-FalconContainerAwsAccount' @@ -231,6 +300,11 @@ 'Remove-FalconContainerAwsAccount' 'Remove-FalconContainerAzureAccount' + # loggingapi + 'Get-FalconFoundryRepository' + 'Get-FalconFoundrySearch' + 'Get-FalconFoundryView' + # malquery 'Get-FalconMalQuery' 'Get-FalconMalQueryQuota' @@ -289,6 +363,9 @@ 'Get-FalconOverWatchDetection' 'Get-FalconOverWatchIncident' + # plugins + 'Get-FalconWorkflowIntegration' + # policy-device-control 'Edit-FalconDeviceControlPolicy' 'Get-FalconDeviceControlPolicy' @@ -381,7 +458,6 @@ 'Show-FalconModule' # psf-policies - 'Compare-FalconPreventionPhase' 'Copy-FalconDeviceControlPolicy' 'Copy-FalconFirewallPolicy' 'Copy-FalconPreventionPolicy' @@ -392,6 +468,7 @@ 'Add-FalconSensorTag' 'Get-FalconSensorTag' 'Remove-FalconSensorTag' + 'Set-FalconSensorTag' 'Uninstall-FalconSensor' # psf-real-time-response @@ -473,16 +550,26 @@ 'Update-FalconStream' # settings - 'Edit-FalconHorizonPolicy' - 'Edit-FalconHorizonSchedule' - 'Get-FalconHorizonPolicy' - 'Get-FalconHorizonSchedule' + 'Edit-FalconCloudPolicy' + 'Edit-FalconCloudSchedule' + 'Get-FalconCloudPolicy' + 'Get-FalconCloudSchedule' + + # snapshots + 'Get-FalconSnapshot' + 'Get-FalconSnapshotScan' + 'New-FalconSnapshotScan' # spotlight 'Get-FalconRemediation' 'Get-FalconVulnerability' 'Get-FalconVulnerabilityLogic' + # threatgraph + 'Get-FalconThreatGraphEdge' + 'Get-FalconThreatGraphIndicator' + 'Get-FalconThreatGraphVertex' + # ti 'Get-FalconTailoredEvent' 'Get-FalconTailoredRule' @@ -497,12 +584,29 @@ 'Remove-FalconRole' 'Remove-FalconUser' + # workflows + 'Export-FalconWorkflow' + 'Get-FalconWorkflow' + 'Get-FalconWorkflowAction' + 'Get-FalconWorkflowInput' + 'Get-FalconWorkflowTrigger' + 'Import-FalconWorkflow' + 'Invoke-FalconWorkflow' + 'Redo-FalconWorkflow' + # zero-trust-assessment 'Get-FalconZta' ) CmdletsToExport = @() VariablesToExport = '*' - AliasesToExport = @('Get-FalconFimChange') + AliasesToExport = @('Edit-FalconHorizonAwsAccount','Edit-FalconHorizonAzureAccount','Edit-FalconHorizonPolicy', + 'Edit-FalconHorizonSchedule','Get-FalconFimChange','Get-FalconHorizonAwsAccount','Get-FalconHorizonAwsLink', + 'Get-FalconHorizonAzureAccount','Get-FalconHorizonAzureCertificate','Get-FalconHorizonAzureGroup', + 'Get-FalconHorizonIoa','Get-FalconHorizonIoaEvent','Get-FalconHorizonIoaUser','Get-FalconHorizonIom', + 'Get-FalconHorizonPolicy','Get-FalconHorizonSchedule','New-FalconHorizonAwsAccount', + 'New-FalconHorizonAzureAccount','New-FalconHorizonAzureGroup','Receive-FalconHorizonAwsScript', + 'Receive-FalconHorizonAzureScript','Remove-FalconHorizonAwsAccount','Remove-FalconHorizonAzureAccount', + 'Remove-FalconHorizonAzureGroup') PrivateData = @{ PSData = @{ Tags = @('CrowdStrike','Falcon','OAuth2','REST','API','PSEdition_Desktop','PSEdition_Core', @@ -510,7 +614,7 @@ LicenseUri = 'https://raw.githubusercontent.com/crowdstrike/psfalcon/master/LICENSE' ProjectUri = 'https://github.com/crowdstrike/psfalcon' IconUri = 'https://raw.githubusercontent.com/crowdstrike/psfalcon/master/icon.png' - ReleaseNotes = 'https://github.com/crowdstrike/psfalcon/releases/tag/2.2.6' + ReleaseNotes = 'https://github.com/crowdstrike/psfalcon/releases/tag/2.2.7' } } } \ No newline at end of file diff --git a/PSFalcon.psm1 b/PSFalcon.psm1 index 0f6b3df9..6b6792ba 100644 --- a/PSFalcon.psm1 +++ b/PSFalcon.psm1 @@ -1,8 +1,10 @@ @( # Import class, public and private functions - Get-ChildItem -Path $PSScriptRoot\class\Class.ps1 - Get-ChildItem -Path $PSScriptRoot\private\Private.ps1 - Get-ChildItem -Path $PSScriptRoot\public\*.ps1 + Get-ChildItem -Path (Join-Path (Join-Path $PSScriptRoot class) Class.ps1) + Get-ChildItem -Path (Join-Path (Join-Path $PSScriptRoot private) Private.ps1) + Get-ChildItem -Path (Join-Path (Join-Path $PSScriptRoot public) *.ps1) ).foreach{ try { . $_.FullName } catch { throw $_ } -} \ No newline at end of file +} +# Check for available module update from PowerShell Gallery +Invoke-UpdateCheck $PSScriptRoot \ No newline at end of file diff --git a/class/Class.ps1 b/class/Class.ps1 index cc19360b..034461b9 100644 --- a/class/Class.ps1 +++ b/class/Class.ps1 @@ -2,10 +2,13 @@ class ApiClient { [System.Net.Http.HttpClientHandler]$Handler [System.Net.Http.HttpClient]$Client [System.Collections.Hashtable]$Collector + [string]$UserAgent ApiClient() { + $this.Collector = $null $this.Handler = [System.Net.Http.HttpClientHandler]::New() $this.Client = [System.Net.Http.HttpClient]::New($this.Handler) - $this.Collector = $null + $this.Client.Timeout = [System.TimeSpan]::New(0,1,0) + $this.UserAgent = 'crowdstrike-psfalcon/2.2.7' } [string] Path([string]$Path) { $Output = if (![IO.Path]::IsPathRooted($Path)) { @@ -33,10 +36,9 @@ class ApiClient { # Create Formdata message $Message.Content = [System.Net.Http.MultipartFormDataContent]::New() $Param.Formdata.GetEnumerator().foreach{ - $Verbose = if ($_.Key -match '^(file|upfile)$') { + $Verbose = if ($_.Key -match '^((data_)?file|upfile)$') { # With 'file' or 'upfile', create StreamContent from key/value pair - $FileStream = [System.IO.FileStream]::New($this.Path($_.Value), - [System.IO.FileMode]::Open) + $FileStream = [System.IO.FileStream]::New($this.Path($_.Value),[System.IO.FileMode]::Open) $Filename = [System.IO.Path]::GetFileName($this.Path($_.Value)) $StreamContent = [System.Net.Http.StreamContent]::New($FileStream) $FileType = $this.StreamType($Filename) @@ -70,11 +72,13 @@ class ApiClient { # Send request $this.Client.SendAsync($Message,[System.Net.Http.HttpCompletionOption]::ResponseHeadersRead) } - if ($Param.Outfile -and $Request) { + if ($Request -and $Param.Outfile) { try { - # When file download is complete, direct to 'Outfile' - $this.Verbose('ApiClient.Invoke',"Creating '$($Param.Outfile)'.") - [System.IO.File]::WriteAllBytes($this.Path($Param.Outfile),$Request.Result) + # Download file to provided 'OutFile' path and display file information when successful + $LocalPath = $this.Path($Param.Outfile) + $this.Verbose('ApiClient.Invoke',"Creating '$LocalPath'.") + [System.IO.File]::WriteAllBytes($LocalPath,$Request.Result) + if (Test-Path $LocalPath) { Get-ChildItem $LocalPath | Select-Object FullName,Length,LastWriteTime } } catch { throw $_ } finally { @@ -82,15 +86,15 @@ class ApiClient { if ($this.Client.DefaultRequestHeaders.$_) { [void]($this.Client.DefaultRequestHeaders.Remove($_)) } } } - } elseif ($Request.Result.StatusCode) { + } elseif ($Request) { # Output HTTP response code to verbose stream - $HashCode = $Request.Result.StatusCode.GetHashCode() - $this.Verbose('ApiClient.Invoke',($HashCode,$Request.Result.StatusCode -join ': ')) + $HashCode = if ($Request.Result.StatusCode) { $Request.Result.StatusCode.GetHashCode() } + if ($HashCode) { $this.Verbose('ApiClient.Invoke',($HashCode,$Request.Result.StatusCode -join ': ')) } if ($Request.Result.Headers) { # Output response headers to verbose stream and warn when 'X-Api-Deprecation' appears $this.Verbose('ApiClient.Invoke',"$($Request.Result.Headers.GetEnumerator().foreach{ @($_.Key,(@($_.Value) -join ', ')) -join '=' } -join ', ')") - @($Request.Result.Headers.GetEnumerator().Where({ $_.Key -match '^X-Api-Deprecation' })).foreach{ + @($Request.Result.Headers.GetEnumerator().Where({$_.Key -match '^X-Api-Deprecation'})).foreach{ Write-Warning ([string]$_.Key,[string]$_.Value -join ': ') } } @@ -100,14 +104,14 @@ class ApiClient { } $RetryAfter = if ($HashCode -eq 429 -and $Param.Path -notmatch '/oauth2/token$') { # Capture 'X-Ratelimit-Retryafter' when present - $Request.Result.Headers.GetEnumerator().Where({ $_.Key -eq 'X-Ratelimit-Retryafter' }).Value + $Request.Result.Headers.GetEnumerator().Where({$_.Key -eq 'X-Ratelimit-Retryafter'}).Value } if ($RetryAfter) { # Subtract current time from 'X-Ratelimit-Retryafter', warn, and retry when rate limited [int32]$Wait = (([System.DateTimeOffset]::FromUnixTimeSeconds($RetryAfter)).LocalDateTime - (Get-Date)).Seconds - $Limit = $Request.Result.Headers.GetEnumerator().Where({ $_.Key -eq 'X-Ratelimit-Limit' }).Value - $Remaining = $Request.Result.Headers.GetEnumerator().Where({ $_.Key -eq 'X-Ratelimit-Remaining' }).Value + $Limit = $Request.Result.Headers.GetEnumerator().Where({$_.Key -eq 'X-Ratelimit-Limit'}).Value + $Remaining = $Request.Result.Headers.GetEnumerator().Where({$_.Key -eq 'X-Ratelimit-Remaining'}).Value Write-Warning ('Rate limited for {0} second(s). [{1}, {2}]' -f $Wait,('Limit',$Limit -join '='), ('Remaining',$Remaining -join '=')) Start-Sleep -Seconds $Wait @@ -133,49 +137,98 @@ class ApiClient { return $Output } [void] Log([System.Object]$Object) { - # Create LogScale message payload from 'HttpRequestMessage' or 'HttpResponseMessage' - $Item = @{ timestamp = Get-Date -Format o; attributes = @{ Headers = @{} }} - if ($Object -is [System.Net.Http.HttpRequestMessage]) { - @('RequestUri','Method').foreach{ $Item.attributes[$_] = $Object.$_.ToString() } - $Object.Headers.GetEnumerator().Where({ $_.Key -ne 'Authorization' }).foreach{ - $Item.attributes.Headers[$_.Key] = $_.Value + # Create Falcon LogScale/NGSIEM message payload from 'HttpRequestMessage' or 'HttpResponseMessage' + $Timestamp = if ($this.Collector.Token -match '^[a-fA-F0-9]{32}$') { + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + } else { + Get-Date -Format o + } + if ($this.Collector.Token -match '^[a-fA-F0-9]{32}$') { + $Item = @{ + event = @{ + '@timestamp' = $Timestamp + '@sourcetype' = $this.UserAgent + '#ecs.version' = '8.11.0' + '#Cps.version' = '1.0.0' + 'Parser.version' = '1.0.0' + } } - if ($Object.Content) { - # Redact 'client_secret' from request - $Item.attributes['Content'] = $Object.Content.ReadAsStringAsync().Result -replace 'client_secret=\w+&?', - 'client_secret=redacted' + if ($Object -is [System.Net.Http.HttpRequestMessage]) { + # Add request URI, method and headers (without 'authorization') + $Item.event['url.full'] = $Object.RequestUri.ToString() + $Item.event['http.request.method'] = $Object.Method.ToString() + $Item.event['http.request.headers'] = @{} + $Object.Headers.GetEnumerator().Where({$_.Key -ne 'Authorization'}).foreach{ + $Item.event.'http.request.headers'[$_.Key] = $_.Value + } + if ($Object.Content) { + # Redact 'client_secret' from request + $Item.event['http.request.body.content'] = + $Object.Content.ReadAsStringAsync().Result -replace 'client_secret=\w+&?','client_secret=redacted' + } + } elseif ($Object -is [System.Net.Http.HttpResponseMessage]) { + $Item.event['http.response.headers'] = @{} + $Object.Headers.GetEnumerator().foreach{ $Item.event.'http.response.headers'[$_.Key] = $_.Value } + if ($Object.Content -and ($Object.Content.Headers.ContentType -eq 'application/json' -or + $Object.Content.Headers.ContentType.MediaType -eq 'application/json')) { + # Add response content (excluding 'access_token') + $Content = @{} + @(($Object.Content.ReadAsStringAsync().Result | ConvertFrom-Json).PSObject.Properties).Where({ + $_.Name -ne 'access_token'}).foreach{ $Content[$_.Name] = $_.Value } + $Item.event['http.response.body.content'] = $Content + } elseif ($Object.Content) { + # Add content as a string when unable to determine if 'HttpRequestMessage' or 'HttpResponseMessage' + $Item.event['http.response.body.content'] = $Object.Content.ReadAsStringAsync().Result + } } - } elseif ($Object -is [System.Net.Http.HttpResponseMessage]) { - $Object.Headers.GetEnumerator().foreach{ $Item.attributes.Headers[$_.Key] = $_.Value } - if ($Object.Content -and ($Object.Content.Headers.ContentType -eq 'application/json' -or - $Object.Content.Headers.ContentType.MediaType -eq 'application/json')) { - @(($Object.Content.ReadAsStringAsync().Result | ConvertFrom-Json).PSObject.Properties).Where({ - $_.Name -ne 'access_token' }).foreach{ - # Add content, but exclude 'access_token' - $Item.attributes[$_.Name] = $_.Value - } - } elseif ($Object.Content) { - # Add content as a string when unable to determine if 'HttpRequestMessage' or 'HttpResponseMessage' - $Item.attributes['Content'] = $Object.Content.ReadAsStringAsync().Result + } else { + $Item = @{ timestamp = $Timestamp; attributes = @{ Headers = @{} }} + if ($Object -is [System.Net.Http.HttpRequestMessage]) { + @('RequestUri','Method').foreach{ $Item.attributes[$_] = $Object.$_.ToString() } + $Object.Headers.GetEnumerator().Where({$_.Key -ne 'Authorization'}).foreach{ + $Item.attributes.Headers[$_.Key] = $_.Value + } + if ($Object.Content) { + # Redact 'client_secret' from request + $Item.attributes['Content'] = $Object.Content.ReadAsStringAsync().Result -replace 'client_secret=\w+&?', + 'client_secret=redacted' + } + } elseif ($Object -is [System.Net.Http.HttpResponseMessage]) { + $Object.Headers.GetEnumerator().foreach{ $Item.attributes.Headers[$_.Key] = $_.Value } + if ($Object.Content -and ($Object.Content.Headers.ContentType -eq 'application/json' -or + $Object.Content.Headers.ContentType.MediaType -eq 'application/json')) { + @(($Object.Content.ReadAsStringAsync().Result | ConvertFrom-Json).PSObject.Properties).Where({ + $_.Name -ne 'access_token'}).foreach{ + # Add content, but exclude 'access_token' + $Item.attributes[$_.Name] = $_.Value + } + } elseif ($Object.Content) { + # Add content as a string when unable to determine if 'HttpRequestMessage' or 'HttpResponseMessage' + $Item.attributes['Content'] = $Object.Content.ReadAsStringAsync().Result + } } } - # Use Invoke-RestMethod to send to LogScale within a background job + # Use Invoke-RestMethod to send to Falcon LogScale/NGSIEM within a background job $Job = @{ - Name = 'ApiClient_Log',$Item.timestamp -join '.' + Name = 'ApiClient_Log',$Timestamp -join '.' ScriptBlock = { $Param = $args[0]; Invoke-RestMethod @Param } ArgumentList = @{ Uri = $this.Collector.Uri Method = 'post' Headers = @{ Authorization = 'Bearer',$this.Collector.Token -join ' '; ContentType = 'application/json' } - Body = ConvertTo-Json @( - @{ - tags = @{ - host = [System.Net.Dns]::GetHostName() - source = $this.Client.DefaultRequestHeaders.UserAgent.ToString() + Body = if ($this.Collector.Token -match '^[a-fA-F0-9]{32}') { + ConvertTo-Json $Item -Depth 32 -Compress + } else { + ConvertTo-Json @( + @{ + tags = @{ + host = [System.Net.Dns]::GetHostName() + source = $this.UserAgent + } + events = @(,$Item) } - events = @(,$Item) - } - ) -Depth 32 -Compress + ) -Depth 32 -Compress + } } } [void](Start-Job @Job) @@ -193,6 +246,7 @@ class ApiClient { '^(bmp|gif|jp(e?)g|png)$' { "image/$_" } '^(pdf|zip)$' { "application/$_" } '^7z$' { 'application/x-7z-compressed' } + '^(yaml|yml)$' { 'application/yaml' } '^(csv|txt)$' { if ($_ -eq 'txt') { 'text/plain' } else { "text/$_" }} '^doc(x?)$' { if ($_ -match 'x$') { diff --git a/format/format.json b/format/format.json index ab4686a2..6d1a2eed 100644 Binary files a/format/format.json and b/format/format.json differ diff --git a/policy/linux.json b/policy/linux.json deleted file mode 100644 index 13293ed1..00000000 Binary files a/policy/linux.json and /dev/null differ diff --git a/policy/mac.json b/policy/mac.json deleted file mode 100644 index f84d608c..00000000 Binary files a/policy/mac.json and /dev/null differ diff --git a/policy/windows.json b/policy/windows.json deleted file mode 100644 index c62df105..00000000 Binary files a/policy/windows.json and /dev/null differ diff --git a/private/Private.ps1 b/private/Private.ps1 index c437c8f7..3d3fd001 100644 --- a/private/Private.ps1 +++ b/private/Private.ps1 @@ -40,9 +40,9 @@ function Add-Include { foreach ($i in $Output) { $SetParam = @{ Object = if ($i.policy_id) { - @($Object).Where({ $_.id -eq $i.policy_id }) + @($Object).Where({$_.id -eq $i.policy_id}) } else { - @($Object).Where({ $_.id -eq $i.id }) + @($Object).Where({$_.id -eq $i.id}) } Name = $_.Key Value = $i @@ -59,9 +59,9 @@ function Add-Include { # Append all properties from 'Include' $SetParam = @{ Object = if ($i.device_id) { - @($Object).Where({ $_.id -eq $i.device_id }) + @($Object).Where({$_.id -eq $i.device_id}) } else { - @($Object).Where({ $_.id -eq $i.id }) + @($Object).Where({$_.id -eq $i.id}) } Name = $_ Value = $i.$_ @@ -95,7 +95,7 @@ function Build-Content { begin { function Build-Body ($Format,$UserInput) { $Body = @{} - $UserInput.GetEnumerator().Where({ $Format.Body.Values -match $_.Key }).foreach{ + $UserInput.GetEnumerator().Where({$Format.Body.Values -match $_.Key}).foreach{ if ($_.Key -eq 'raw_array') { $RawArray = @($_.Value) } else { @@ -122,15 +122,15 @@ function Build-Content { } else { if (!$Body) { $Body = @{} } if (($Value -is [array] -or $Value -is [string]) -and ($Value | - Get-Member -MemberType Method).Where({ $_.Name -eq 'Normalize' })) { + Get-Member -MemberType Method).Where({$_.Name -eq 'Normalize'})) { # Normalize values to avoid Json conversion errors when 'Get-Content' was used if ($Value -is [array]) { - $Value = [array] ($Value).Normalize() + $Value = [array]($Value).Normalize() } elseif ($Value -is [string]) { $Value = ($Value).Normalize() } } - $Format.Body.GetEnumerator().Where({ $_.Value -eq $Field }).foreach{ + $Format.Body.GetEnumerator().Where({$_.Value -eq $Field}).foreach{ if ($_.Key -eq 'root') { # Add key/value pair directly to 'Body' $Body.Add($Field,$Value) @@ -158,7 +158,7 @@ function Build-Content { } function Build-Formdata ($Format,$UserInput) { $Formdata = @{} - $UserInput.GetEnumerator().Where({ $Format.Formdata -contains $_.Key }).foreach{ + $UserInput.GetEnumerator().Where({$Format.Formdata -contains $_.Key}).foreach{ $Formdata[($_.Key).ToLower()] = if ($_.Key -eq 'content') { $Content = try { # Collect file content as a string @@ -178,8 +178,8 @@ function Build-Content { function Build-Query ($Format,$UserInput) { # Regex pattern for matching 'last [int] days/hours' [regex]$Relative = '([Ll]ast (?\d{1,}) ([Dd]ay[s]?|[Hh]our[s]?))' - [array]$Query = foreach ($Field in $Format.Query.Where({ $UserInput.Keys -contains $_ })) { - foreach ($Value in ($UserInput.GetEnumerator().Where({ $_.Key -eq $Field }).Value)) { + [string[]]$Query = foreach ($Field in $Format.Query.Where({$UserInput.Keys -contains $_})) { + foreach ($Value in ($UserInput.GetEnumerator().Where({$_.Key -eq $Field}).Value)) { if ($Field -eq 'filter' -and $Value -match $Relative) { # Convert 'last [int] days/hours' to Rfc3339 @($Value | Select-String $Relative -AllMatches).foreach{ @@ -190,11 +190,11 @@ function Build-Content { } } } - # Output array of strings to append to 'Path' and HTML-encode '+' - ,"$($Field)=$($Value -replace '\+','%2B')" + # Output array of [string] with URL-encoded values to append to 'Path' + ,($Field,([System.Uri]::EscapeDataString($Value)) -join '=') } } - # Return 'Query' array + # Return 'Query' if ($Query) { $Query } } } @@ -228,7 +228,7 @@ function Build-Content { if ($Format.$_) { $Value = if ($_ -eq 'Outfile') { # Get absolute path for 'OutFile' - $Outfile = $UserInput.GetEnumerator().Where({ $Format.Outfile -eq $_.Key }).Value + $Outfile = $UserInput.GetEnumerator().Where({$Format.Outfile -eq $_.Key}).Value if ($Outfile) { $Script:Falcon.Api.Path($Outfile) } } else { # Get value(s) from each 'Build' function @@ -244,95 +244,105 @@ function Build-Content { if (($Content.Keys | Measure-Object).Count -gt 0) { $Content } } } +function Confirm-CidValue ([string]$String) { + if ($String -match '^[a-fA-F0-9]{32}-\w{2}$') { + # If input matches CID with checksum, strip checksum + ($String.Split('-')[0]).ToLower() + } elseif ($String -match '^[a-fA-F0-9]{32}$') { + # If input matches CID, return CID + $String.ToLower() + } else { + throw "'$String' is not a valid customer identifier value." + } +} function Confirm-Parameter { [CmdletBinding()] [OutputType([boolean])] param( - [Parameter(Mandatory)] - [object]$Object, - [Parameter(Mandatory)] + [Parameter(Mandatory,Position=1)] + [object[]]$Object, + [Parameter(Mandatory,Position=2)] [string]$Command, - [Parameter(Mandatory)] - [string]$Endpoint, - [string[]]$Required, - [string[]]$Allowed, - [string[]]$Content, - [string[]]$Pattern, - [hashtable]$Format + [Parameter(Mandatory,Position=3)] + [string]$Endpoint ) begin { - # Retrieve parameters from target $Endpoint and create object string for error message - $ParamList = @((Get-Command $Command).Parameters.Values).Where({ $_.ParameterSets.Keys -contains $Endpoint }) - [string]$ErrorObject = ConvertTo-Json $Object -Depth 32 -Compress + function Get-ParameterName ([System.Management.Automation.ParameterMetadata]$Parameter) { + # Return parameter name, or first alias when present + if ($Parameter.Aliases) { $Parameter.Aliases[0] } else { $Parameter.Name } + } } process { - [string[]]$Keys = if ($Object -is [hashtable]) { - $Object.Keys - } elseif ($Object -is [PSCustomObject]) { - $Object.PSObject.Members.Where({ $_.MemberType -eq 'NoteProperty' }).Name - } - if ($Required) { - @($Required).foreach{ - # Verify object contains required fields - if ($Keys -notcontains $_) { throw "Missing property '$_'. $ErrorObject" } else { $true } - } - } - if ($Allowed) { - @($Keys).foreach{ - # Error if field is not in allowed list - if ($Allowed -notcontains $_) { throw "Unexpected property '$_'. $ErrorObject" } else { $true } + foreach ($i in $Object) { + # Retrieve parameters from target $Endpoint and create object string for error message + [System.Management.Automation.ParameterMetadata[]]$PmList = @( + (Get-Command $Command).Parameters.Values).Where({$_.ParameterSets.Keys -contains $Endpoint}) + [string]$ErrorObject = ConvertTo-Json $i -Depth 32 -Compress + [string[]]$Keys = if ($i -is [hashtable]) { + $i.Keys + } elseif ($i -is [PSCustomObject]) { + $i.PSObject.Members.Where({$_.MemberType -eq 'NoteProperty'}).Name + } else { + throw "Use [hashtable] or [PSCustomObject]." } - } - if ($Content) { - @($Content).foreach{ - # Match property name with parameter name - [string]$Name = if ($Format -and $Format.$_) { $Format.$_ } else { $_ } - if ($Object.$_) { - # Verify that 'ValidValues' contains provided value - [string[]]$ValidValues = @($ParamList).Where({ $_.Name -eq $Name }).Attributes.ValidValues - if ($ValidValues) { - if ($Object.$_ -is [array]) { - foreach ($Item in $Object.$_) { - if ($ValidValues -notcontains $Item) { "'$Item' is not a valid '$_' value. $ErrorObject" } - } - } elseif ($ValidValues -notcontains $Object.$_) { - throw "'$($Object.$_)' is not a valid '$_' value. $ErrorObject" + if ($Keys) { + @($PmList.Where({$_.attributes.Mandatory -eq $true}).foreach{ Get-ParameterName $_ }).foreach{ + # Verify object contains required properties + if ($Keys -notcontains $_) { throw "Missing required property '$_'. $ErrorObject" } else { $true } + } + foreach ($Name in $Keys) { + # Gather parameter detail for each property in object + $Parameter = $PmList.Where({$_.Name -eq $Name -or ($_.Aliases -and @($_.Aliases)[0] -eq $Name )}) + if ($Parameter) { + if ($Parameter.Aliases -and @($Parameter.Aliases)[0] -cne $Name) { + # Error if property is not accurately named for submission + throw "Unexpected property '$Name'. Try '$(@($Parameter.Aliases)[0])'. $ErrorObject" } else { $true } + # Collect 'ValidateSet' values + [string[]]$ValidSet = $Parameter.Attributes.ValidValues + if ($ValidSet) { + if ($i.$Name -and $i.$Name -is [array]) { + foreach ($Value in $i.$Name) { + # Error if array value is not in 'ValidateSet' + if ($ValidSet -cnotcontains $Value) { + throw "'$Value' is not a valid '$Name' value. $ErrorObject" + } else { + $true + } + } + } elseif ($i.$Name -and $ValidSet -cnotcontains $i.$Name) { + # Error if value is not in 'ValidateSet' + throw "'$($i.$Name)' is not a valid '$Name' value. $ErrorObject" + } else { + $true + } + } + # Collect 'ValidatePattern' value + [string]$ValidPattern = $Parameter.attributes.RegexPattern + if ($ValidPattern) { + if ($i.$Name -and $i.$Name -is [array]) { + foreach ($Value in $i.$Name) { + # Error if array value does not match 'ValidatePattern' + if ($Value -notmatch $ValidPattern) { + throw "'$Value' is not a valid '$Name' value. $ErrorObject" + } else { + $true + } + } + $true + } elseif ($i.$Name -and $i.$Name -notmatch $ValidPattern) { + # Error if value does not match 'ValidatePattern' + throw "'$($i.$Name)' is not a valid '$Name' value. $ErrorObject" + } else { + $true + } + } } } } } - if ($Pattern) { - @($Pattern).foreach{ - # Match property name with parameter name - [string]$Name = if ($Format -and $Format.$_) { $Format.$_ } else { $_ } - if ($Object.$_) { - # Verify provided value matches 'ValidPattern' - [string]$ValidPattern = @($ParamList).Where.({ - $_.Name -eq $Name -or $_.Aliases -contains $Name - }).Attributes.RegexPattern - if ($ValidPattern -and $Object.$_ -notmatch $ValidPattern) { - throw "'$($Object.$_)' is not a valid '$_' value. $ErrorObject" - } else { - $true - } - } - } - } - } -} -function Confirm-Property { - [CmdletBinding()] - [OutputType([PSCustomObject[]])] - param([Parameter(Mandatory,Position=1)][string[]]$Property,[Parameter(Position=2)][object[]]$Object) - process { - foreach ($Item in $Object) { - # Filter to defined properties containing values - [string[]]$Select = @($Property).foreach{ if ($Item.$_) { $_ } } - if ($Select) { [PSCustomObject]$Item | Select-Object $Select } - } } } function Convert-Rfc3339 { @@ -371,7 +381,7 @@ function Get-EndpointFormat { # Define endpoint payload/parameters using 'format.json' [string[]]$Array = try { $Endpoint -split ':',2 } catch {} if ($Array) { - @($Script:Falcon.Format.($Array[0]).($Array[1]).PSObject.Properties).Where({ $null -ne $_.Value }).foreach{ + @($Script:Falcon.Format.($Array[0]).($Array[1]).PSObject.Properties).Where({$null -ne $_.Value}).foreach{ $Output[$_.Name] = if ($_.Value -is [PSCustomObject]) { $Value = @{} @($_.Value.PSObject.Properties).foreach{ $Value[$_.Name] = $_.Value } @@ -398,15 +408,15 @@ function Get-ParamSet { # Get baseline switch and endpoint parameters $Switches = @{} if ($UserInput) { - $UserInput.GetEnumerator().Where({ $_.Key -match '^(All|Detailed|Total)$' }).foreach{ + $UserInput.GetEnumerator().Where({$_.Key -match '^(All|Detailed|Total)$'}).foreach{ $Switches.Add($_.Key,$_.Value) } } $Base = @{ Path = if ($HostUrl) { - $HostUrl,$Endpoint.Split(':',2)[0] -join $null + [string]::Concat($HostUrl,$Endpoint.Split(':',2)[0]) } else { - $Script:Falcon.Hostname,$Endpoint.Split(':',2)[0] -join $null + [string]::Concat($Script:Falcon.Hostname,$Endpoint.Split(':',2)[0]) } Method = $Endpoint.Split(':')[1] Headers = $Headers @@ -417,13 +427,27 @@ function Get-ParamSet { $Pmax = ($UserInput.ids | Measure-Object -Maximum -Property Length -EA 0).Maximum if ($Pmax) { [Math]::Floor([decimal](18500/($Pmax + 5))) } } - # Output maximum, no greater than 500 - $Max = if ($IdCount -and $IdCount -lt 500) { $IdCount } else { 500 } + # Output maximum + $Max = if ($IdCount -and $IdCount -lt 500) { + $IdCount + } elseif ($UserInput.composite_ids) { + # Use 1000 for 'composite_ids' + 1000 + } else { + # Default to 500 + 500 + } } # Get 'Content' from user input and find identifier field $Content = Build-Content -UserInput $UserInput -Format $Format [string]$Field = if ($Content.Body) { - if ($Content.Body.ids) { 'ids' } elseif ($Content.Body.samples) { 'samples' } + if ($Content.Body.composite_ids) { + 'composite_ids' + } elseif ($Content.Body.ids) { + 'ids' + } elseif ($Content.Body.samples) { + 'samples' + } } } process { @@ -438,7 +462,7 @@ function Get-ParamSet { } else { "?$($Content.Query[$i..($i + ($Max - 1))] -join '&')" } - $Content.GetEnumerator().Where({ $_.Key -ne 'Query' -and $_.Value }).foreach{ + $Content.GetEnumerator().Where({$_.Key -ne 'Query' -and $_.Value}).foreach{ # Add values other than 'Query' $Split.Endpoint.Add($_.Key,$_.Value) } @@ -451,7 +475,7 @@ function Get-ParamSet { $Split = $Switches.Clone() $Split.Add('Endpoint',$Base.Clone()) $Split.Endpoint.Add('Body',@{ $Field = $Content.Body.$Field[$i..($i + ($Max - 1))] }) - $Content.GetEnumerator().Where({ $_.Value }).foreach{ + $Content.GetEnumerator().Where({$_.Value}).foreach{ # Add values other than 'Body.$Field' if ($_.Key -eq 'Query') { $Split.Endpoint.Path += if ($Split.Endpoint.Path -match '\?') { @@ -460,7 +484,7 @@ function Get-ParamSet { "?$($_.Value -join '&')" } } elseif ($_.Key -eq 'Body') { - ($_.Value).GetEnumerator().Where({ $_.Key -ne $Field }).foreach{ + ($_.Value).GetEnumerator().Where({$_.Key -ne $Field}).foreach{ $Split.Endpoint.Body.Add($_.Key,$_.Value) } } else { @@ -511,26 +535,25 @@ function Get-RtrCommand { @($null,'Responder','Admin').foreach{ $Key = if ($_ -eq $null) { 'ReadOnly' } else { $_ } $Index[$Key] = (Get-Command "Invoke-Falcon$($_)Command").Parameters.GetEnumerator().Where({ - $_.Key -eq 'Command' }).Value.Attributes.ValidValues + $_.Key -eq 'Command'}).Value.Attributes.ValidValues } # Filter 'Responder' and 'Admin' to unique command(s) - $Index.Responder = @($Index.Responder).Where({ $Index.ReadOnly -notcontains $_ }) - $Index.Admin = @($Index.Admin).Where({ $Index.ReadOnly -notcontains $_ -and $Index.Responder -notcontains - $_ }) + $Index.Responder = @($Index.Responder).Where({$Index.ReadOnly -notcontains $_}) + $Index.Admin = @($Index.Admin).Where({$Index.ReadOnly -notcontains $_ -and $Index.Responder -notcontains $_}) if ($Command) { # Determine command to invoke using $Command and permission level [string]$Result = if ($Command -eq 'runscript') { # Force 'Admin' for 'runscript' command 'Invoke-FalconAdminCommand' } else { - $Index.GetEnumerator().Where({ $_.Value -contains $Command }).foreach{ + $Index.GetEnumerator().Where({$_.Value -contains $Command}).foreach{ if ($_.Key -eq 'ReadOnly') { 'Invoke-FalconCommand' } else { "Invoke-Falcon$($_.Key)Command" } } } if ($ConfirmCommand) { $Result -replace 'Invoke','Confirm' } else { $Result } } elseif ($Permission) { # Return available Real-time Response commands by permission - $Index.GetEnumerator().Where({ $Permission -contains $_.Key }).Value + $Index.GetEnumerator().Where({$Permission -contains $_.Key}).Value } else { # Return all available Real-time Response commands @($Index.Values).foreach{ $_ } @@ -549,7 +572,7 @@ function Get-RtrResult { process { foreach ($Result in $Object) { # Update 'Output' with populated result(s) from 'Object' - @($Result.PSObject.Properties).Where({ $RtrFields -contains $_.Name }).foreach{ + @($Result.PSObject.Properties).Where({$RtrFields -contains $_.Name}).foreach{ $Name = if ($_.Name -eq 'task_id') { # Rename 'task_id' to 'cloud_request_id' 'cloud_request_id' @@ -571,7 +594,7 @@ function Get-RtrResult { # Update 'Output' with result using 'aid' or 'session_id' $Match = if ($Result.aid) { 'aid' } else { 'session_id' } if ($Result.$Match) { - @($Output).Where({ $Result.$Match -eq $_.$Match }).foreach{ Set-Property $_ $Name $Value } + @($Output).Where({$Result.$Match -eq $_.$Match}).foreach{ Set-Property $_ $Name $Value } } } } @@ -589,7 +612,8 @@ function Invoke-Falcon { [switch]$RawOutput, [int32]$Max, [string]$HostUrl, - [switch]$BodyArray + [switch]$BodyArray, + [string]$JsonBody ) begin { function Invoke-Loop ([hashtable]$Splat,[object]$Object,[int]$Int) { @@ -637,7 +661,7 @@ function Invoke-Falcon { $Current = [regex]::Match($Clone.Endpoint.Path,'offset=(\d+)(^&)?').Captures.Value $Next[1] += [int]$Current.Split('=')[-1] $Clone.Endpoint.Path -replace $Current,($Next -join '=') - } elseif ($Clone.Endpoint.Path -match "$($Splat.Endpoint)^" -and $Clone.Endpoint.Path -notmatch '\?') { + } elseif ($Clone.Endpoint.Path -eq $Splat.Endpoint.Path -and $Clone.Endpoint.Path -notmatch '\?') { # Add pagination $Clone.Endpoint.Path,($Next -join '=') -join '?' } else { @@ -670,9 +694,9 @@ function Invoke-Falcon { # Add 'Format' using 'format.json' when not supplied if (!$PSBoundParameters.Format) { $PSBoundParameters['Format'] = Get-EndpointFormat $Endpoint } # Gather request parameters and split into groups - [string[]]$Exclude = 'BodyArray','Command','RawOutput' + [string[]]$Exclude = 'BodyArray','Command','JsonBody','RawOutput' $GetParam = @{} - $PSBoundParameters.GetEnumerator().Where({ $Exclude -notcontains $_.Key }).foreach{ + $PSBoundParameters.GetEnumerator().Where({$Exclude -notcontains $_.Key}).foreach{ $GetParam.Add($_.Key,$_.Value) } # Add 'Accept: application/json' when undefined @@ -684,15 +708,19 @@ function Invoke-Falcon { } if ($UserInput.All -eq $true -and !$UserInput.Limit) { # Add maximum 'Limit' when not present and using 'All' - $Limit = (Get-Command $Command).ParameterSets.Where({ - $_.Name -eq $Endpoint }).Parameters.Where({ $_.Name -eq 'Limit' }).Attributes.MaxRange + $Limit = (Get-Command $Command).ParameterSets.Where({$_.Name -eq $Endpoint}).Parameters.Where({ + $_.Name -eq 'Limit'}).Attributes.MaxRange if ($Limit) { $UserInput.Add('Limit',$Limit) } } } process { Get-ParamSet @GetParam | ForEach-Object { [string]$Operation = $_.Endpoint.Method.ToUpper() - if ($_.Endpoint.Headers.ContentType -eq 'application/json' -and $_.Endpoint.Body) { + if ($JsonBody) { + # Add 'JsonBody' directly as the request body, when present + $_.Endpoint['Body'] = $JsonBody + if (!$_.Endpoint.Headers.ContentType) { $_.Endpoint.Headers.Add('ContentType','application/json') } + } elseif ($_.Endpoint.Headers.ContentType -eq 'application/json' -and $_.Endpoint.Body) { $_.Endpoint.Body = if ($BodyArray) { # Force Json array when 'BodyArray' is present ConvertTo-Json @($_.Endpoint.Body) -Depth 32 -Compress @@ -707,10 +735,7 @@ function Invoke-Falcon { try { Write-Log $Command $Endpoint $Request = $Script:Falcon.Api.Invoke($_.Endpoint) - if ($_.Endpoint.Outfile -and (Test-Path $_.Endpoint.Outfile)) { - # Display 'Outfile' - Get-ChildItem $_.Endpoint.Outfile | Select-Object FullName,Length,LastWriteTime - } elseif ($Request -and $RawOutput) { + if ($Request -and $RawOutput) { # Return result if 'RawOutput' is defined $Request } elseif ($Request) { @@ -738,6 +763,69 @@ function Invoke-Falcon { } } } +function Invoke-UpdateCheck { + param( + [Parameter(Mandatory,Position=1)] + [string]$BasePath + ) + function Write-UpdateJson { + param( + [Parameter(Mandatory,Position=1)] + [string]$Path, + [Parameter(Mandatory,Position=2)] + [boolean]$Connection, + [Parameter(Mandatory,Position=3)] + [int64]$Timestamp, + [Parameter(Mandatory,Position=4)] + [string]$Version + ) + # Create Json with update check information + [PSCustomObject]@{ + psgallery_connection = $Connection + timestamp = $Timestamp + version = $Version + } | ConvertTo-Json -Compress > $Path + Write-Log 'Invoke-UpdateCheck' ('Created "{0}"' -f $Path) + } + function Write-VersionWarning ([string]$String) { + # Write warning message notifying that a new release is available + Write-Warning ('PSFalcon is out of date. Release v{0} is available on the PowerShell Gallery.' -f $String) + } + # Check for available module update + $Current = try { (Show-FalconModule).ModuleVersion.Split(' ',2)[0] -replace '^v',$null } catch { $null } + if ($Current) { + # Create 'update_check.json' if it doesn't exist, then import 'update_check.json' + $JsonPath = Join-Path $BasePath update_check.json + $WeekAgo = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() - 604800000 + if (!(Test-Path -Path $JsonPath)) { + # Determine if PowerShell Gallery was used for initial installation + $Connection = if (Get-Command -Name Get-InstalledModule -EA 0) { + if ((Get-InstalledModule -Name PSFalcon -EA 0).Repository -eq 'PSGallery') { $true } else { $false } + } else { + $false + } + Write-UpdateJson $JsonPath $Connection $WeekAgo $Current + } + $Json = try { Get-Content -Path $JsonPath -EA 0 | ConvertFrom-Json -EA 0 } catch { $null } + if ($Json -and $Json.psgallery_connection -eq $true -and $Json.timestamp -and $Json.version) { + if ($Current -lt $Json.version) { + # Notify that a new release is available + Write-VersionWarning $Json.version + } elseif ($WeekAgo -lt $Json.timestamp) { + # Check PowerShell Gallery every 7 days + $Gallery = try { Find-Module -Name PSFalcon -Repository PSGallery -EA 0 } catch { $null } + $Timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + if (!$Gallery) { + # Create new Json when PowerShell Gallery connection fails + Write-UpdateJson $JsonPath $false $Timestamp $Current + } elseif ($Gallery -and $Gallery.Version) { + # Create new Json with PowerShell Gallery version information + Write-UpdateJson $JsonPath $true $Timestamp $Gallery.Version.ToString() + } + } + } + } +} function New-ShouldMessage { [CmdletBinding()] [OutputType([string[]])] @@ -781,6 +869,43 @@ function New-ShouldMessage { } catch {} } } +function Remove-EmptyValue { + param( + [object]$Object, + [string[]]$String + ) + foreach ($i in $Object.PSObject.Properties.Name) { + if (($Object.$i | Measure-Object).Count -gt 1) { + # Remove empty sub-properties + @($Object.$i).foreach{ Remove-EmptyValue $_ } + } + if ($String -notcontains $i -and [string]::IsNullOrEmpty($Object.$i)) { + # Remove empty properties, except those defined by 'String' + [void]$Object.PSObject.Properties.Remove($i) + } + } +} +function Select-CertificateProperty { + [CmdletBinding()] + [OutputType([PSCustomObject])] + param( + [Parameter(Mandatory,Position=1)] + [object]$Object + ) + try { + # Select required fields when submitting a certificate for a certificate-based exclusion + [string[]]$Select = 'issuer','serial','subject','thumbprint','valid_from','valid_to' + $Output = [PSCustomObject]$Object | Select-Object $Select + if ($Output) { + @($Select).foreach{ + if (!$Output.$_ -or $null -eq $Output.$_) { throw "Certificate missing required property '$_'." } + } + $Output + } + } catch { + throw $_ + } +} function Select-Property { [CmdletBinding()] param( @@ -966,7 +1091,7 @@ function Stop-RtrUpdate { } } } - @(Get-Job).Where({ $_.Name -match '^psfalcon-rtr_' -and $_.State -eq 'Completed' }).foreach{ + @(Get-Job).Where({$_.Name -match '^psfalcon-rtr_' -and $_.State -eq 'Completed'}).foreach{ # Remove 'Completed' background jobs Remove-Job -Id $_.Id if (Get-Job -Id $_.Id -EA 0) { @@ -977,6 +1102,36 @@ function Stop-RtrUpdate { } } } +function Test-ActionParameter { + [CmdletBinding()] + [OutputType([hashtable])] + param( + [hashtable]$Hashtable, + [string[]]$String, + [switch]$Incident + ) + if ($Hashtable) { + $Hashtable.GetEnumerator().foreach{ + if ($String -and $String -notcontains $_.Key) { + # Verify that each 'Action' is using a valid 'name' + throw ('"{0}" is not a valid action name.' -f $_.Key) + } elseif ($_.Key -eq 'update_status') { + if ($Incident -and $_.Value -match '^(20|new|25|reopened|30|in_progress|40|closed)$') { + # Verify that 'update_status' is using a proper string value when working with incidents + $_.Value = switch -Regex ($_.Value) { + '20|new' { '20' } + '25|reopened' { '25' } + '30|in_progress' { '30' } + '40|closed' { '40' } + } + } elseif ($_.Value -notmatch '^(new|reopened|in_progress|closed)$') { + throw "Valid values for 'update_status': 'closed', 'in_progress', 'new', 'reopened'." + } + } + return @{ name = $_.Key; value = $_.Value } + } + } +} function Test-FqlStatement { [CmdletBinding()] [OutputType([boolean])] @@ -1096,8 +1251,8 @@ function Wait-RtrGet { } $_ } - if ($Object.Where({ !$_.deleted_at -and $_.complete -eq $false })) { Start-Sleep -Seconds 20 } - } while ($Object.Where({ !$_.deleted_at -and $_.complete -eq $false })) + if ($Object.Where({!$_.deleted_at -and $_.complete -eq $false})) { Start-Sleep -Seconds 20 } + } while ($Object.Where({!$_.deleted_at -and $_.complete -eq $false})) } } end { $Object } @@ -1118,12 +1273,12 @@ function Write-Result { }) -join ', ' Write-Log 'Write-Result' ($Message -join ' ') } - if ($Json.PSObject.Properties.Where({ $_.Name -ne 'meta' -and $null -ne $_.Value }) -or + if ($Json.PSObject.Properties.Where({$_.Name -ne 'meta' -and $null -ne $_.Value}) -or $Json.meta.pagination.total -eq 0 -and !$Json.meta.reqid) { # Remove 'meta' when other sub-properties are populated, or when pagination.total equals 0 [void]$Json.PSObject.Properties.Remove('meta') } - @($Json.PSObject.Properties).Where({ $_.Name -eq 'errors' -and $_.Value }).foreach{ + @($Json.PSObject.Properties).Where({$_.Name -eq 'errors' -and $_.Value}).foreach{ @($_.Value).foreach{ # Output 'errors' to error stream as Json string $PSCmdlet.WriteError( diff --git a/public/alerts.ps1 b/public/alerts.ps1 index 12adf939..85f23ed0 100644 --- a/public/alerts.ps1 +++ b/public/alerts.ps1 @@ -6,6 +6,8 @@ Search for alerts Requires 'Alerts: Read'. .PARAMETER Id Alert identifier +.PARAMETER IncludeHidden +Include hidden alerts when retrieving results by identifier .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Query @@ -25,40 +27,47 @@ Display total result count instead of results .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconAlert #> - [CmdletBinding(DefaultParameterSetName='/alerts/queries/alerts/v1:get',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/alerts/queries/alerts/v2:get',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/alerts/entities/alerts/v2:post',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [Alias('composite_ids','composite_id','ids')] [string[]]$Id, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get',Position=1)] + [Parameter(ParameterSetName='/alerts/entities/alerts/v2:post',Position=1)] + [Alias('include_hidden')] + [boolean]$IncludeHidden, + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] [string]$Filter, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get',Position=2)] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get',Position=2)] [Alias('q')] [string]$Query, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get',Position=3)] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get',Position=3)] [string]$Sort, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get',Position=4)] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get',Position=4)] [ValidateRange(1,10000)] [int32]$Limit, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get')] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get')] [int32]$Offset, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get')] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get')] [switch]$Detailed, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get')] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2:get')] [switch]$All, - [Parameter(ParameterSetName='/alerts/queries/alerts/v1:get')] + [Parameter(ParameterSetName='/alerts/queries/alerts/v2: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($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['composite_ids'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Invoke-FalconAlertAction { @@ -71,6 +80,10 @@ Requires 'Alerts: Write'. Action to perform .PARAMETER Value Value for the chosen action +.PARAMETER Action +One or more hashtables defining multiple name/value pairs +.PARAMETER IncludeHidden +Include hidden alerts when performing action [default: $true] .PARAMETER Id Alert identifier .LINK @@ -84,27 +97,42 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconAlertAction [string]$Name, [Parameter(ParameterSetName='/alerts/entities/alerts/v3:patch',Position=2)] [string]$Value, + [Parameter(ParameterSetName='action_parameters',Mandatory,Position=1)] + [Alias('action_parameters')] + [hashtable[]]$Action, + [Parameter(ParameterSetName='/alerts/entities/alerts/v3:patch',Position=3)] + [Parameter(ParameterSetName='action_parameters',Position=2)] + [Alias('include_hidden')] + [boolean]$IncludeHidden, [Parameter(ParameterSetName='/alerts/entities/alerts/v3:patch',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=3)] + [Parameter(ParameterSetName='action_parameters',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline,Position=3)] [Alias('composite_ids','composite_id','ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ Body = @{ root = @('composite_ids','action_parameters') }} + Endpoint = '/alerts/entities/alerts/v3:patch' + Max = 1000 } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) - [hashtable]$Parameters = @{ name = $PSBoundParameters.name } - if ($PSBoundParameters.Value) { $Parameters['value'] = $PSBoundParameters.Value } - $PSBoundParameters['action_parameters'] = @($Parameters) - @('Name','Value').foreach{ [void]$PSBoundParameters.Remove($_) } + $PSBoundParameters['Id'] = @($List) + if ($PSBoundParameters.Action) { + # Verify valid 'Action' key/value pairs and update formatting before request + $Valid = (Get-Command $Param.Command).Parameters.Name.Attributes.ValidValues + [hashtable[]]$PSBoundParameters.Action = @($PSBoundParameters.Action).foreach{ + Test-ActionParameter $_ $Valid + } + $Param.Format.Body.root = @('composite_ids','action_parameters') + [void]$Param.Format.Body.Remove('action_parameters') + } Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/archives.ps1 b/public/archives.ps1 index 17b962e8..c078452c 100644 Binary files a/public/archives.ps1 and b/public/archives.ps1 differ diff --git a/public/cloud-connect-cspm-aws.ps1 b/public/cloud-connect-cspm-aws.ps1 index f39ce95b..9f304dce 100644 --- a/public/cloud-connect-cspm-aws.ps1 +++ b/public/cloud-connect-cspm-aws.ps1 @@ -1,7 +1,7 @@ -function Edit-FalconHorizonAwsAccount { +function Edit-FalconCloudAwsAccount { <# .SYNOPSIS -Modify a Falcon Horizon AWS account +Modify a Falcon Cloud Security AWS account .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER AccountId @@ -18,11 +18,20 @@ Enable sensor management for account Region where remediation occurs .PARAMETER RemediationTouAccepted Remediation terms-of-use acceptance date +.PARAMETER Environment +Environment +.PARAMETER TargetOu +Target OU +.PARAMETER DspmEnabled +DSPM enabled +.PARAMETER DspmRole +DSPM role ARN .LINK -https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonAwsAccount +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconCloudAwsAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', SupportsShouldProcess)] + [Alias('Edit-FalconHorizonAwsAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch',Mandatory, ValueFromPipelineByPropertyName,Position=1)] @@ -31,11 +40,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonAwsAccount [string]$AccountId, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', ValueFromPipelineByPropertyName,Position=2)] - [ValidateSet('af-south-1','ap-east-1','ap-northeast-1','ap-northeast-2','ap-northeast-3','ap-south-1', - 'ap-south-2','ap-southeast-1','ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1', - 'cn-north-1','cn-northwest-1','eu-central-1','eu-central-2','eu-north-1','eu-south-1','eu-south-2', - 'eu-west-1','eu-west-2','eu-west-3','il-central-1','me-central-1','me-south-1','sa-east-1','us-east-1', - 'us-east-2','us-gov-east-1','us-gov-west-1','us-west-1','us-west-2',IgnoreCase=$false)] [Alias('cloudtrail_region')] [string]$CloudtrailRegion, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', @@ -57,15 +61,30 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonAwsAccount [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', ValueFromPipelineByPropertyName,Position=7)] [Alias('remediation_tou_accepted')] - [string]$RemediationTouAccepted + [string]$RemediationTouAccepted, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', + ValueFromPipelineByPropertyName,Position=8)] + [string]$Environment, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', + ValueFromPipelineByPropertyName,Position=10)] + [Alias('target_ous')] + [string[]]$TargetOu, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', + ValueFromPipelineByPropertyName,Position=11)] + [Alias('dspm_enabled')] + [boolean]$DspmEnabled, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:patch', + ValueFromPipelineByPropertyName,Position=12)] + [Alias('dspm_role')] + [string]$DspmRole ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Get-FalconHorizonAwsAccount { +function Get-FalconCloudAwsAccount { <# .SYNOPSIS -Search for Falcon Horizon AWS accounts +Search for Falcon Cloud Security AWS accounts .DESCRIPTION A properly provisioned AWS account will display the status 'Event_DiscoverAccountStatusOperational'. @@ -84,6 +103,8 @@ Field to group by AWS IAM role ARNs .PARAMETER Migrated Only return migrated Discover for Cloud accounts +.PARAMETER CspmLite +Only return CSPM Lite accounts .PARAMETER Limit Maximum number of results per request .PARAMETER Offset @@ -93,15 +114,15 @@ 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-FalconHorizonAwsAccount +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudAwsAccount #> - [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get', - SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonAwsAccount')] param( - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get', - ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',ValueFromPipelineByPropertyName, + ValueFromPipeline)] [ValidatePattern('^\d{12}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',Position=1)] [ValidatePattern('^o-[0-9a-z]{10,32}$')] @@ -124,6 +145,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAwsAccount [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',Position=6)] [boolean]$Migrated, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',Position=7)] + [Alias('cspm_lite')] + [boolean]$CspmLite, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get',Position=8)] [ValidateRange(1,500)] [int32]$Limit, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:get')] @@ -137,33 +161,38 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAwsAccount $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } -function Get-FalconHorizonAwsLink { +function Get-FalconCloudAwsLink { <# .SYNOPSIS -Retrieve a URL to grant Falcon Horizon access in AWS +Retrieve a URL to grant Falcon Cloud Security access in AWS .DESCRIPTION Once logging in to the provided link using your AWS administrator credentials, use the 'Create Stack' button to grant access. Requires 'CSPM registration: Read'. .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAwsLink +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudAwsLink #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/console-setup-urls/v1:get', SupportsShouldProcess)] + [Alias('Get-FalconHorizonAwsLink')] param() - process { Invoke-Falcon -Endpoint $PSCmdlet.ParameterSetName } + process { Invoke-Falcon -Command $MyInvocation.MyCommand.Name -Endpoint $PSCmdlet.ParameterSetName } } -function New-FalconHorizonAwsAccount { +function New-FalconCloudAwsAccount { <# .SYNOPSIS -Provision a Falcon Horizon AWS account +Provision a Falcon Cloud Security AWS account .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER AccountId @@ -184,75 +213,143 @@ Use existing Cloudtrail log Enable behavior assessment for account .PARAMETER SensorManagementEnabled Enable sensor management for account +.PARAMETER TargetOu +Target OU +.PARAMETER DspmEnabled +DSPM enabled +.PARAMETER DspmRole +DSPM role ARN .LINK -https://github.com/crowdstrike/psfalcon/wiki/New-FalconHorizonAwsAccount +https://github.com/crowdstrike/psfalcon/wiki/New-FalconCloudAwsAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post', SupportsShouldProcess)] + [Alias('New-FalconHorizonAwsAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Mandatory,Position=1)] [ValidatePattern('^\d{12}$')] [Alias('account_id')] [string]$AccountId, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Mandatory,Position=2)] - [ValidateSet('af-south-1','ap-east-1','ap-northeast-1','ap-northeast-2','ap-northeast-3','ap-south-1', - 'ap-south-2','ap-southeast-1','ap-southeast-2','ap-southeast-3','ap-southeast-4','ca-central-1', - 'cn-north-1','cn-northwest-1','eu-central-1','eu-central-2','eu-north-1','eu-south-1','eu-south-2', - 'eu-west-1','eu-west-2','eu-west-3','il-central-1','me-central-1','me-south-1','sa-east-1','us-east-1', - 'us-east-2','us-gov-east-1','us-gov-west-1','us-west-1','us-west-2',IgnoreCase=$false)] [Alias('cloudtrail_region')] [string]$CloudtrailRegion, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=3)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=3)] [ValidatePattern('^\d{12}$')] [Alias('organization_id')] [string]$OrganizationId, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=4)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=4)] [Alias('account_type')] [string]$AccountType, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=5)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=5)] [Alias('is_master')] [boolean]$IsMaster, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=6)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=6)] [Alias('iam_role_arn')] [string]$IamRoleArn, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=7)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=7)] [Alias('use_existing_cloudtrail')] [boolean]$UseExistingCloudtrail, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=8)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=8)] [Alias('behavior_assessment_enabled')] [boolean]$BehaviorAssessmentEnabled, - [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',Position=9)] + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=9)] [Alias('sensor_management_enabled')] - [boolean]$SensorManagementEnabled + [boolean]$SensorManagementEnabled, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=10)] + [Alias('target_ous')] + [string[]]$TargetOu, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=11)] + [Alias('dspm_enabled')] + [boolean]$DspmEnabled, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:post',ValueFromPipelineByPropertyName, + Position=12)] + [Alias('dspm_role')] + [string]$DspmRole ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Receive-FalconHorizonAwsScript { +function Receive-FalconCloudAwsScript { <# .SYNOPSIS -Download a Bash script which grants Falcon Horizon access using the AWS CLI +Download a Bash script which grants Falcon Cloud Security access using the AWS CLI .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER Id AWS account identifier +.PARAMETER OrganizationId +AWS organization identifier +.PARAMETER Template +Template to be rendered +.PARAMETER Account +List of AWS accounts to register +.PARAMETER AccountType +Type of account +.PARAMETER AwsProfile +AWS profile to use during registration +.PARAMETER CustomRole +Custom IAM role to be use during registration +.PARAMETER BehaviorAssessment +Enable behavior assessment +.PARAMETER SensorManagement +Enable sensor management +.PARAMETER ExistingCloudtrail +Use existing Cloudtraile .PARAMETER Path Destination path .PARAMETER Force Overwrite existing file when present .LINK -https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconHorizonAwsScript +https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconCloudAwsScript #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get', SupportsShouldProcess)] + [Alias('Receive-FalconHorizonAwsScript')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get', ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^\d{12}$')] [Alias('ids')] [string[]]$Id, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=2)] + [Alias('organization_id')] + [string]$OrganizationId, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=3)] + [ValidateSet('aws-bash','aws-terraform',IgnoreCase=$false)] + [string]$Template, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=4)] + [Alias('accounts')] + [string[]]$Account, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=5)] + [ValidateSet('commercial','gov',IgnoreCase=$false)] + [Alias('account_type')] + [string]$AccountType, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=6)] + [Alias('aws_profile')] + [string]$AwsProfile, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=7)] + [Alias('custom_role_name')] + [string]$CustomRole, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=8)] + [Alias('behavior_assessment_enabled')] + [boolean]$BehaviorAssessment, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=9)] + [Alias('sensor_management_enabled')] + [boolean]$SensorManagement, + [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Position=10)] + [Alias('use_existing_cloudtrail')] + [boolean]$ExistingCloudtrail, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get',Mandatory, - Position=2)] + Position=11)] [string]$Path, [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/user-scripts-download/v1:get')] [switch]$Force @@ -280,10 +377,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconHorizonAwsScript } } } -function Remove-FalconHorizonAwsAccount { +function Remove-FalconCloudAwsAccount { <# .SYNOPSIS -Remove Falcon Horizon AWS accounts +Remove Falcon Cloud Security AWS accounts .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER Id @@ -291,15 +388,16 @@ AWS account identifier .PARAMETER OrganizationId AWS organization identifier .LINK -https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHorizonAwsAccount +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCloudAwsAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:delete', SupportsShouldProcess)] + [Alias('Remove-FalconHorizonAwsAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-aws/entities/account/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^\d{12}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='OrganizationIds',Mandatory)] [ValidatePattern('^o-[0-9a-z]{10,32}$')] @@ -313,9 +411,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHorizonAwsAccount } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } \ No newline at end of file diff --git a/public/cloud-connect-cspm-azure.ps1 b/public/cloud-connect-cspm-azure.ps1 index ad831725..e9f1aec6 100644 --- a/public/cloud-connect-cspm-azure.ps1 +++ b/public/cloud-connect-cspm-azure.ps1 @@ -1,7 +1,7 @@ -function Edit-FalconHorizonAzureAccount { +function Edit-FalconCloudAzureAccount { <# .SYNOPSIS -Modify the default Falcon Horizon Azure client or subscription identifier +Modify the default Falcon Cloud Security Azure client or subscription identifier .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER Id @@ -11,35 +11,36 @@ Azure subscription identifier .PARAMETER TenantId Azure tenant identifier, required when multiple tenants have been registered .LINK -https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonAzureAccount +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconCloudAzureAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/client-id/v1:patch', SupportsShouldProcess)] + [Alias('Edit-FalconHorizonAzureAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/client-id/v1:patch',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id, - [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/default-subscription-id/v1:patch', - 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}$')] + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/default-subscription-id/v1:patch',Mandatory, + ValueFromPipelineByPropertyName)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_id')] [string]$SubscriptionId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/client-id/v1:patch', ValueFromPipelineByPropertyName,Position=2)] [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/default-subscription-id/v1:patch', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant-id','tenant_id')] [string]$TenantId ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Get-FalconHorizonAzureAccount { +function Get-FalconCloudAzureAccount { <# .SYNOPSIS -Search for Falcon Horizon Azure accounts +Search for Falcon Cloud Security Azure accounts .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER Id @@ -50,6 +51,8 @@ Azure tenant identifier Scan type .PARAMETER Status Azure account status +.PARAMETER CspmLite +Only return CSPM Lite accounts .PARAMETER Limit Maximum number of results per request .PARAMETER Offset @@ -59,17 +62,18 @@ 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-FalconHorizonAzureAccount +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudAzureAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get', SupportsShouldProcess)] + [Alias('Get-FalconHorizonAzureAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant_ids')] [string[]]$TenantId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get',Position=3)] @@ -80,6 +84,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAzureAccount [ValidateSet('provisioned','operational',IgnoreCase=$false)] [string]$Status, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get',Position=5)] + [Alias('cspm_lite')] + [boolean]$CspmLite, + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get',Position=6)] [ValidateRange(1,500)] [int32]$Limit, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:get')] @@ -93,16 +100,20 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAzureAccount $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } -function Get-FalconHorizonAzureCertificate { +function Get-FalconCloudAzureCertificate { <# .SYNOPSIS -Retrieve the base64 encoded certificate for a Falcon Horizon Azure tenant +Retrieve the base64 encoded certificate for a Falcon Cloud Security Azure tenant .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER Refresh @@ -112,10 +123,11 @@ Years the certificate should be valid [when Refresh: true] .PARAMETER TenantId Azure tenant identifier .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAzureCertificate +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudAzureCertificate #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/download-certificate/v1:get', SupportsShouldProcess)] + [Alias('Get-FalconHorizonAzureCertificate')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/download-certificate/v1:get',Position=1)] [boolean]$Refresh, @@ -125,17 +137,47 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonAzureCertificate [string]$YearsValid, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/download-certificate/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant_id')] [string[]]$TenantId ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function New-FalconHorizonAzureAccount { +function Get-FalconCloudAzureGroup { <# .SYNOPSIS -Provision a Falcon Horizon Azure account +Retrieve Falcon Cloud Security Azure management group registration +.DESCRIPTION +Requires 'CSPM registration: Read'. +.PARAMETER TenantId +Azure tenant identifier +.PARAMETER Limit +Maximum number of results per request [default: 100] +.PARAMETER Offset +Position to begin retrieving results +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudAzureGroup +#> + [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:get',Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('tenant_ids')] + [string[]]$TenantId, + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:get',Position=2)] + [int32]$Limit, + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:get')] + [int32]$Offset + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function New-FalconCloudAzureAccount { +<# +.SYNOPSIS +Provision a Falcon Cloud Security Azure account .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER SubscriptionId @@ -151,19 +193,20 @@ Account is the default Azure subscription .PARAMETER YearsValid Number of years valid .LINK -https://github.com/crowdstrike/psfalcon/wiki/New-FalconHorizonAzureAccount +https://github.com/crowdstrike/psfalcon/wiki/New-FalconCloudAzureAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:post', SupportsShouldProcess)] + [Alias('New-FalconHorizonAzureAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:post', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_id')] [string]$SubscriptionId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:post', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant_id')] [string]$TenantId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:post',Position=3)] @@ -182,10 +225,38 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconHorizonAzureAccount begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Receive-FalconHorizonAzureScript { +function New-FalconCloudAzureGroup { <# .SYNOPSIS -Download a Bash script which grants Falcon Horizon access using Azure Cloud Shell +Create a Falcon Cloud Security Azure management group +.DESCRIPTION +Requires 'CSPM registration: Write'. +.PARAMETER DefaultSubscriptionId +Default Azure subscription identifier +.PARAMETER TenantId +Azure tenant identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconCloudAzureGroup +#> + [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:post',Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('default_subscription_id')] + [string]$DefaultSubscriptionId, + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:post',Position=2)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('tenant_id')] + [string]$TenantId + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Receive-FalconCloudAzureScript { +<# +.SYNOPSIS +Download a Bash script which grants Falcon Cloud Security access using Azure Cloud Shell .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER TenantId @@ -196,23 +267,26 @@ Azure subscription identifier [default: all] Template to be rendered .PARAMETER AccountType Account type +.PARAMETER AzureManagementGroup +Use Azure Management Group .PARAMETER Path Destination path .PARAMETER Force Overwrite an existing file when present .LINK -https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconHorizonAzureScript +https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconCloudAzureScript #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get', SupportsShouldProcess)] + [Alias('Receive-FalconHorizonAzureScript')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant-id','tenant_id')] [string]$TenantId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_ids')] [string[]]$SubscriptionId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get',Position=3)] @@ -221,6 +295,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconHorizonAzureScript [ValidateSet('commercial','gov',IgnoreCase=$false)] [Alias('account_type')] [string]$AccountType, + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get',Position=5)] + [Alias('azure_management_group')] + [boolean]$AzureManagementGroup, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/user-scripts-download/v1:get',Mandatory, Position=5)] [string]$Path, @@ -250,10 +327,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconHorizonAzureScript } } } -function Remove-FalconHorizonAzureAccount { +function Remove-FalconCloudAzureAccount { <# .SYNOPSIS -Remove Falcon Horizon Azure accounts +Remove Falcon Cloud Security Azure accounts .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER TenantId @@ -263,13 +340,14 @@ Retain Azure tenant when removing an account .PARAMETER Id Azure account identifier .LINK -https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHorizonAzureAccount +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCloudAzureAccount #> [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:delete', SupportsShouldProcess)] + [Alias('Remove-FalconHorizonAzureAccount')] param( [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:delete',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant_ids')] [string[]]$TenantId, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:delete',Position=2)] @@ -277,8 +355,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHorizonAzureAccount [boolean]$RetainTenant, [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/account/v1:delete',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')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string[]]$Id ) begin { @@ -288,8 +366,31 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHorizonAzureAccount process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } +} +function Remove-FalconCloudAzureGroup { +<# +.SYNOPSIS +Remove Falcon Cloud Security Azure management groups +.DESCRIPTION +Requires 'CSPM registration: Write'. +.PARAMETER TenantId +Azure tenant identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCloudAzureGroup +#> + [CmdletBinding(DefaultParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:delete', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/cloud-connect-cspm-azure/entities/management-group/v1:delete', + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('tenant_ids')] + [string[]]$TenantId + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } \ No newline at end of file diff --git a/public/cloud-connect-cspm-gcp.ps1 b/public/cloud-connect-cspm-gcp.ps1 new file mode 100644 index 00000000..962cb9c8 Binary files /dev/null and b/public/cloud-connect-cspm-gcp.ps1 differ diff --git a/public/configuration-assessment.ps1 b/public/configuration-assessment.ps1 index c7135a75..5173e486 100644 Binary files a/public/configuration-assessment.ps1 and b/public/configuration-assessment.ps1 differ diff --git a/public/container-security.ps1 b/public/container-security.ps1 index 82f5a0a4..c04751d4 100644 --- a/public/container-security.ps1 +++ b/public/container-security.ps1 @@ -1,94 +1,865 @@ +[string[]]$ExcludeCountType = 'find-by-runtimeversion' +function Edit-FalconContainerPolicy { +<# +.SYNOPSIS +Modify a Falcon Cloud Security container policy +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Id +Image assessment policy identifier +.PARAMETER Name +Policy name +.PARAMETER Enabled +Policy enablement +.PARAMETER Description +Policy description +.PARAMETER Rule +One or more hashtables containing rule "action" and "policy_rules_data" +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerPolicy +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policies/v1:patch', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [string]$Id, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,Position=2)] + [string]$Name, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,Position=3)] + [Alias('is_enabled')] + [boolean]$Enabled, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:patch', + ValueFromPipelineByPropertyName,Position=4)] + [string]$Description, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:patch', + ValueFromPipelineByPropertyName,Position=5)] + [Alias('policy_data')] + [hashtable[]]$Rule + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Format = @{ Body = @{ root = @('description','is_enabled','name','policy_data') }; Query = @('id') } + } + } + process { + if ($PSBoundParameters.Rule) { + $PSBoundParameters.Rule = @{ rules = [PSCustomObject[]]$PSBoundParameters.Rule } + } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } +} +function Edit-FalconContainerPolicyGroup { +<# +.SYNOPSIS +Modify Falcon Cloud Security container policy image groups +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Id +Image group identifier +.PARAMETER Name +Image group name +.PARAMETER Condition +One or more hashtables containing policy image group "prop" and "value" conditions +.PARAMETER Description +Image group description +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerPolicyGroup +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:patch', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [string]$Id, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:patch', + ValueFromPipelineByPropertyName,Position=2)] + [string]$Name, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:patch', + ValueFromPipelineByPropertyName,Position=3)] + [Alias('policy_group_data')] + [hashtable[]]$Condition, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:patch', + ValueFromPipelineByPropertyName,Position=4)] + [string]$Description + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Format = @{ Body = @{ root = @('description','name','policy_group_data') }; Query = @('id') } + } + } + process { + if ($PSBoundParameters.Condition) { + $PSBoundParameters.Condition = @{ conditions = $PSBoundParameters.Condition } + } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } +} function Edit-FalconContainerRegistry { <# .SYNOPSIS -Modify a registry within Falcon Container Security +Modify a registry within Falcon Cloud Security +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Name +Falcon Cloud Security registry name +.PARAMETER State +Registry connection state +.PARAMETER Credential +A hashtable containing credentials to access the registry +.PARAMETER Id +Container registry identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerRegistry +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:patch', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=1)] + [Alias('user_defined_alias')] + [string]$Name, + [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=2)] + [ValidateSet('pause','resume',IgnoreCase=$false)] + [string]$State, + [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=3)] + [hashtable]$Credential, + [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=4)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [string]$Id + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Format = @{ + Body = @{ root = @('credential','user_defined_alias','state') } + Query = @('id') + } + } + } + process { + if ($PSBoundParameters.Credential) { + $PSBoundParameters.Credential = @{ details = $PSBoundParameters.Credential } + } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } +} +function Get-FalconContainer { +<# +.SYNOPSIS +Search for containers in Falcon Cloud Security +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainer +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/containers/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/containers/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerAlert { +<# +.SYNOPSIS +Search for Falcon Container Security container alerts +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerAlert +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/container-alerts/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/container-alerts/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerAssessment { +<# +.SYNOPSIS +Search for Falcon Container Security image assessment results +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerAssessment +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/image-assessment/images/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get',Position=2)] + [ValidateSet('first_seen.asc','first_seen.desc','highest_detection_severity.asc', + 'highest_detection_severity.desc','highest_vulnerability_severity.asc','highest_vulnerability_severity.desc', + 'image_digest.asc','image_digest.desc','image_id.asc','image_id.desc','registry.asc','registry.desc', + 'repository.asc','repository.desc','tag.asc','tag.desc',IgnoreCase=$false)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get',Position=3)] + [ValidateRange(1,100)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/image-assessment/images/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerCluster { +<# +.SYNOPSIS +Search for Falcon Cloud Security Kubernetes clusters +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerCluster +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/clusters/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/clusters/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerCount { +<# +.SYNOPSIS +List resource counts from Falcon Cloud Security +.DESCRIPTION +Requires 'Falcon Container Image: Read'. +.PARAMETER Filter +Falcon Query Language expression to limit results +.PARAMETER Resource +Falcon Cloud Security resource to count [default: containers] +.PARAMETER Type +Retrieve specific counts by type [default: count] +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerCount +#> + [CmdletBinding(DefaultParameterSetName='/container-security/aggregates/{resource}/{type}/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/aggregates/{resource}/{type}/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/aggregates/{resource}/{type}/v1:get',Position=2)] + [string]$Resource, + [Parameter(ParameterSetName='/container-security/aggregates/{resource}/{type}/v1:get',Position=3)] + [string]$Type + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } } + process { + if (!$PSBoundParameters.Resource) { $PSBoundParameters['Resource'] = 'containers' } + if (!$PSBoundParameters.Type) { $PSBoundParameters['Type'] = 'count' } + if ($Script:Falcon.Format) { + # Determine valid 'Resource' values using 'Format.json' + [string[]]$ValidResource = @($Script:Falcon.Format.PSObject.Properties.Name).Where({ + $_ -match '/container-(compliance|security)/aggregates/([\w-]+/)?[\w-]+/v\d' + }).foreach{ + if ($_ -match 'container-compliance') { + 'container-compliance' + } else { + @($_ -replace '(/container-security/aggregates/|/v\d)',$null -split '/',2)[0] + } + } | Select-Object -Unique | Sort-Object + if ($ValidResource -and $ValidResource -notcontains $PSBoundParameters.Resource) { + # Error if 'Resource' is not in ValidResource list + throw 'Invalid "Resource" value. [Accepted: {1}]' -f $PSBoundParameters.Resource, + ($ValidResource -join ', ') + } + # Determine valid Type' values using 'Format.json' + [string]$TypePattern = if ($PSBoundParameters.Resource -eq 'container-compliance') { + '/{0}/aggregates/[\w-]+/v\d' -f $PSBoundParameters.Resource + } else { + '/container-security/aggregates/{0}/[\w-]+/v\d' -f $PSBoundParameters.Resource + } + [string[]]$ValidType = @($Script:Falcon.Format.PSObject.Properties.Name).Where({ + $_ -match $TypePattern}).foreach{ + if ($PSBoundParameters.Resource -eq 'container-compliance') { + $_ -replace '(/container-compliance/aggregates/|/v\d)',$null + } else { + @($_ -replace '(/container-security/aggregates/|/v\d)',$null -split '/',2)[1] | Where-Object { + $ExcludeCountType -notcontains $_ } + } + } + if ($ValidType -and $ValidType -notcontains $PSBoundParameters.Type) { + # Error if 'Type' is not in ValidType list + throw 'Invalid "Type" value for "{0}". [Accepted: {1}]' -f $PSBoundParameters.Resource, + ($ValidType -join ', ') + } + } + $Param.Endpoint = if ($PSBoundParameters.Resource -eq 'container-compliance') { + # Switch to /container-compliance/ API + $Param.Endpoint -replace '-security/','-compliance/' -replace '\{resource\}/', + $null -replace '\{type\}',$PSBoundParameters.Type -replace '/v1:','/v2:' + } else { + # Update target API endpoint using 'Resource' and 'Type' + $Param.Endpoint -replace '\{resource\}',$PSBoundParameters.Resource -replace '\{type\}', + $PSBoundParameters.Type + } + # Remove 'resource' and 'type' and perform request + @('resource','type').foreach{ [void]$PSBoundParameters.Remove($_) } + $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($Request -and $Request.buckets) { + # Output 'buckets' sub-object + $Request.buckets + } elseif ($Request -and $null -ne $Request.count) { + # Output 'count' sub-object + $Request.count + } else { + # Output entire result when 'buckets' or 'count' were not provided + $Request + } + } +} +function Get-FalconContainerDeployment { +<# +.SYNOPSIS +Search for Falcon Cloud Security Kubernetes deployments +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerDeployment +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/deployments/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/deployments/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerDetection { +<# +.SYNOPSIS +Search for Falcon Cloud Security image assessment detections +.DESCRIPTION +Requires 'Falcon Container Image: 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-FalconContainerDetection +#> + [CmdletBinding(DefaultParameterSetName='/container-security/queries/detections/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/detections/v1:get',Position=1)] + [Parameter(ParameterSetName='/container-security/queries/detections/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/detections/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/detections/v1:get',Position=3)] + [Parameter(ParameterSetName='/container-security/queries/detections/v1:get',Position=2)] + [ValidateRange(1,100)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/detections/v1:get')] + [Parameter(ParameterSetName='/container-security/queries/detections/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/detections/v1:get')] + [switch]$Detailed, + [Parameter(ParameterSetName='/container-security/queries/detections/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/queries/detections/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerDriftIndicator { +<# +.SYNOPSIS +Search for Falcon Container Security container drift indicators +.DESCRIPTION +Requires 'Falcon Container Image: Read'. +.PARAMETER Id +Falcon Cloud Security drift indicator +.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-FalconContainerDriftIndicator +#> + [CmdletBinding(DefaultParameterSetName='/container-security/queries/drift-indicators/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/drift-indicators/v1:get', + ValueFromPipelineByPropertyName,ValueFromPipeline,Mandatory)] + [Alias('ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/container-security/combined/drift-indicators/v1:get',Position=1)] + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/drift-indicators/v1:get',Position=2)] + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/drift-indicators/v1:get',Position=3)] + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/drift-indicators/v1:get')] + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/drift-indicators/v1:get',Mandatory)] + [switch]$Detailed, + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/queries/drift-indicators/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($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Get-FalconContainerImage { +<# +.SYNOPSIS +Search for Falcon Cloud Security container images +.DESCRIPTION +Requires 'Falcon Container Image: 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 WithConfig +Include container image configuration detail +.PARAMETER Offset +Position to begin retrieving results +.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-FalconContainerImage +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/container-images/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get',Position=1)] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get',Position=2)] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get',Position=3)] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get',Mandatory,Position=4)] + [Alias('with_config')] + [boolean]$WithConfig, + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get')] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get')] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/container-images/v1:get')] + [Parameter(ParameterSetName='/container-security/combined/images/detail/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerIom { +<# +.SYNOPSIS +Search for Falcon Container Security Kubernetes Indicators of Misconfiguration +.DESCRIPTION +Requires 'Falcon Container Image: Read'. +.PARAMETER Id +Falcon Cloud Security Kubernetes IOM 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-FalconContainerIom +#> + [CmdletBinding(DefaultParameterSetName='/container-security/queries/kubernetes-ioms/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/kubernetes-ioms/v1:get', + ValueFromPipelineByPropertyName,ValueFromPipeline,Mandatory)] + [Alias('ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/container-security/combined/kubernetes-ioms/v1:get',Position=1)] + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/kubernetes-ioms/v1:get',Position=2)] + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/kubernetes-ioms/v1:get',Position=3)] + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/kubernetes-ioms/v1:get')] + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/kubernetes-ioms/v1:get',Mandatory)] + [switch]$Detailed, + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/queries/kubernetes-ioms/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($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $Param['Max'] = 100 + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Get-FalconContainerNode { +<# +.SYNOPSIS +Search for Falcon Cloud Security Kubernetes nodes +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerNode +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/nodes/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/nodes/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerPackage { +<# +.SYNOPSIS +Search for Falcon Cloud Security container packages +.DESCRIPTION +Requires 'Falcon Container Image: 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 OnlyZeroDayAffected +Only return packages with zero days [default: false] +.PARAMETER Offset +Position to begin retrieving results +.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-FalconContainerPackage +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/packages/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get',Position=2)] + [ValidateSet('license.asc','license.desc','package_name_version.asc','package_name_version.desc','type.asc', + 'type.desc',IgnoreCase=$false)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get',Position=4)] + [Alias('only_zero_day_affected')] + [boolean]$OnlyZeroDayAffected, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/packages/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerPod { +<# +.SYNOPSIS +Search for Falcon Cloud Security Kubernetes pods +.DESCRIPTION +Requires 'Falcon Container Image: 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 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-FalconContainerPod +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/pods/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/pods/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerPolicy { +<# +.SYNOPSIS +List Falcon Cloud Security container policies .DESCRIPTION -Requires 'Falcon Container Image: Write'. -.PARAMETER Name -Falcon Container Security registry name -.PARAMETER State -Registry connection state -.PARAMETER Credential -A hashtable containing credentials to access the registry -.PARAMETER Id -Container registry identifier +Requires 'Falcon Container Image: Read'. .LINK -https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerRegistry +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerPolicy #> - [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:patch', + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policies/v1:get', SupportsShouldProcess)] - param( - [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=1)] - [Alias('user_defined_alias')] - [string]$Name, - [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=2)] - [ValidateSet('pause','resume',IgnoreCase=$false)] - [string]$State, - [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Position=3)] - [hashtable]$Credential, - [Parameter(ParameterSetName='/container-security/entities/registries/v1:patch',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline,Position=4)] - [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}$')] - [string]$Id - ) - begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Body = @{ root = @('credential','user_defined_alias','state') } - Query = @('id') - } - } - } - process { - if ($PSBoundParameters.Credential) { - $PSBoundParameters.Credential = @{ details = $PSBoundParameters.Credential } - } - Invoke-Falcon @Param -UserInput $PSBoundParameters - } + param() + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Get-FalconContainerAssessment { +function Get-FalconContainerPolicyExclusion { <# .SYNOPSIS -Retrieve Falcon container image assessment reports +List Falcon Cloud Security container policy exclusions .DESCRIPTION -Requires 'Falcon Container Image: Write'. -.PARAMETER Registry -Container registry -.PARAMETER Repository -Container repository -.PARAMETER Tag -Container tag +Requires 'Falcon Container Image: Read'. .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAssessment +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerPolicyExclusion #> - [CmdletBinding(DefaultParameterSetName='/reports:get',SupportsShouldProcess)] - param( - [Parameter(ParameterSetName='/reports:get',Mandatory,Position=1)] - [string]$Registry, - [Parameter(ParameterSetName='/reports:get',Mandatory,Position=2)] - [string]$Repository, - [Parameter(ParameterSetName='/reports:get',Mandatory,Position=3)] - [string]$Tag - ) - begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ Query = @('registry','repository','tag') } - HostUrl = Get-ContainerUrl - } - } - process { - $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters - try { $Request | ConvertFrom-Json } catch { $Request } - } + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-exclusions/v1:get', + SupportsShouldProcess)] + param() + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconContainerPolicyGroup { +<# +.SYNOPSIS +List Falcon Cloud Security container policy image groups +.DESCRIPTION +Requires 'Falcon Container Image: Read'. +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerPolicyGroup +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:get', + SupportsShouldProcess)] + param() + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } function Get-FalconContainerRegistry { <# .SYNOPSIS -List Falcon Container Security registries +List Falcon Cloud Security registries .DESCRIPTION Requires 'Falcon Container Image: Read'. .PARAMETER Id @@ -96,7 +867,7 @@ Container registry identifier .PARAMETER Sort Property and direction to sort results .PARAMETER Limit -Maximum number of results per request +Maximum number of results per request [default: 100] .PARAMETER Offset Position to begin retrieving results .PARAMETER Detailed @@ -112,12 +883,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerRegistry param( [Parameter(ParameterSetName='/container-security/entities/registries/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string]$Id, [Parameter(ParameterSetName='/container-security/queries/registries/v1:get',Position=1)] [string]$Sort, [Parameter(ParameterSetName='/container-security/queries/registries/v1:get',Position=2)] + [ValidateRange(1,5000)] [int]$Limit, [Parameter(ParameterSetName='/container-security/queries/registries/v1:get')] [int]$Offset, @@ -132,10 +904,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerRegistry $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + $Param['Max'] = 100 + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerSensor { @@ -156,45 +933,236 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerSensor if (!$Script:Falcon.Registry -or $Script:Falcon.Registry.Expiration -lt (Get-Date).AddSeconds(240)) { Request-FalconRegistryCredential } + if ($Script:Falcon.Registry) { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName -replace '{sensortype}', + $Script:Falcon.Registry.SensorType -replace '{region}',$Script:Falcon.Registry.Region + Header = @{ Authorization = "Bearer $($Script:Falcon.Registry.Token)" } + HostUrl = Get-ContainerUrl -Registry + } + $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters + $Result = try { $Request | ConvertFrom-Json } catch { $Request } + if ($LatestUrl) { + ($Param.HostUrl -replace 'https://',$null),$Script:Falcon.Registry.SensorType, + $Script:Falcon.Registry.Region,'release',"falcon-sensor:$($Result.tags[-1])" -join '/' + } else { + $Result + } + } + } +} +function Get-FalconContainerVulnerability { +<# +.SYNOPSIS +Search for Falcon Cloud Security container image vulnerabilities +.DESCRIPTION +Requires 'Falcon Container Image: Read'. +.PARAMETER Id +CVE identifier +.PARAMETER Filter +Falcon Query Language expression to limit results +.PARAMETER Limit +Maximum number of results per request +.PARAMETER Offset +Position to begin retrieving results +.PARAMETER Sort +Property and direction to sort results +.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-FalconContainerVulnerability +#> + [CmdletBinding(DefaultParameterSetName='/container-security/combined/vulnerabilities/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/info/v1:get', + ValueFromPipelineByPropertyName,ValueFromPipeline,Mandatory)] + [Alias('cve_id')] + [string]$Id, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get',Position=2)] + [ValidateSet('cps_current_rating.asc','cps_current_rating.desc','cve_id.asc','cve_id.desc','cvss_score.asc', + 'cvss_score.desc','description.asc','description.desc','images_impacted.asc','images_impacted.desc', + 'packages_impacted.asc','packages_impacted.desc','severity.asc','severity.desc',IgnoreCase=$false)] + [string]$Sort, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/container-security/combined/vulnerabilities/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function New-FalconContainerImage { +<# +.SYNOPSIS +Create a Falcon Cloud Security base container image +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER ImageId +Container image identifier +.PARAMETER ImageDigest +Container image digest +.PARAMETER Registry +Container registry +.PARAMETER Repository +Container repository +.PARAMETER Tag +Container tag +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerImage +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/base-images/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:post',Mandatory,Position=1)] + [Alias('image_id')] + [string]$ImageId, + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:post',Mandatory,Position=2)] + [Alias('image_digest')] + [string]$ImageDigest, + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:post',Mandatory,Position=3)] + [string]$Registry, + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:post',Mandatory,Position=4)] + [string]$Repository, + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:post',Mandatory,Position=5)] + [string]$Tag + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function New-FalconContainerPolicy { +<# +.SYNOPSIS +Create a Falcon Cloud Security container policy +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Name +Policy name +.PARAMETER Description +Policy description +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerPolicy +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policies/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:post',Mandatory, + Position=1)] + [string]$Name, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:post',Mandatory, + Position=2)] + [string]$Description + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function New-FalconContainerPolicyExclusion { +<# +.SYNOPSIS +Create Falcon Cloud Security container policy exclusions +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Condition +One or more hashtables containing "prop", "value", "description", and "ttl" values +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerPolicyExclusion +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-exclusions/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-exclusions/v1:post', + Mandatory,ValueFromPipelineByPropertyName,Position=1)] + [Alias('conditions')] + [hashtable[]]$Condition + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Format = @{ Body = @{ root = @('conditions') }} + } + } + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function New-FalconContainerPolicyGroup { +<# +.SYNOPSIS +Create Falcon Cloud Security container policy image groups +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Name +Image group name +.PARAMETER PolicyId +Container image policy identifier +.PARAMETER Condition +One or more hashtables containing policy image group "prop" and "value" conditions +.PARAMETER Description +Image group description +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerPolicyGroup +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:post',Mandatory, + Position=1)] + [string]$Name, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:post',Mandatory, + Position=2)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('policy_id')] + [string]$PolicyId, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:post',Mandatory, + Position=3)] + [Alias('policy_group_data')] + [hashtable[]]$Condition, + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:post',Position=4)] + [string]$Description + + ) + begin { $Param = @{ - Endpoint = $PSCmdlet.ParameterSetName -replace '{sensortype}', - $Script:Falcon.Registry.SensorType -replace '{region}',$Script:Falcon.Registry.Region - Header = @{ Authorization = "Bearer $($Script:Falcon.Registry.Token)" } - HostUrl = Get-ContainerUrl -Registry + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Format = @{ Body = @{ root = @('description','name','policy_id','policy_group_data') }} } - $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters - $Result = try { $Request | ConvertFrom-Json } catch { $Request } - if ($LatestUrl) { - ($Param.HostUrl -replace 'https://',$null),$Script:Falcon.Registry.SensorType, - $Script:Falcon.Registry.Region,'release',"falcon-sensor:$($Result.tags[-1])" -join '/' - } else { - $Result + } + process { + if ($PSBoundParameters.Condition) { + $PSBoundParameters.Condition = @{ conditions = $PSBoundParameters.Condition } } + Invoke-Falcon @Param -UserInput $PSBoundParameters } } function New-FalconContainerRegistry { <# .SYNOPSIS -Create a registry within Falcon Container Security +Create a registry within Falcon Cloud Security .DESCRIPTION Requires 'Falcon Container Image: Write'. .PARAMETER Name -Desired registry name within Falcon Container Security +Desired registry name within Falcon Cloud Security .PARAMETER Type Registry type .PARAMETER Url URL used to log in to the registry .PARAMETER Credential -A hashtable containing credentials to access the registry +A hashtable containing username and password used to access the registry .PARAMETER UrlUniquenessKey Registry URL alias - -Available with Docker Hub, Google Artifact Registry, Google Container Registry, IBM Cloud, and Oracle .LINK https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerRegistry #> - [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:post', - SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/container-security/entities/registries/v1:post',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/container-security/entities/registries/v1:post',Mandatory,Position=1)] [Alias('user_defined_alias')] @@ -226,7 +1194,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerRegistry function Remove-FalconContainerImage { <# .SYNOPSIS -Remove a Falcon container image +Remove a Falcon Cloud Security base container image .DESCRIPTION Requires 'Falcon Container Image: Write'. .PARAMETER Id @@ -234,31 +1202,74 @@ Container image identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerImage #> - [CmdletBinding(DefaultParameterSetName='/images/{id}:delete',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/container-security/entities/base-images/v1:delete', + SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/images/{id}:delete',Mandatory,ValueFromPipelineByPropertyName, - ValueFromPipeline,Position=1)] - [object]$Id + [Parameter(ParameterSetName='/container-security/entities/base-images/v1:delete',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [Alias('ids')] + [string[]]$Id ) - begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; HostUrl = Get-ContainerUrl }} - process { - $PSBoundParameters.Id = switch ($PSBoundParameters.Id) { - { $_.ImageInfo.id } { $_.ImageInfo.id } - { $_ -is [string] } { $_ } - } - if ($PSBoundParameters.Id -notmatch '^[A-Fa-f0-9]{64}$') { - throw "'$($PSBoundParameters.Id)' is not a valid image identifier." - } else { - $Endpoint = $PSCmdlet.ParameterSetName -replace '{id}',$PSBoundParameters.Id - [void]$PSBoundParameters.Remove('Id') - Invoke-Falcon @Param -Endpoint $Endpoint -UserInput $PSBoundParameters + 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) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters } } } +function Remove-FalconContainerPolicy { +<# +.SYNOPSIS +Delete Image Assessment Policy by policy UUID +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Id +Image assessment policy identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerPolicy +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policies/v1:delete', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policies/v1:delete',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [string]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Remove-FalconContainerPolicyGroup { +<# +.SYNOPSIS +Remove Falcon Cloud Security container policy image groups +.DESCRIPTION +Requires 'Falcon Container Image: Write'. +.PARAMETER Id +Image group identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerPolicyGroup +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:delete', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-groups/v1:delete',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [string]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} function Remove-FalconContainerRegistry { <# .SYNOPSIS -Remove a registry from Falcon Container Security +Remove a registry from Falcon Cloud Security .DESCRIPTION Requires 'Falcon Container Image: Write'. .PARAMETER Id @@ -271,18 +1282,18 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerRegistry param( [Parameter(ParameterSetName='/container-security/entities/registries/v1:delete',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string]$Id ) begin { - $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $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 | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -303,9 +1314,9 @@ function Request-FalconRegistryCredential { .SYNOPSIS Request your Falcon container registry username, password and access token .DESCRIPTION -If successful, you token and username are cached for re-use as you use Falcon container security related commands. +If successful, you token and username are cached for re-use as you use Falcon Cloud Security related commands. -If an active access token is due to expire in less than 15 seconds, a new token will automatically be requested. +If an active access token is due to expire in less than 4 minutes, a new token will automatically be requested. Requires 'Falcon Container Image: Read' and 'Sensor Download: Read'. .PARAMETER SensorType @@ -315,54 +1326,64 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconRegistryCredential #> [CmdletBinding(SupportsShouldProcess)] param( - [Parameter(Mandatory,Position=1)] + [Parameter(Position=1)] [ValidateSet('falcon-sensor','falcon-container',IgnoreCase=$false)] [string]$SensorType ) process { - [System.Collections.Hashtable]$Credential = @{} - $Credential['Username'] = if ($Script:Falcon.Registry.Username) { - $Script:Falcon.Registry.Username - } else { - try { - @(Get-FalconCcid -EA 0).foreach{ 'fc',$_.Split('-')[0].ToLower() -join '-' } - } catch { - throw "Failed to retrieve registry username. Verify 'Sensor Download: Read' permission." + [System.Collections.Hashtable]$Credential = @{ + Username = if ($Script:Falcon.Registry.Username) { + $Script:Falcon.Registry.Username + } else { + try { + @(Get-FalconCcid -EA 0).foreach{ 'fc',$_.Split('-')[0].ToLower() -join '-' } + } catch { + throw "Failed to retrieve registry username. Verify 'Sensor Download: Read' permission." + } } - } - $Credential['Password'] = if ($Script:Falcon.Registry.Password) { - $Script:Falcon.Registry.Password - } else { - try { - (Invoke-Falcon -Endpoint ( - '/container-security/entities/image-registry-credentials/v1:get')).Token - } catch { - throw "Failed to retrieve registry password. Verify 'Falcon Container Image: Read' permission." + Password = if ($Script:Falcon.Registry.Password) { + $Script:Falcon.Registry.Password + } else { + try { + (Invoke-Falcon -Command $MyInvocation.MyCommand.Name -Endpoint ( + '/container-security/entities/image-registry-credentials/v1:get')).Token + } catch { + throw "Failed to retrieve registry password. Verify 'Falcon Container Image: Read' permission." + } } } if ($Credential.Username -and $Credential.Password) { $Param = @{ + Command = $MyInvocation.MyCommand.Name Endpoint = "/v2/token?=$($Credential.Username):get" Header = @{ - Authorization = "Basic $([System.Convert]::ToBase64String( - [System.Text.Encoding]::ASCII.GetBytes("$($Credential.Username):$( - $Credential.Password)")))" + Authorization = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes( + "$($Credential.Username):$($Credential.Password)")))" } Format = @{ Query = @('scope','service') } HostUrl = Get-ContainerUrl -Registry } [string]$Region = switch -Regex ($Script:Falcon.Hostname) { - 'eu-1' { 'eu-1' } + 'eu-1' { 'eu-1' } 'laggar\.gcw' { 'us-gov-1' } - 'us-2' { 'us-2' } - default { 'us-1' } + 'us-2' { 'us-2' } + default { 'us-1' } } - $PSBoundParameters['scope'] = 'repository:',"/$Region/release/",':pull' -join + $SensorType = if ($PSBoundParameters.SensorType) { $PSBoundParameters.SensorType + } elseif ($Script:Falcon.Registry.SensorType) { + $Script:Falcon.Registry.SensorType + } else { + Read-Host 'SensorType' + } + $PSBoundParameters['scope'] = 'repository:',"/$Region/release/",':pull' -join $SensorType $PSBoundParameters['service'] = 'registry.crowdstrike.com' [void]$PSBoundParameters.Remove('SensorType') $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters - if ($Request) { + @('token','expires_in').foreach{ + if (!$Request.$_) { throw "Token request failed. Missing expected '$_' property from response." } + } + if ($Request.token -and $Request.expires_in) { $Script:Falcon['Registry'] = @{ Username = $Credential.Username Password = $Credential.Password @@ -375,6 +1396,31 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconRegistryCredential } } } +function Set-FalconContainerPolicyPrecedence { +<# +.SYNOPSIS +Set Falcon Cloud Security container image assessment policy precedence +.DESCRIPTION +All policy identifiers must be supplied in order to define policy precedence. + +Requires 'Falcon Container Image: Write'. +.PARAMETER Id +Policy identifiers in desired precedence order +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Set-FalconContainerPolicyPrecedence +#> + [CmdletBinding(DefaultParameterSetName='/container-security/entities/image-assessment-policy-precedence/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/container-security/entities/image-assessment-policy-precedence/v1:post', + Mandatory,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('precedence')] + [string[]]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} function Show-FalconRegistryCredential { <# .SYNOPSIS @@ -394,11 +1440,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Show-FalconRegistryCredential } [PSCustomObject]@{ Token = if ($Script:Falcon.Registry.Token -and $Script:Falcon.Registry.Expiration -gt - (Get-Date).AddSeconds(240)) { - $true - } else { - $false - } + (Get-Date).AddSeconds(240)) { $true } else { $false } Username = $Script:Falcon.Registry.Username Password = $Script:Falcon.Registry.Password Region = $Script:Falcon.Registry.Region @@ -406,7 +1448,43 @@ https://github.com/crowdstrike/psfalcon/wiki/Show-FalconRegistryCredential PullToken = $PullToken } } else { - Write-Error "No registry credential available. Try 'Request-FalconRegistryCredential'." + throw "No registry credential available. Try 'Request-FalconRegistryCredential'." + } + } +} +Register-ArgumentCompleter -CommandName Get-FalconContainerCount -ParameterName Resource -ScriptBlock { + if ($Script:Falcon.Format) { + # Add 'Resource' values to Get-FalconContainerCount using 'format.json' + $List = [System.Collections.Generic.List[string]]@() + @(@($Script:Falcon.Format.PSObject.Properties.Name).Where({ + $_ -match '/container-(compliance|security)/aggregates/([\w-]+/)?[\w-]+/v\d' + }).foreach{ + if ($_ -match 'container-compliance') { + 'container-compliance' + } else { + ($_ -replace '(/container-security/aggregates/|/v\d)',$null -split '/',2)[0] + } + } | Select-Object -Unique).foreach{ + $List.Add($_) + } + $List | Sort-Object + } +} +Register-ArgumentCompleter -CommandName Get-FalconContainerCount -ParameterName Type -ScriptBlock { + if ($Script:Falcon.Format) { + # Add 'Type' values to Get-FalconContainerCount using 'Format.json' + $List = [System.Collections.Generic.List[string]]@() + @(@($Script:Falcon.Format.PSObject.Properties.Name).Where({ + $_ -match '/container-(compliance|security)/aggregates/([\w-]+/)?[\w-]+/v\d' + }).foreach{ + if ($_ -match 'container-compliance') { + $_ -replace '(/container-compliance/aggregates/|/v\d)',$null + } else { + ($_ -replace '(/container-security/aggregates/|/v\d)',$null -split '/',2)[1] + } + } | Select-Object -Unique).Where({$ExcludeCountType -notcontains $_}).foreach{ + $List.Add($_) } + $List | Sort-Object } } \ No newline at end of file diff --git a/public/delivery-settings.ps1 b/public/delivery-settings.ps1 new file mode 100644 index 00000000..ce60c46a Binary files /dev/null and b/public/delivery-settings.ps1 differ diff --git a/public/detects.ps1 b/public/detects.ps1 index 32822db2..0b85e771 100644 --- a/public/detects.ps1 +++ b/public/detects.ps1 @@ -24,19 +24,17 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconDetection [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',Position=2)] [Alias('show_in_ui')] [boolean]$ShowInUi, - [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',ValueFromPipelineByPropertyName, - Position=3)] + [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',ValueFromPipelineByPropertyName,Position=3)] [ValidateSet('new','in_progress','true_positive','false_positive','closed','reopened',IgnoreCase=$false)] [string]$Status, - [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',ValueFromPipelineByPropertyName, - Position=4)] - [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}$')] + [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',ValueFromPipelineByPropertyName,Position=4)] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('assigned_to_uuid','uuid')] [string]$AssignedToUuid, [Parameter(ParameterSetName='/detects/entities/detects/v2:patch',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=5)] [ValidatePattern('^ldt:[a-fA-F0-9]{32}:\d+$')] - [Alias('Ids','detection_id','detection_ids')] + [Alias('ids','detection_id','detection_ids')] [string[]]$Id ) begin { @@ -48,82 +46,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconDetection if ($PSBoundParameters.Comment -and !$PSBoundParameters.Status) { throw "A 'status' value must be supplied when adding a comment." } elseif ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } } -function Get-FalconDetection { +function Get-FalconCloudIoa { <# .SYNOPSIS -Search for detections -.DESCRIPTION -Requires 'Detections: Read'. -.PARAMETER Id -Detection identifier -.PARAMETER Filter -Falcon Query Language expression to limit results -.PARAMETER Query -Perform a generic substring search across available fields -.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-FalconDetection -#> - [CmdletBinding(DefaultParameterSetName='/detects/queries/detects/v1:get',SupportsShouldProcess)] - param( - [Parameter(ParameterSetName='/detects/entities/summaries/GET/v1:post',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline)] - [ValidatePattern('^ldt:[a-fA-F0-9]{32}:\d+$')] - [Alias('Ids','detection_id','detection_ids')] - [string[]]$Id, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=1)] - [ValidateScript({ Test-FqlStatement $_ })] - [string]$Filter, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=2)] - [Alias('q')] - [string]$Query, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=3)] - [ValidateSet('adversary_id.asc','adversary_id.desc','devices.hostname.asc','devices.hostname.desc', - 'first_behavior.asc','first_behavior.desc','last_behavior.asc','last_behavior.desc', - 'max_confidence.asc','max_confidence.desc','max_severity.asc','max_severity.desc',IgnoreCase=$false)] - [string]$Sort, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=4)] - [ValidateRange(1,5000)] - [int32]$Limit, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] - [int32]$Offset, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] - [switch]$Detailed, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] - [switch]$All, - [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] - [switch]$Total - ) - begin { - $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 1000 } - [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 -UserInput $PSBoundParameters - } -} -function Get-FalconHorizonIoa { -<# -.SYNOPSIS -Search for Falcon Horizon Indicators of Attack +Search for Falcon Cloud Security Indicators of Attack .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER CloudPlatform @@ -161,9 +92,10 @@ 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-FalconHorizonIoa +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudIoa #> [CmdletBinding(DefaultParameterSetName='/detects/entities/ioa/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonIoa')] param( [Parameter(ParameterSetName='/detects/entities/ioa/v1:get',Mandatory,Position=1)] [ValidateSet('aws','azure',IgnoreCase=$false)] @@ -177,11 +109,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoa [Alias('aws_account_id')] [string]$AwsAccountId, [Parameter(ParameterSetName='/detects/entities/ioa/v1:get',ValueFromPipelineByPropertyName,Position=4)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_subscription_id','subscription_id')] [string]$AzureSubscriptionId, [Parameter(ParameterSetName='/detects/entities/ioa/v1:get',ValueFromPipelineByPropertyName,Position=5)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_tenant_id','tenant_id')] [string]$AzureTenantId, [Parameter(ParameterSetName='/detects/entities/ioa/v1:get',Position=6)] @@ -224,14 +156,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoa begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Get-FalconHorizonIom { +function Get-FalconCloudIom { <# .SYNOPSIS -Search for Falcon Horizon Indicators of Misconfiguration +Search for Falcon Cloud Security Indicators of Misconfiguration .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER Id -Horizon Indicator of Misconfiguration identifier +Falcon Cloud Security Indicator of Misconfiguration identifier .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -249,9 +181,10 @@ 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-FalconHorizonIom +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudIom #> [CmdletBinding(DefaultParameterSetName='/detects/queries/iom/v2:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonIom')] param( [Parameter(ParameterSetName='/detects/entities/iom/v2:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] @@ -288,9 +221,84 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIom $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Get-FalconDetection { +<# +.SYNOPSIS +Search for detections +.DESCRIPTION +Requires 'Detections: Read'. +.PARAMETER Id +Detection identifier +.PARAMETER Filter +Falcon Query Language expression to limit results +.PARAMETER Query +Perform a generic substring search across available fields +.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-FalconDetection +#> + [CmdletBinding(DefaultParameterSetName='/detects/queries/detects/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/detects/entities/summaries/GET/v1:post',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline)] + [ValidatePattern('^ldt:[a-fA-F0-9]{32}:\d+$')] + [Alias('ids','detection_id','detection_ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=2)] + [Alias('q')] + [string]$Query, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=3)] + [ValidateSet('adversary_id.asc','adversary_id.desc','devices.hostname.asc','devices.hostname.desc', + 'first_behavior.asc','first_behavior.desc','last_behavior.asc','last_behavior.desc', + 'max_confidence.asc','max_confidence.desc','max_severity.asc','max_severity.desc',IgnoreCase=$false)] + [string]$Sort, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get',Position=4)] + [ValidateRange(1,5000)] + [int32]$Limit, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] + [switch]$Detailed, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/detects/queries/detects/v1:get')] + [switch]$Total + ) + begin { + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 1000 } + [System.Collections.Generic.List[string]]$List = @() + } + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } \ No newline at end of file diff --git a/public/devices.ps1 b/public/devices.ps1 index d7b92649..31bb6066 100644 --- a/public/devices.ps1 +++ b/public/devices.ps1 @@ -27,7 +27,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconGroupingTag [Parameter(ParameterSetName='/devices/entities/devices/tags/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('device_ids','device_id','Ids')] + [Alias('device_ids','device_id','ids')] [string[]]$Id ) begin { @@ -38,7 +38,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconGroupingTag process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -126,7 +126,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHost [Parameter(ParameterSetName='/devices/entities/online-state/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','host_ids','aid')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id, [Parameter(ParameterSetName='/devices/queries/devices-scroll/v1:get',Position=1)] [Parameter(ParameterSetName='/devices/queries/devices-hidden/v1:get',Position=1)] @@ -199,7 +199,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHost } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters if ($Request) { @@ -257,7 +257,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHost @('device_control','firewall','prevention','remote_response','sensor_update').foreach{ foreach ($i in (& "Get-Falcon$($_ -replace '(remote)?_',$null)Policy" -Id ( $Request.device_policies.$_.policy_id | Select-Object -Unique) -EA 0)) { - @($Request.device_policies.$_).Where({ $_.policy_id -eq $i.id }).foreach{ + @($Request.device_policies.$_).Where({$_.policy_id -eq $i.id}).foreach{ Set-Property $_ 'policy_name' $i.name } } @@ -312,7 +312,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHostGroup [Parameter(ParameterSetName='/devices/entities/host-groups/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/devices/queries/host-groups/v1:get',Position=1)] [Parameter(ParameterSetName='/devices/combined/host-groups/v1:get',Position=1)] @@ -350,7 +350,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHostGroup } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters @{ members = 'Get-FalconHostGroupMember' } @@ -449,7 +449,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconHostAction [Parameter(ParameterSetName='/devices/entities/devices-actions/v2:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id')] + [Alias('ids','device_id')] [string[]]$Id ) begin { @@ -467,7 +467,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconHostAction process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters -Command 'Get-FalconHost' @@ -507,7 +507,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconHostGroupAction [Parameter(ParameterSetName='/devices/entities/host-group-actions/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','HostIds')] + [Alias('ids','device_id','HostIds')] [string[]]$HostId ) begin { @@ -521,7 +521,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconHostGroupAction process { if ($HostId) { @($HostId).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('HostId') for ($i = 0; $i -lt $List.Count; $i += 500) { $IdString = (@($List[$i..($i + 499)]).foreach{ "'$_'" }) -join ',' @@ -539,8 +539,8 @@ function New-FalconHostGroup { Create host groups .DESCRIPTION Requires 'Host groups: Write'. -.PARAMETER Array -An array of host groups to create in a single request +.PARAMETER InputObject +One or more host groups to create in a single request .PARAMETER GroupType Host group type .PARAMETER Name @@ -554,22 +554,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconHostGroup #> [CmdletBinding(DefaultParameterSetName='/devices/entities/host-groups/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconHostGroup' - Endpoint = '/devices/entities/host-groups/v1:post' - Required = @('group_type','name') - Content = @('group_type') - Format = @{ group_type = 'GroupType' } - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconHostGroup' '/devices/entities/host-groups/v1:post' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/devices/entities/host-groups/v1:post',Mandatory,Position=1)] [ValidateSet('dynamic','static','staticByID',IgnoreCase=$false)] [Alias('group_type')] @@ -590,21 +578,21 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconHostGroup [string]$AssignmentRule ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/devices/entities/host-groups/v1:post' - Format = if ($PSCmdlet.ParameterSetName -eq 'array') { @{ Body = @{ root = @('resources') }}} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/devices/entities/host-groups/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - @($Array).foreach{ - if ($_.group_type -ne 'dynamic' -and $_.assignment_rule) { - # Remove 'assignment_rule' from non-dynamic groups - $_.PSObject.Properties.Remove('assignment_rule') + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined properties and remove empty values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + if ($i.group_type -ne 'dynamic' -and $i.assignment_rule) { + # Remove 'assignment_rule' when 'group_type' is not 'dynamic' + [void]$i.PSObject.Properties.Remove('assignment_rule') } - $List.Add($_) + Remove-EmptyValue $i group_type,name + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -612,8 +600,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconHostGroup } end { if ($List) { - for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format.Body = @{ root = @('resources') } + for ($i = 0; $i -lt $List.Count; $i += 50) { + $PSBoundParameters['resources'] = @($List[$i..($i + 49)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -650,7 +640,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconGroupingTag [Parameter(ParameterSetName='/devices/entities/devices/tags/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('device_ids','device_id','Ids')] + [Alias('device_ids','device_id','ids')] [string[]]$Id ) begin { @@ -661,7 +651,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconGroupingTag process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -682,7 +672,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHostGroup [Parameter(ParameterSetName='/devices/entities/host-groups/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -692,8 +682,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconHostGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) - Invoke-Falcon @Param -UserInput $PSBoundParameters + [void]$PSBoundParameters.Remove('Id') + for ($i = 0; $i -lt $List.Count; $i += 50) { + $PSBoundParameters['ids'] = @($List[$i..($i + 49)]) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } } \ No newline at end of file diff --git a/public/discover.ps1 b/public/discover.ps1 index 3a412e25..885d58b2 100644 --- a/public/discover.ps1 +++ b/public/discover.ps1 @@ -16,6 +16,8 @@ Maximum number of results per request Include additional properties .PARAMETER Offset Position to begin retrieving results +.PARAMETER After +Pagination token to retrieve the next set of results .PARAMETER Detailed Retrieve detailed information .PARAMETER All @@ -26,6 +28,8 @@ Display total result count instead of results Search for user account assets .PARAMETER Application Search for applications +.PARAMETER External +Search for external assets .PARAMETER IoT Search for IoT assets .PARAMETER Login @@ -45,84 +49,157 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconAsset ValueFromPipelineByPropertyName,ValueFromPipeline)] [Parameter(ParameterSetName='/discover/entities/logins/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] - [ValidatePattern('^[a-fA-F0-9]{32}_\w+$')] - [Alias('Ids')] + [Parameter(ParameterSetName='/fem/entities/external-assets/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] + [Alias('ids')] [string[]]$Id, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Position=1)] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get',Position=1)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get',Position=1)] [Parameter(ParameterSetName='/discover/queries/applications/v1:get',Position=1)] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get',Position=1)] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get',Position=1)] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get',Position=1)] [Parameter(ParameterSetName='/discover/queries/logins/v1:get',Position=1)] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] [string]$Filter, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Position=2)] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get',Position=2)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get',Position=2)] [Parameter(ParameterSetName='/discover/queries/applications/v1:get',Position=2)] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get',Position=2)] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get',Position=2)] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get',Position=2)] [Parameter(ParameterSetName='/discover/queries/logins/v1:get',Position=2)] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get',Position=2)] [string]$Sort, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Position=3)] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get',Position=3)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get',Position=3)] [Parameter(ParameterSetName='/discover/queries/applications/v1:get',Position=3)] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get',Position=3)] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get',Position=3)] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get',Position=3)] [Parameter(ParameterSetName='/discover/queries/logins/v1:get',Position=3)] - [ValidateRange(1,100)] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get',Position=3)] [int32]$Limit, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Position=4)] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get',Position=4)] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get',Position=4)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get',Position=4)] - [ValidateSet('login_event',IgnoreCase=$false)] + [ValidateSet('login_event','browser_extension','host_info','install_usage','system_insights','third_party', + 'risk_factors',IgnoreCase=$false)] [string[]]$Include, [Parameter(ParameterSetName='/discover/queries/hosts/v1:get')] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get')] [Parameter(ParameterSetName='/discover/queries/applications/v1:get')] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get')] [Parameter(ParameterSetName='/discover/queries/logins/v1:get')] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get')] [int32]$Offset, + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get')] + [Parameter(ParameterSetName='/discover/combined/applications/v1:get')] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get')] + [string]$After, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Mandatory)] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get',Mandatory)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get')] - [Parameter(ParameterSetName='/discover/queries/applications/v1:get')] - [Parameter(ParameterSetName='/discover/queries/hosts/v1:get')] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get')] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get')] [Parameter(ParameterSetName='/discover/queries/logins/v1:get')] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get')] [switch]$Detailed, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get')] + [Parameter(ParameterSetName='/discover/combined/hosts/v1:get')] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get')] [Parameter(ParameterSetName='/discover/queries/applications/v1:get')] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get')] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get')] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get')] [Parameter(ParameterSetName='/discover/queries/logins/v1:get')] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get')] [switch]$All, [Parameter(ParameterSetName='/discover/queries/accounts/v1:get')] [Parameter(ParameterSetName='/discover/queries/applications/v1:get')] [Parameter(ParameterSetName='/discover/queries/hosts/v1:get')] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get')] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get')] [Parameter(ParameterSetName='/discover/queries/logins/v1:get')] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get')] [switch]$Total, [Parameter(ParameterSetName='/discover/entities/accounts/v1:get',Mandatory)] [Parameter(ParameterSetName='/discover/queries/accounts/v1:get',Mandatory)] [switch]$Account, + [Parameter(ParameterSetName='/discover/combined/applications/v1:get',Mandatory)] [Parameter(ParameterSetName='/discover/entities/applications/v1:get',Mandatory)] [Parameter(ParameterSetName='/discover/queries/applications/v1:get',Mandatory)] [switch]$Application, + [Parameter(ParameterSetName='/fem/entities/external-assets/v1:get',Mandatory)] + [Parameter(ParameterSetName='/fem/queries/external-assets/v1:get',Mandatory)] + [switch]$External, [Parameter(ParameterSetName='/discover/entities/iot-hosts/v1:get',Mandatory)] - [Parameter(ParameterSetName='/discover/queries/iot-hosts/v1:get',Mandatory)] + [Parameter(ParameterSetName='/discover/queries/iot-hosts/v2:get',Mandatory)] [switch]$IoT, [Parameter(ParameterSetName='/discover/entities/logins/v1:get',Mandatory)] [Parameter(ParameterSetName='/discover/queries/logins/v1:get',Mandatory)] [switch]$Login ) begin { - $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 100 } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() + $RegEx = @{ + CombinedUrl = '/discover/combined/(applications|hosts)/v1:get' + AppFacet = '^(browser_extension|host_info|install_usage)$' + HostFacet = '^(login_event|system_insights|third_party|risk_factors)$' + } + if ($PSBoundParameters.All -and !$PSBoundParameters.Limit) { + # Add appropriate 'Limit' when using 'All' + $PSBoundParameters['Limit'] = if ($PSCmdlet.ParameterSetName -match $RegEx.CombinedUrl) { 1000 } else { 100 } + } } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - $Request = if ($Detailed -and ($Account -or $Application -or $IoT -or $Login)) { + if ($List) { + # Submit 'id' values to /entities/ API in groups of 100 + $PSBoundParameters['Id'] = @($List) + $Param['Max'] = 100 + } else { + # Error when 'Limit' exceeds 100 or 1,000 for relevant API + $MaxLimit = if ($PSCmdlet.ParameterSetName -match $RegEx.CombinedUrl) { 1000 } else { 100 } + if ($PSBoundParameters.Limit -and $PSBoundParameters.Limit -gt $MaxLimit) { + $Message = (('Cannot validate argument on parameter {0}. The {1} argument is greater than the maximum al' + + 'lowed range of {2}. Supply an argument that is less than or equal to {2} and then try the command aga' + + 'in.') -f "'Limit'",$PSBoundParameters.Limit,$MaxLimit) + throw $Message + } + if ($PSBoundParameters.Include) { + # Error if individual 'Include' value is not valid for target API + [string[]]$Valid = if ($PSCmdlet.ParameterSetName -eq '/discover/combined/applications/v1:get') { + $RegEx.AppFacet -replace '[\^\(\)\$]',$null -split '\|' + } elseif ($PSCmdlet.ParameterSetName -eq '/discover/combined/hosts/v1:get') { + $RegEx.HostFacet -replace '[\^\(\)\$]',$null -split '\|' + } elseif ($PSCmdlet.ParameterSetName -match '/queries/') { + 'login_event' + } + [string[]]$Facet = @($PSBoundParameters.Include).foreach{ + $Message = (('Cannot validate argument on parameter {0}. The argument "{1}" does not belong to the set' + + ' "{2}" specified by the ValidateSet attribute. Supply an argument that is in the set and then try t' + + 'he command again.') -f "'Include'",$_,($Valid -join ',')) + if ($Valid -notcontains $_) { throw $Message } elseif ($_ -ne 'login_event') { $_ } + } + if ($Facet) { + # Move 'Include' values to 'facet' for /combined/ API(s) + $PSBoundParameters['facet'] = $Facet + $PSBoundParameters.Include = @($PSBoundParameters.Include).Where({$Facet -notcontains $_}) + if (!$PSBoundParameters.Include) { [void]$PSBoundParameters.Remove('Include') } + } + } + } + $Request = if ($Include -contains 'login_event' -and !$PSBoundParameters.Detailed -and !$Account) { + $PSBoundParameters['Detailed'] = $true + Invoke-Falcon @Param -UserInput $PSBoundParameters | Select-Object id,aid + } elseif ($Detailed -and ($Account -or $External -or $IoT -or $Login)) { + # Re-submit 'id' values to appropriate /entities/ API to retrieve detail [void]$PSBoundParameters.Remove('Detailed') $IdList = Invoke-Falcon @Param -UserInput $PSBoundParameters if ($IdList -and $Account) { $IdList | & $MyInvocation.MyCommand.Name -Account - } elseif ($IdList -and $Application) { - $IdList | & $MyInvocation.MyCommand.Name -Application + } elseif ($IdList -and $External) { + $IdList | & $MyInvocation.MyCommand.Name -External } elseif ($IdList -and $IoT) { $IdList | & $MyInvocation.MyCommand.Name -IoT } elseif ($IdList -and $Login) { @@ -131,20 +208,21 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconAsset } else { Invoke-Falcon @Param -UserInput $PSBoundParameters } - if ($Include) { + if ($Request -and $PSBoundParameters.Include -and $PSBoundParameters.Include -contains 'login_event') { + # Match 'login_event' results with $ReqId if (!$Request.id) { $Request = @($Request).foreach{ ,[PSCustomObject]@{ id = $_ }}} - if ($Include -contains 'login_event') { - # Define property to match 'login' results with 'id' value - [string]$Property = if ($Account) { 'account_id' } else { 'host_id' } - for ($i = 0; $i -lt ($Request | Measure-Object).Count; $i += 100) { - # In groups of 100, perform filtered search for login events - $Filter = @(@($Request.id)[$i..($i + 99)]).foreach{ $Property,"'$_'" -join ':' } -join ',' - $Content = & $MyInvocation.MyCommand.Name -Filter $Filter -Detailed -All -Login -EA 0 - foreach ($Value in @($Content.$Property | Select-Object -Unique)) { - @($Request).Where({ $_.id -eq $Value }).foreach{ - # Append matched login events to 'id' using 'host_id' or 'account_id' - Set-Property $_ login_event @($Content).Where({ $_.$Property -eq $Value }) - } + [string]$ReqId = if ($PSCmdlet.ParameterSetName -match 'hosts') { 'aid' } else { 'id' } + [string]$Property = if ($ReqId -eq 'aid') { 'aid' } else { 'account_id' } + for ($i=0; $i -lt ($Request | Measure-Object).Count; $i+=100) { + # In groups of 100, perform filtered search for login events + [string[]]$Group = @(@($Request)[$i..($i+99)]).Where({![string]::IsNullOrEmpty($_.$ReqId)}).$ReqId + Write-Host ($Group -join ',') + [string[]]$Filter = @($Group).foreach{ $Property,"'$_'" -join ':' } + $Content = & $MyInvocation.MyCommand.Name -Filter ($Filter -join ',') -Login -Detailed -All -EA 0 + foreach ($Value in $Group) { + @($Request).Where({$_.$ReqId -eq $Value}).foreach{ + # Append matched login events using 'aid' or 'account_id' + Set-Property $_ login_event @($Content).Where({$_.$Property -eq $Value}) } } } diff --git a/public/enrollments.ps1 b/public/enrollments.ps1 index 701c3c88..196a5473 100644 --- a/public/enrollments.ps1 +++ b/public/enrollments.ps1 @@ -1,11 +1,13 @@ function Invoke-FalconMobileAction { <# .SYNOPSIS -Trigger on-boarding process for a mobile device +Trigger on-boarding process for a device in Falcon for Mobile .DESCRIPTION Requires 'Mobile Enrollment: Write'. .PARAMETER Name Action to perform +.PARAMETER EnrollmentType +Enrollment type .PARAMETER ExpiresAt Expiration time [default: 30 days] .PARAMETER Email @@ -13,17 +15,20 @@ Email address .LINK https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconMobileAction #> - [CmdletBinding(DefaultParameterSetName='/enrollments/entities/details/v3:post',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/enrollments/entities/details/v4:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/enrollments/entities/details/v3:post',Mandatory,Position=1)] + [Parameter(ParameterSetName='/enrollments/entities/details/v4:post',Mandatory,Position=1)] [ValidateSet('enroll','re-enroll',IgnoreCase=$false)] [Alias('action_name')] [string]$Name, - [Parameter(ParameterSetName='/enrollments/entities/details/v3:post',Position=2)] + [Parameter(ParameterSetName='/enrollments/entities/details/v4:post',Position=2)] + [Alias('enrollment_type')] + [string]$EnrollmentType, + [Parameter(ParameterSetName='/enrollments/entities/details/v4:post',Position=3)] [Alias('expires_at')] [string]$ExpiresAt, - [Parameter(ParameterSetName='/enrollments/entities/details/v3:post',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] + [Parameter(ParameterSetName='/enrollments/entities/details/v4:post',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=4)] [ValidateScript({ if ((Test-RegexValue $_) -eq 'email') { $true } else { throw "'$_' is not a valid email address." } })] @@ -38,7 +43,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconMobileAction process { if ($Email) { @($Email).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Email'] = @($List | Select-Object -Unique) + $PSBoundParameters['Email'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/exclusions.ps1 b/public/exclusions.ps1 new file mode 100644 index 00000000..93f22c1d --- /dev/null +++ b/public/exclusions.ps1 @@ -0,0 +1,258 @@ +function Edit-FalconCertificateExclusion { +<# +.SYNOPSIS +Modify a certificate-based Machine Learning exclusion +.DESCRIPTION +Requires 'Machine Learning exclusions: Write'. +.PARAMETER Name +Exclusion name +.PARAMETER Description +Exclusion description +.PARAMETER Status +Exclusion status +.PARAMETER Certificate +Apply to all hosts in environment +.PARAMETER AppliedGlobally +Exclusion should be applied to all hosts +.PARAMETER MemberCid +Member CIDs, used when in a Flight Control environment +.PARAMETER GroupId +Host group identifier +.PARAMETER Comment +Audit log comment +.PARAMETER Id +Exclusion identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconCertificateExclusion +#> + [CmdletBinding(DefaultParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=1)] + [string]$Name, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=2)] + [string]$Description, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=3)] + [string]$Status, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=4)] + [object]$Certificate, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=5)] + [Alias('applied_globally')] + [boolean]$AppliedGlobally, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=6)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('children_cids')] + [string[]]$Cid, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=7)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('host_groups')] + [string[]]$GroupId, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch', + ValueFromPipelineByPropertyName,Position=8)] + [string]$Comment, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:patch',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=9)] + [string]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { + if ($PSBoundParameters.Certificate) { + # Force required properties in 'certificate' + $PSBoundParameters.Certificate = Select-CertificateProperty $PSBoundParameters.Certificate + } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } +} +function Get-FalconCertificate { +<# +.SYNOPSIS +Retrieve certificate signing information for a file +.DESCRIPTION +Requires 'Machine Learning exclusions: Read'. +.PARAMETER Id +Certificate identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCertificate +#> + [CmdletBinding(DefaultParameterSetName='/exclusions/entities/certificates/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/exclusions/entities/certificates/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [Alias('ids')] + [string]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconCertificateExclusion { +<# +.SYNOPSIS +Search for certificate-based Machine Learning exclusions +.DESCRIPTION +Requires 'Machine Learning exclusions: Read'. +.PARAMETER Id +Exclusion 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 [default: 100] +.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-FalconCertificateExclusion +#> + [CmdletBinding(DefaultParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Alias('ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get',Position=2)] + [ValidateSet('created_by.asc','created_by.desc','created_on.asc','created_on.desc','modified_by.asc', + 'modified_by.desc','modified_on.asc','modified_on.desc','name.asc','name.desc',IgnoreCase=$false)] + [string]$Sort, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get',Position=3)] + [ValidateRange(1,100)] + [int32]$Limit, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get')] + [switch]$Detailed, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/exclusions/queries/cert-based-exclusions/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($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function New-FalconCertificateExclusion { +<# +.SYNOPSIS +Create a certificate-based Machine Learning exclusion +.DESCRIPTION +Requires 'Machine Learning exclusions: Write'. +.PARAMETER Name +Exclusion name +.PARAMETER Description +Exclusion description +.PARAMETER Status +Exclusion status +.PARAMETER Certificate +Certificate detail +.PARAMETER AppliedGlobally +Apply to all hosts in environment +.PARAMETER MemberCid +Member CIDs, used when in a Flight Control environment +.PARAMETER GroupId +Host group identifier +.PARAMETER Comment +Audit log comment +.LINK +https://github.com/crowdstrike/psfalcon/wiki/New-FalconCertificateExclusion +#> + [CmdletBinding(DefaultParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post',Mandatory,Position=1)] + [string]$Name, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=2)] + [string]$Description, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=3)] + [string]$Status, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=4)] + [object]$Certificate, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=5)] + [Alias('applied_globally')] + [boolean]$AppliedGlobally, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=6)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('children_cids')] + [string[]]$MemberCid, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=7)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('host_groups')] + [string[]]$GroupId, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:post', + ValueFromPipelineByPropertyName,Position=8)] + [string]$Comment + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { + if ($PSBoundParameters.Certificate) { + # Force required properties in 'certificate' + $PSBoundParameters.Certificate = Select-CertificateProperty $PSBoundParameters.Certificate + } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } +} +function Remove-FalconCertificateExclusion { +<# +.SYNOPSIS +Remove certificate-based Machine Learning exclusions +.DESCRIPTION +Requires 'Machine Learning exclusions: Write'. +.PARAMETER Comment +Audit log comment +.PARAMETER Id +Exclusion identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCertificateExclusion +#> + [CmdletBinding(DefaultParameterSetName='/exclusions/entities/cert-based-exclusions/v1:delete', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:delete',Position=1)] + [string]$Comment, + [Parameter(ParameterSetName='/exclusions/entities/cert-based-exclusions/v1:delete',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] + [Alias('ids')] + [string[]]$Id + ) + 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) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} \ No newline at end of file diff --git a/public/falcon-complete-dashboards.ps1 b/public/falcon-complete-dashboards.ps1 index 29757d50..150894e8 100644 --- a/public/falcon-complete-dashboards.ps1 +++ b/public/falcon-complete-dashboards.ps1 @@ -3,7 +3,7 @@ function Get-FalconCompleteAlert { .SYNOPSIS Search for Falcon Complete alerts .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -45,7 +45,7 @@ function Get-FalconCompleteAllowlist { .SYNOPSIS Search for Falcon Complete Allowlist tickets .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -87,7 +87,7 @@ function Get-FalconCompleteBlocklist { .SYNOPSIS Search for Falcon Complete Blocklist tickets .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -129,7 +129,7 @@ function Get-FalconCompleteCollection { .SYNOPSIS Search for Falcon Complete device collections .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -174,7 +174,7 @@ function Get-FalconCompleteDetection { .SYNOPSIS Search for Falcon Complete detections .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -216,7 +216,7 @@ function Get-FalconCompleteEscalation { .SYNOPSIS Search for Falcon Complete escalations .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -258,7 +258,7 @@ function Get-FalconCompleteIncident { .SYNOPSIS Search for Falcon Complete incidents .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -300,7 +300,7 @@ function Get-FalconCompleteRemediation { .SYNOPSIS Search for Falcon Complete remediations .DESCRIPTION -Requires 'Falcon Complete dashboard: Read'. +Requires 'Falcon Complete Dashboards: Read'. .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort diff --git a/public/falconx.ps1 b/public/falconx.ps1 index 72338f5e..e32991df 100644 --- a/public/falconx.ps1 +++ b/public/falconx.ps1 @@ -32,7 +32,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReport [Parameter(ParameterSetName='/falconx/entities/report-summaries/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/falconx/queries/reports/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -57,10 +57,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReport $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconSubmission { @@ -93,7 +97,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSubmission [Parameter(ParameterSetName='/falconx/entities/submissions/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/falconx/queries/submissions/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -116,10 +120,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSubmission $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconSubmissionQuota { @@ -399,7 +407,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReport param( [Parameter(ParameterSetName='/falconx/entities/reports/v1:delete',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] - [Alias('Ids')] + [Alias('ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/fdr.ps1 b/public/fdr.ps1 index c16f3a0f..c3337194 100644 Binary files a/public/fdr.ps1 and b/public/fdr.ps1 differ diff --git a/public/fem.ps1 b/public/fem.ps1 new file mode 100644 index 00000000..b24f6c68 Binary files /dev/null and b/public/fem.ps1 differ diff --git a/public/filevantage.ps1 b/public/filevantage.ps1 index 8dc25f83..5f16f471 100644 --- a/public/filevantage.ps1 +++ b/public/filevantage.ps1 @@ -31,7 +31,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconFileVantageHostGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $PSBoundParameters['action'] = 'assign' Invoke-Falcon @Param -UserInput $PSBoundParameters } @@ -70,7 +70,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconFileVantageRuleGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $PSBoundParameters['action'] = 'assign' Invoke-Falcon @Param -UserInput $PSBoundParameters } @@ -135,17 +135,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFileVantageExclusion [string]$Timezone, [Parameter(ParameterSetName='/filevantage/entities/policy-scheduled-exclusions/v1:patch', ValueFromPipelineByPropertyName,Position=7)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconFileVantageExclusion' - Endpoint = '/filevantage/entities/policy-scheduled-exclusions/v1:patch' - Allowed = @('all_day','end_time','frequency','monthly_days','occurrence','start_time','weekly_days') - } - Confirm-Parameter @Param - } - })] [object]$Repeated, [Parameter(ParameterSetName='/filevantage/entities/policy-scheduled-exclusions/v1:patch', ValueFromPipelineByPropertyName,Position=8)] @@ -163,18 +152,19 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFileVantageExclusion [string]$Description ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Body = @{ - root = @('description','id','name','policy_id','processes','repeated','schedule_end','schedule_start', - 'timezone','users') - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Format + } + process { + if ($PSBoundParameters.Repeated) { + # Filter to defined 'repeated' properties and make sure 'repeated' is properly appended + $PSBoundParameters.Repeated = [PSCustomObject]$PSBoundParameters.Repeated | + Select-Object $Param.Format.Body.repeated + [void]$Param.Format.Body.Remove('repeated') + $Param.Format.Body.root += 'repeated' } + Invoke-Falcon @Param -UserInput $PSBoundParameters } - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } function Edit-FalconFileVantagePolicy { <# @@ -270,6 +260,8 @@ Track file write events Track registry key create events .PARAMETER RegKeyDelete Track registry key delete events +.PARAMETER RegKeyPermission +Track registry key permission change events .PARAMETER RegKeyRename Track registry key rename events .PARAMETER RegKeySet @@ -282,6 +274,10 @@ Track registry value delete events Enable the capture of file content during events .PARAMETER ContentFiles A specific list of files to monitor for content changes +.PARAMETER ContentRegistryValues +A specific list of registry paths to monitor for content changes (matching Include/Exclude) +.PARAMETER HashCapture +Track file hash .PARAMETER RuleGroupId FileVantage rule group identifier .LINK @@ -388,28 +384,40 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFileVantageRule [boolean]$RegKeyDelete, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, Position=26)] + [Alias('watch_permissions_key_changes')] + [boolean]$RegKeyPermission, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, + Position=27)] [Alias('watch_rename_key_changes')] [boolean]$RegKeyRename, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, - Position=27)] + Position=28)] [Alias('watch_set_value_changes')] [boolean]$RegKeySet, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, - Position=28)] + Position=29)] [Alias('watch_create_value_changes')] [boolean]$RegValueCreate, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, - Position=29)] + Position=30)] [Alias('watch_delete_value_changes')] [boolean]$RegValueDelete, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, - Position=30)] + Position=31)] [Alias('enable_content_capture')] [boolean]$EnableContentCapture, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, - Position=31)] + Position=32)] [Alias('content_files')] [string[]]$ContentFiles, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, + Position=33)] + [Alias('content_registry_values')] + [string[]]$ContentRegistryValues, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',ValueFromPipelineByPropertyName, + Position=34)] + [Alias('enable_hash_capture')] + [boolean]$HashCapture, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:patch',Mandatory, ValueFromPipelineByPropertyName)] [ValidatePattern('^[a-fA-F0-9]{32}$')] @@ -450,6 +458,69 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFileVantageRuleGroup begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } +function Get-FalconFileVantageAction { +<# +.SYNOPSIS +Search for Falcon FileVantage actions +.DESCRIPTION +Requires 'Falcon FileVantage: Read'. +.PARAMETER Id +FileVantage action 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 [default: 100] +.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-FalconFileVantageAction +#> + [CmdletBinding(DefaultParameterSetName='/filevantage/queries/actions/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/filevantage/entities/actions/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get',Position=3)] + [ValidateRange(1,500)] + [int32]$Limit, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get')] + [switch]$Detailed, + [Parameter(ParameterSetName='/filevantage/queries/actions/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/filevantage/queries/actions/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($_) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} function Get-FalconFileVantageChange { <# .SYNOPSIS @@ -457,7 +528,7 @@ Search for Falcon FileVantage changes .DESCRIPTION Requires 'Falcon FileVantage: Read'. .PARAMETER Id -Activity identifier +FileVantage change identifier .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -481,12 +552,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageChange [Parameter(ParameterSetName='/filevantage/entities/changes/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/filevantage/queries/changes/v3:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] [string]$Filter, [Parameter(ParameterSetName='/filevantage/queries/changes/v3:get',Position=2)] + [ValidateSet('action_timestamp|asc','action_timestamp|desc','ingestion_timestamp|asc', + 'ingestion_timestamp|desc',IgnoreCase=$false)] [string]$Sort, [Parameter(ParameterSetName='/filevantage/queries/changes/v3:get',Position=3)] [ValidateRange(1,5000)] @@ -504,12 +577,36 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageChange $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } +function Get-FalconFileVantageContent { +<# +.SYNOPSIS +Retrieve content recorded in a Falcon FileVantage change +.DESCRIPTION +Requires 'Falcon FileVantage Content: Read'. +.PARAMETER Id +FileVantage change identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageContent +#> + [CmdletBinding(DefaultParameterSetName='/filevantage/entities/change-content/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/filevantage/entities/change-content/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [string]$Id + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} function Get-FalconFileVantageExclusion { <# .SYNOPSIS @@ -541,10 +638,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageExclusion $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFileVantagePolicy { @@ -609,7 +710,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantagePolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters if ($Request -and $Include -contains 'exclusions') { @@ -660,7 +761,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageRule process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -720,10 +821,84 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFileVantageRuleGroup $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) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Invoke-FalconFileVantageAction { +<# +.SYNOPSIS +Perform actions on Falcon FileVantage changes +.DESCRIPTION +Requires 'Falcon FileVantage: Write'. +.PARAMETER Name +Action to perform +.PARAMETER Comment +Audit log comment +.PARAMETER Id +FileVantage change identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconFileVantageAction +#> + [CmdletBinding(DefaultParameterSetName='/filevantage/entities/actions/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/filevantage/entities/actions/v1:post',Mandatory,Position=1)] + [ValidateSet('suppress','unsuppress','purge',IgnoreCase=$false)] + [Alias('operation')] + [string]$Name, + [Parameter(ParameterSetName='/filevantage/entities/actions/v1:post',Position=2)] + [string]$Comment, + [Parameter(ParameterSetName='/filevantage/entities/actions/v1:post',ValueFromPipelineByPropertyName, + ValueFromPipeline,Position=3)] + [Alias('change_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 | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Invoke-FalconFileVantageWorkflow { +<# +.SYNOPSIS +Execute an on-demand Falcon Fusion workflow for Falcon FileVantage changes +.DESCRIPTION +Requires 'Falcon FileVantage: Write'. +.PARAMETER Id +FileVantage change identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconFileVantageWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/filevantage/entities/workflow/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/filevantage/entities/workflow/v1:post',ValueFromPipelineByPropertyName, + ValueFromPipeline,Mandatory,Position=1)] + [Alias('ids')] + [string[]]$Id + ) + 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) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconFileVantageExclusion { @@ -774,17 +949,6 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFileVantageExclusion [string]$Timezone, [Parameter(ParameterSetName='/filevantage/entities/policy-scheduled-exclusions/v1:post', ValueFromPipelineByPropertyName,Position=5)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconFileVantageExclusion' - Endpoint = '/filevantage/entities/policy-scheduled-exclusions/v1:post' - Allowed = @('all_day','end_time','frequency','monthly_days','occurrence','start_time','weekly_days') - } - Confirm-Parameter @Param - } - })] [object]$Repeated, [Parameter(ParameterSetName='/filevantage/entities/policy-scheduled-exclusions/v1:post', ValueFromPipelineByPropertyName,Position=6)] @@ -807,18 +971,19 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFileVantageExclusion [string]$PolicyId ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Body = @{ - root = @('description','name','policy_id','processes','repeated','schedule_end','schedule_start', - 'timezone','users') - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Format + } + process { + if ($PSBoundParameters.Repeated) { + # Filter to defined 'repeated' properties and make sure 'repeated' is properly appended + $PSBoundParameters.Repeated = [PSCustomObject]$PSBoundParameters.Repeated | + Select-Object $Param.Format.Body.repeated + [void]$Param.Format.Body.Remove('repeated') + $Param.Format.Body.root += 'repeated' } + Invoke-Falcon @Param -UserInput $PSBoundParameters } - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } function New-FalconFileVantagePolicy { <# @@ -907,6 +1072,8 @@ Track file write events Track registry key create events .PARAMETER RegKeyDelete Track registry key delete events +.PARAMETER RegKeyPermission +Track registry key permission change events .PARAMETER RegKeyRename Track registry key rename events .PARAMETER RegKeySet @@ -919,6 +1086,10 @@ Track registry value delete events Enable the capture of file content during events .PARAMETER ContentFiles A specific list of files to monitor for content changes +.PARAMETER ContentRegistryValues +A specific list of registry paths to monitor for content changes (matching Include/Exclude) +.PARAMETER HashCapture +Track file hash .PARAMETER RuleGroupId FileVantage rule group identifier .LINK @@ -1021,28 +1192,40 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFileVantageRule [boolean]$RegKeyDelete, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, Position=25)] + [Alias('watch_permissions_key_changes')] + [boolean]$RegKeyPermission, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, + Position=26)] [Alias('watch_rename_key_changes')] [boolean]$RegKeyRename, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, - Position=26)] + Position=27)] [Alias('watch_set_value_changes')] [boolean]$RegKeySet, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, - Position=27)] + Position=28)] [Alias('watch_create_value_changes')] [boolean]$RegValueCreate, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, - Position=27)] + Position=29)] [Alias('watch_delete_value_changes')] [boolean]$RegValueDelete, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, - Position=28)] + Position=30)] [Alias('enable_content_capture')] [boolean]$EnableContentCapture, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, - Position=29)] + Position=31)] [Alias('content_files')] [string[]]$ContentFiles, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, + Position=32)] + [Alias('content_registry_values')] + [string[]]$ContentRegistryValues, + [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',ValueFromPipelineByPropertyName, + Position=33)] + [Alias('enable_hash_capture')] + [boolean]$HashCapture, [Parameter(ParameterSetName='/filevantage/entities/rule-groups-rules/v1:post',Mandatory, ValueFromPipelineByPropertyName)] [ValidatePattern('^[a-fA-F0-9]{32}$')] @@ -1119,7 +1302,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFileVantageExclusion process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1157,7 +1340,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFileVantageHostGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $PSBoundParameters['action'] = 'unassign' Invoke-Falcon @Param -UserInput $PSBoundParameters } @@ -1189,7 +1372,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFileVantagePolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1227,7 +1410,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFileVantageRule process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1265,7 +1448,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFileVantageRuleGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) if ($PSCmdlet.ParameterSetName -match 'patch$') { $PSBoundParameters['action'] = 'unassign' } Invoke-Falcon @Param -UserInput $PSBoundParameters } @@ -1305,7 +1488,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFileVantagePrecedence process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1343,7 +1526,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFileVantageRulePrecedence process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1381,7 +1564,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFileVantageRuleGroupPrece process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $PSBoundParameters['action'] = 'precedence' Invoke-Falcon @Param -UserInput $PSBoundParameters } diff --git a/public/fwmgr.ps1 b/public/fwmgr.ps1 index fc6a9715..d140f790 100644 --- a/public/fwmgr.ps1 +++ b/public/fwmgr.ps1 @@ -6,8 +6,8 @@ Modify Falcon Firewall Management rule groups All fields (plus 'rulegroup_version' and 'tracking') are required when making a rule group change. PSFalcon adds missing values automatically using data from your existing rule group. -'DiffOperation' array objects must contain 'op', 'path' and 'value' properties. Accepted 'op' values are 'add', -'remove' and 'replace'. +'DiffOperation' array objects must contain 'from', 'op', 'path' and 'value' properties. Accepted 'op' values are +'add', 'remove' and 'replace'. When adding a rule to a rule group,the required rule fields must be included along with a 'temp_id' (in both the rule properties and in precedence order within 'rule_ids') to establish proper placement of the rule within the @@ -33,21 +33,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallGroup param( [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:patch',Mandatory,Position=1)] [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:patch',Mandatory,Position=1)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconFirewallGroup' - Endpoint = '/fwmgr/entities/rule-groups/v1:patch' - Required = @('op','path') - } - Confirm-Parameter @Param - if ($Object.op -notmatch '^(add|remove|replace)$') { - $ObjectString = ConvertTo-Json $Object -Compress - throw "'$($Object.op)' is not a valid 'op' value. $ObjectString" - } - } - })] [Alias('diff_operations','DiffOperations')] [object[]]$DiffOperation, [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:patch',Position=2)] @@ -62,9 +47,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallGroup [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:patch',Position=4)] [ValidatePattern('^(null|\d+)$')] [Alias('rule_versions','RuleVersions')] - [int[]]$RuleVersion, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:patch',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline,Position=5)] + [string[]]$RuleVersion, + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:patch',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline,Position=5)] [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=5)] [ValidatePattern('^[a-fA-F0-9]{32}$')] @@ -73,45 +58,53 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallGroup [switch]$Validate ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Query = @('comment') - Body = @{ - root = @('rule_ids','tracking','id','diff_type','rule_versions','diff_operations', - 'rulegroup_version') + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + [System.Collections.Generic.List[object]]$List = @() + } + process { + if ($DiffOperation) { + @($DiffOperation).foreach{ + # Filter to defined 'diff_operations' properties + [PSCustomObject]$i = $_ | Select-Object $Param.Format.Body.diff_operations + if ($i.op -and $i.op -notmatch '^(add|remove|replace)$') { + # Ignore if 'op' is an unexpected value + $ObjectString = ConvertTo-Json $i -Compress + Write-Error "'$($i.op)' is not a valid 'op' value. $ObjectString" + } else { + $List.Add($i) } } } } - process { + end { if ($PSCmdlet.ShouldProcess('Edit-FalconFirewallGroup','Get-FalconFirewallGroup')) { - $Format = Get-EndpointFormat $PSCmdlet.ParameterSetName - if ($Format) { - @($Format.Body.root).Where({ $_ -notmatch '^(diff_operations|id)$' }).foreach{ - if (!$PSBoundParameters.$_) { - # When not provided, add required fields using existing rule group - if (!$Group) { $Group = try { Get-FalconFirewallGroup -Id $PSBoundParameters.Id -EA 0 } catch {}} - $PSBoundParameters[$_] = if ($_ -eq 'rulegroup_version') { - if ($Group.version) { $Group.version } else { 0 } - } elseif ($_ -eq 'rule_versions') { - if ($PSBoundParameters.RuleId) { - (Get-FalconFirewallRule -Id $PSBoundParameters.RuleId).version - } else { - (Get-FalconFirewallRule -Id $Group.rule_ids).version - } + # Remove remaining 'DiffOperation' value + [void]$PSBoundParameters.Remove('DiffOperation') + @($Param.Format.Body.root).Where({$_ -ne 'id'}).foreach{ + if (!$PSBoundParameters.$_) { + # When not provided, add required fields using existing rule group + if (!$Group) { $Group = try { Get-FalconFirewallGroup -Id $PSBoundParameters.Id -EA 0 } catch {} } + $PSBoundParameters[$_] = if ($_ -eq 'rulegroup_version') { + if ($Group.version) { $Group.version } else { 0 } + } elseif ($_ -eq 'rule_versions') { + if ($PSBoundParameters.RuleId) { + (Get-FalconFirewallRule -Id $PSBoundParameters.RuleId).version } else { - $Group.$_ + (Get-FalconFirewallRule -Id $Group.rule_ids).version } + } else { + $Group.$_ } } } - if (!$PSBoundParameters.Tracking) { - throw "Unable to obtain 'tracking' value from rule group '$($PSBoundParameters.Id)'." - } + if (!$PSBoundParameters.Tracking) { throw "Unable to obtain 'tracking' value from rule group '$($Id)'." } } + # Add 'diff_type', add 'diff_operations' as an array and modify 'Format' $PSBoundParameters['diff_type'] = 'application/json-patch+json' + $PSBoundParameters['diff_operations'] = @($List) + [void]$Param.Format.Body.Remove('diff_operations') + $Param.Format.Body.root += 'diff_operations' Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -241,7 +234,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallLocationSetting SupportsShouldProcess)] param( [Parameter(ParameterSetName='/fwmgr/entities/network-locations-metadata/v1:post',Position=1)] - [ValidatePattern('^[a-fA-F0-9]{32}$')] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/fwmgr/entities/network-locations-metadata/v1:post',Position=2)] [Alias('icmp_request_targets_polling_interval')] @@ -260,7 +253,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallLocationSetting [string]$Comment ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } + process { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } function Edit-FalconFirewallSetting { <# @@ -374,7 +370,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallEvent param( [Parameter(ParameterSetName='/fwmgr/entities/events/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/fwmgr/queries/events/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -402,10 +398,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallEvent $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFirewallField { @@ -435,7 +435,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallField param( [Parameter(ParameterSetName='/fwmgr/entities/firewall-fields/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/fwmgr/queries/firewall-fields/v1:get',Position=1)] [ValidateSet('0','1')] @@ -457,10 +457,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallField $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFirewallGroup { @@ -497,7 +501,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallGroup [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/fwmgr/queries/rule-groups/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -525,10 +529,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallGroup $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFirewallLocation { @@ -592,10 +600,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallLocation $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFirewallPlatform { @@ -624,7 +636,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallPlatform [Parameter(ParameterSetName='/fwmgr/entities/platforms/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidateSet('0','1')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/fwmgr/queries/platforms/v1:get',Position=1)] [ValidateRange(1,5000)] @@ -642,10 +654,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallPlatform $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconFirewallRule { @@ -683,7 +699,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallRule param( [Parameter(ParameterSetName='/fwmgr/entities/rules/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/fwmgr/queries/policy-rules/v1:get',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] @@ -730,7 +746,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallRule end { if ($List) { $Param['Format'] = @{ Query = @('ids') } - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) } $Request = @(Invoke-Falcon @Param -UserInput $PSBoundParameters).foreach{ if ($_.version -and $null -eq $_.version) { $_.version = 0 } @@ -763,7 +779,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallSetting [Parameter(ParameterSetName='/fwmgr/entities/policies/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -773,7 +789,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallSetting process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -807,31 +823,28 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFirewallGroup #> [CmdletBinding(DefaultParameterSetName='/fwmgr/entities/rule-groups/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=1)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=1)] [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',Mandatory, ValueFromPipelineByPropertyName,Position=1)] [string]$Name, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=2)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=2)] [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',Mandatory, ValueFromPipelineByPropertyName,Position=2)] [boolean]$Enabled, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName, + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName,Position=3)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',ValueFromPipelineByPropertyName, Position=3)] - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post', - ValueFromPipelineByPropertyName,Position=3)] [string]$Description, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName, + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName,Position=4)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',ValueFromPipelineByPropertyName, Position=4)] - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post', - ValueFromPipelineByPropertyName,Position=4)] [Alias('rules')] [object[]]$Rule, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName, + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName,Position=5)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',ValueFromPipelineByPropertyName, Position=5)] - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post', - ValueFromPipelineByPropertyName,Position=5)] [string]$Comment, [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',Position=6)] [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',Position=6)] @@ -841,30 +854,37 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFirewallGroup [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('clone_id','id')] [string]$CloneId, - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName, + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:post',ValueFromPipelineByPropertyName,Position=8)] + [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',ValueFromPipelineByPropertyName, Position=8)] - [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post', - ValueFromPipelineByPropertyName,Position=8)] [string]$Platform, [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/validation/v1:post',Mandatory)] [switch]$Validate ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Query = @('library','comment','clone_id') - Body = @{ root = @('enabled','name','rules','description','platform') } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + [System.Collections.Generic.List[object]]$List = @() + } + process { + if ($Rule) { + @($Rule).foreach{ + # Filter to defined 'rules' properties and remove empty values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.rules + Remove-EmptyValue $i name,description,comment + $List.Add($i) } } } - process { - if ($PSBoundParameters.Rule) { - [object[]]$PSBoundParameters.Rule = Confirm-Property 'action','address_family','description', - 'direction','enabled','fields','fqdn','fqdn_enabled','icmp','local_address','local_port','log', - 'monitor','name','protocol','remote_address','remote_port','temp_id' $PSBoundParameters.Rule + end { + if ($List) { + # Add 'rules' as an array and remove remaining value + $PSBoundParameters['rules'] = @($List) + [void]$PSBoundParameters.Remove('Rule') } + # Modify 'Format' to ensure 'rules' is properly appended and make request + [void]$Param.Format.Body.Remove('rules') + $Param.Format.Body.root += 'rules' Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -994,7 +1014,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFirewallGroup [Parameter(ParameterSetName='/fwmgr/entities/rule-groups/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -1004,7 +1024,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFirewallGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1035,7 +1055,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFirewallLocation process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -1059,6 +1079,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFirewallLocationPrecedenc SupportsShouldProcess)] param( [Parameter(ParameterSetName='/fwmgr/entities/network-locations-precedence/v1:post',Position=1)] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/fwmgr/entities/network-locations-precedence/v1:post',Position=2)] [string]$Comment, @@ -1068,7 +1089,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFirewallLocationPrecedenc [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } + process { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } function Test-FalconFirewallPath { <# diff --git a/public/host-migration.ps1 b/public/host-migration.ps1 new file mode 100644 index 00000000..1a23c433 Binary files /dev/null and b/public/host-migration.ps1 differ diff --git a/public/identity-protection.ps1 b/public/identity-protection.ps1 index 623c8360..52db9a92 100644 --- a/public/identity-protection.ps1 +++ b/public/identity-protection.ps1 @@ -124,7 +124,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIdentityHost [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')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id, [Parameter(ParameterSetName='/identity-protection/queries/devices/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -147,18 +147,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIdentityHost $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 - } - } + process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { $Param['Max'] = 5000 - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) - Invoke-Falcon @Param -UserInput $PSBoundParameters + $PSBoundParameters['Id'] = @($List) } + Invoke-Falcon @Param -UserInput $PSBoundParameters } } \ No newline at end of file diff --git a/public/image-assessment.ps1 b/public/image-assessment.ps1 index a5cd33dc..fbfd0fec 100644 --- a/public/image-assessment.ps1 +++ b/public/image-assessment.ps1 @@ -1,5 +1,6 @@ -function Get-FalconContainerVulnerability { <# +function Get-FalconContainerVulnerability { +# .SYNOPSIS Retrieve known vulnerabilities for the provided image .DESCRIPTION @@ -13,48 +14,57 @@ Key and value pairs to filter packages. Accepted properties include: 'layerhash' Key and value pairs to filter application packages. Accepted properties include: 'libraries' and 'type'. .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerVulnerability -#> +# [CmdletBinding(DefaultParameterSetName='/image-assessment/combined/vulnerability-lookups/v1:post', SupportsShouldProcess)] param( [Parameter(ParameterSetName='/image-assessment/combined/vulnerability-lookups/v1:post',Position=1)] [string]$OsVersion, [Parameter(ParameterSetName='/image-assessment/combined/vulnerability-lookups/v1:post',Position=2)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Get-FalconContainerVulnerability' - Endpoint = '/image-assessment/combined/vulnerability-lookups/v1:post' - Allowed = @('layerindex','packageprovider','layerhash','packagehash','packagesource', - 'softwarearchitecture','status','majorversion','product','vendor') - } - Confirm-Parameter @Param - } - })] [Alias('packages')] [object[]]$Package, [Parameter(ParameterSetName='/image-assessment/combined/vulnerability-lookups/v1:post',Position=3)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Get-FalconContainerVulnerability' - Endpoint = '/image-assessment/combined/vulnerability-lookups/v1:post' - Allowed = @('libraries','type') - } - Confirm-Parameter @Param - } - })] [Alias('applicationPackages')] [object[]]$Application ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ Body = @{ root = @('osversion','packages','applicationPackages') }} + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + [System.Collections.Generic.List[object]]$PackList = @() + [System.Collections.Generic.List[object]]$AppList = @() + } + process { + if ($Package) { + @($Package).foreach{ + # Filter to defined 'packages' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.packages + $PackList.Add($i) + } + } + if ($Application) { + @($Application).foreach{ + # Filter to defined 'applicationPackages' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.applicationPackages + $AppList.Add($i) + } + } + } + end { + if ($PackList) { + # Add 'packages' as an array and remove remaining value + $PSBoundParameters['packages'] = @($PackList) + [void]$PSBoundParameters.Remove('Package') + } + if ($AppList) { + # Add 'packages' as an array and remove remaining value + $PSBoundParameters['applicationPackages'] = @($AppList) + [void]$PSBoundParameters.Remove('Application') } + # Modify 'Format' to ensure 'packages' and 'applicationPackages' are properly appended and make request + [void]$Param.Format.Body.Remove('packages') + [void]$Param.Format.Body.Remove('applicationPackages') + $Param.Format.Body.root += 'packages','applicationPackages' + Invoke-Falcon @Param -UserInput $PSBoundParameters } - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } -} \ No newline at end of file +} +#> \ No newline at end of file diff --git a/public/incidents.ps1 b/public/incidents.ps1 index e8dca867..b3c7952b 100644 --- a/public/incidents.ps1 +++ b/public/incidents.ps1 @@ -28,7 +28,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconBehavior [Parameter(ParameterSetName='/incidents/entities/behaviors/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^ind:[a-fA-F0-9]{32}:(\d|\-)+$')] - [Alias('Ids','behavior_id')] + [Alias('ids','behavior_id')] [string[]]$Id, [Parameter(ParameterSetName='/incidents/queries/behaviors/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -52,10 +52,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconBehavior $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIncident { @@ -88,7 +92,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIncident [Parameter(ParameterSetName='/incidents/entities/incidents/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^inc:[a-fA-F0-9]{32}:[a-fA-F0-9]{32}$')] - [Alias('Ids','incident_id')] + [Alias('ids','incident_id')] [string[]]$Id, [Parameter(ParameterSetName='/incidents/queries/incidents/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -115,10 +119,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIncident $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconScore { @@ -173,6 +181,8 @@ Requires 'Incidents: Write'. Action to perform .PARAMETER Value Value for the chosen action +.PARAMETER Action +One or more hashtables defining multiple name/value pairs .PARAMETER UpdateDetects Update status of related 'new' detections .PARAMETER OverwriteDetects @@ -188,39 +198,52 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconIncidentAction [ValidateSet('add_tag','delete_tag','unassign','update_description','update_name','update_status', 'update_assigned_to_v2',IgnoreCase=$false)] [string]$Name, - [Parameter(ParameterSetName='/incidents/entities/incident-actions/v1:post',Mandatory,Position=2)] + [Parameter(ParameterSetName='/incidents/entities/incident-actions/v1:post',Position=2)] [string]$Value, + [Parameter(ParameterSetName='action_parameters',Mandatory,Position=1)] + [Alias('action_parameters')] + [hashtable[]]$Action, [Parameter(ParameterSetName='/incidents/entities/incident-actions/v1:post',Position=3)] + [Parameter(ParameterSetName='action_parameters',Position=2)] [Alias('update_detects')] [boolean]$UpdateDetects, [Parameter(ParameterSetName='/incidents/entities/incident-actions/v1:post',Position=4)] + [Parameter(ParameterSetName='action_parameters',Position=3)] [Alias('overwrite_detects')] [boolean]$OverwriteDetects, [Parameter(ParameterSetName='/incidents/entities/incident-actions/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=5)] + [Parameter(ParameterSetName='action_parameters',Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline, + Position=4)] [ValidatePattern('^inc:[a-fA-F0-9]{32}:[a-fA-F0-9]{32}$')] - [Alias('Ids','incident_id')] + [Alias('ids','incident_id')] [string[]]$Id ) begin { - $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 1000 } + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = '/incidents/entities/incident-actions/v1:post' + Max = 1000 + } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) - if ($PSBoundParameters.Name -eq 'update_status') { - if ($PSBoundParameters.Value -notmatch '^(closed|in_progress|new|reopened)$') { - throw "Valid values for 'update_status': 'closed', 'in_progress', 'new', 'reopened'." - } else { - $PSBoundParameters['Value'] = switch ($PSBoundParameters.Value) { - 'new' { '20' } - 'reopened' { '25' } - 'in_progress' { '30' } - 'closed' { '40' } - } + $PSBoundParameters['Id'] = @($List) + if ($PSBoundParameters.Action) { + # Verify valid 'Action' key/value pairs and update formatting before request + $Valid = (Get-Command $Param.Command).Parameters.Name.Attributes.ValidValues + [hashtable[]]$PSBoundParameters.Action = @($PSBoundParameters.Action).foreach{ + Test-ActionParameter $_ $Valid -Incident } + $Param.Format.Body.root = @('ids','action_parameters') + [void]$Param.Format.Body.Remove('action_parameters') + } else { + # Update 'value' when 'name' is 'update_status' + $Valid = Test-ActionParameter @{ $PSBoundParameters.Name = $PSBoundParameters.Value } -Incident + if ($Valid -and $PSBoundParameters.Value -ne $Valid.Value) { $PSBoundParameters.Value = $Valid.Value } } Invoke-Falcon @Param -UserInput $PSBoundParameters } diff --git a/public/indicators.ps1 b/public/indicators.ps1 index 4ab39c4d..c97ac672 100644 --- a/public/indicators.ps1 +++ b/public/indicators.ps1 @@ -23,13 +23,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIocHost param( [Parameter(ParameterSetName='/indicators/queries/devices/v1:get',Mandatory, ValueFromPipelineByPropertyName,Position=1)] - [Parameter(ParameterSetName='/indicators/aggregates/devices-count/v1:get',Mandatory, + [Parameter(ParameterSetName='/iocs/aggregates/indicators/device-count/v1:get',Mandatory, ValueFromPipelineByPropertyName,Position=1)] [ValidateSet('domain','ipv4','ipv6','md5','sha256',IgnoreCase=$false)] [string]$Type, [Parameter(ParameterSetName='/indicators/queries/devices/v1:get',Mandatory, ValueFromPipelineByPropertyName,Position=2)] - [Parameter(ParameterSetName='/indicators/aggregates/devices-count/v1:get',Mandatory, + [Parameter(ParameterSetName='/iocs/aggregates/indicators/device-count/v1:get',Mandatory, ValueFromPipelineByPropertyName,Position=2)] [string]$Value, [Parameter(ParameterSetName='/indicators/queries/devices/v1:get',Position=3)] @@ -39,7 +39,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIocHost [int32]$Offset, [Parameter(ParameterSetName='/indicators/queries/devices/v1:get')] [switch]$All, - [Parameter(ParameterSetName='/indicators/aggregates/devices-count/v1:get',Mandatory)] + [Parameter(ParameterSetName='/iocs/aggregates/indicators/device-count/v1:get',Mandatory)] [switch]$Total ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -74,7 +74,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIocProcess param( [Parameter(ParameterSetName='/processes/entities/processes/v1:get',ValueFromPipeline,Mandatory)] [ValidatePattern('^pid:[a-fA-F0-9]{32}:\d+$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/indicators/queries/processes/v1:get',Mandatory,Position=1)] [ValidateSet('domain','ipv4','ipv6','md5','sha256',IgnoreCase=$false)] @@ -100,9 +100,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIocProcess $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } \ No newline at end of file diff --git a/public/installation-tokens.ps1 b/public/installation-tokens.ps1 index 93f7df0d..787da3c0 100644 --- a/public/installation-tokens.ps1 +++ b/public/installation-tokens.ps1 @@ -57,7 +57,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconInstallToken [Parameter(ParameterSetName='/installation-tokens/entities/tokens/v1:patch',Mandatory, ValueFromPipelineByPropertyName,Position=4)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -67,7 +67,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconInstallToken process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -102,7 +102,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstallToken [Parameter(ParameterSetName='/installation-tokens/entities/tokens/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/installation-tokens/queries/tokens/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -125,10 +125,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstallToken $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconInstallTokenEvent { @@ -162,7 +166,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstallTokenEvent [Parameter(ParameterSetName='/installation-tokens/entities/audit-events/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/installation-tokens/queries/audit-events/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -184,10 +188,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstallTokenEvent $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconInstallTokenSetting { @@ -205,7 +213,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstallTokenSetting [CmdletBinding(DefaultParameterSetName='/installation-tokens/entities/customer-settings/v1:get', SupportsShouldProcess)] param() - process { Invoke-Falcon -Endpoint $PSCmdlet.ParameterSetName } + process { Invoke-Falcon -Command $MyInvocation.MyCommand.Name -Endpoint $PSCmdlet.ParameterSetName } } function New-FalconInstallToken { <# @@ -248,7 +256,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconInstallToken [Parameter(ParameterSetName='/installation-tokens/entities/tokens/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -258,7 +266,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconInstallToken process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/intel.ps1 b/public/intel.ps1 index ad7147bf..ab1e7bab 100644 --- a/public/intel.ps1 +++ b/public/intel.ps1 @@ -33,7 +33,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconActor param( [Parameter(ParameterSetName='/intel/entities/actors/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/intel/queries/actors/v1:get',Position=1)] [Parameter(ParameterSetName='/intel/combined/actors/v1:get',Position=1)] @@ -79,7 +79,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconActor } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters if (!$Request.slug) { $Request = $Request | & $MyInvocation.MyCommand.Name | Select-Object id,slug } @@ -133,7 +133,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconAttck } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -194,10 +194,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCve $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIndicator { @@ -235,7 +239,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIndicator param( [Parameter(ParameterSetName='/intel/entities/indicators/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/intel/queries/indicators/v1:get',Position=1)] [Parameter(ParameterSetName='/intel/combined/indicators/v1:get',Position=1)] @@ -278,10 +282,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIndicator $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIntel { @@ -317,7 +325,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIntel param( [Parameter(ParameterSetName='/intel/entities/reports/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/intel/queries/reports/v1:get',Position=1)] [Parameter(ParameterSetName='/intel/combined/reports/v1:get',Position=1)] @@ -356,10 +364,87 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIntel $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Get-FalconMalwareFamily { +<# +.SYNOPSIS +Search for malware families +.DESCRIPTION +Requires 'Malware Families (Falcon Intelligence): Read'. +.PARAMETER Id +Malware family identifier +.PARAMETER Filter +Falcon Query Language expression to limit results +.PARAMETER Query +Perform a generic substring search across available fields +.PARAMETER Sort +Property and direction to sort results +.PARAMETER Limit +Maximum number of results per request +.PARAMETER Offset +Position to begin retrieving results +.PARAMETER Mitre +Retrieve MITRE TTP information for malware families +.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-FalconMalwareFamily +#> + [CmdletBinding(DefaultParameterSetName='/intel/queries/malware/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/intel/entities/malware/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] + [Parameter(ParameterSetName='/intel/queries/mitre-malware/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] + [Alias('ids')] + [string[]]$Id, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get',Position=2)] + [Alias('q')] + [string]$Query, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get',Position=3)] + [string]$Sort, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get',Position=4)] + [ValidateRange(1,5000)] + [int32]$Limit, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get')] + [int32]$Offset, + [Parameter(ParameterSetName='/intel/queries/mitre-malware/v1:get',Mandatory)] + [switch]$Mitre, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get')] + [switch]$Detailed, + [Parameter(ParameterSetName='/intel/queries/malware/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/intel/queries/malware/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($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconRule { @@ -404,7 +489,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRule [Parameter(ParameterSetName='/intel/entities/rules/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^\d{4,}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/intel/queries/rules/v1:get',Mandatory,Position=1)] [ValidateSet('snort-suricata-master','snort-suricata-update','snort-suricata-changelog','yara-master', @@ -444,10 +529,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRule $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Receive-FalconAttck { diff --git a/public/ioa.ps1 b/public/ioa.ps1 index 4b2d867a..6e5cfa7b 100644 --- a/public/ioa.ps1 +++ b/public/ioa.ps1 @@ -1,7 +1,7 @@ -function Get-FalconHorizonIoaEvent { +function Get-FalconCloudIoaEvent { <# .SYNOPSIS -Retrieve Falcon Horizon Indicator of Attack events +Retrieve Falcon Cloud Security Indicator of Attack events .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER CloudPlatform @@ -27,9 +27,10 @@ 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-FalconHorizonIoaEvent +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudIoaEvent #> [CmdletBinding(DefaultParameterSetName='/ioa/entities/events/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonIoaEvent')] param( [Parameter(ParameterSetName='/ioa/entities/events/v1:get',Mandatory,ValueFromPipelineByPropertyName, Position=1)] @@ -45,11 +46,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoaEvent [Alias('aws_account_id','account_id','AccountId')] [string]$AwsAccountId, [Parameter(ParameterSetName='/ioa/entities/events/v1:get',ValueFromPipelineByPropertyName,Position=4)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_subscription_id')] [string]$AzureSubscriptionId, [Parameter(ParameterSetName='/ioa/entities/events/v1:get',ValueFromPipelineByPropertyName,Position=5)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_tenant_id')] [string]$AzureTenantId, [Parameter(ParameterSetName='/ioa/entities/events/v1:get',Position=6)] @@ -92,10 +93,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoaEvent } } } -function Get-FalconHorizonIoaUser { +function Get-FalconCloudIoaUser { <# .SYNOPSIS -Retrieve Falcon Horizon Indicator of Attack users +Retrieve Falcon Cloud Security Indicator of Attack users .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER PolicyId @@ -111,9 +112,10 @@ Azure tenant identifier .PARAMETER State Event state .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoaUser +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudIoaUser #> [CmdletBinding(DefaultParameterSetName='/ioa/entities/users/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonIoaUser')] param( [Parameter(ParameterSetName='/ioa/entities/users/v1:get',Mandatory,ValueFromPipelineByPropertyName, Position=1)] @@ -129,11 +131,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonIoaUser [Alias('aws_account_id','account_id','AccountId')] [string]$AwsAccountId, [Parameter(ParameterSetName='/ioa/entities/users/v1:get',ValueFromPipelineByPropertyName,Position=4)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_subscription_id')] [string]$AzureSubscriptionId, [Parameter(ParameterSetName='/ioa/entities/users/v1:get',ValueFromPipelineByPropertyName,Position=5)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('azure_tenant_id')] [string]$AzureTenantId, [Parameter(ParameterSetName='/ioa/entities/users/v1:get',Position=6)] diff --git a/public/ioarules.ps1 b/public/ioarules.ps1 index 59d929ba..b2af3c63 100644 --- a/public/ioarules.ps1 +++ b/public/ioarules.ps1 @@ -44,7 +44,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoaGroup process { $Format = Get-EndpointFormat $PSCmdlet.ParameterSetName if ($Format) { - ($Format.Body.root | Where-Object { $_ -ne 'id' }).foreach{ + @($Format.Body.root).Where({$_ -ne 'id'}).foreach{ # When not provided, add required fields using existing policy settings if (!$PSBoundParameters.$_) { if (!$Existing) { $Existing = Get-FalconIoaGroup -Id $PSBoundParameters.Id -EA 0 } @@ -63,8 +63,8 @@ function Edit-FalconIoaRule { .SYNOPSIS Modify custom Indicator of Attack rules within a rule group .DESCRIPTION -All fields are required (plus 'rulegroup_version') when making a rule group change. PSFalcon adds missing values -automatically using data from your existing rule group. +All fields are required when making a rule group change. PSFalcon adds missing values automatically using data +from your existing rule group. If an existing rule is submitted within 'rule_updates', it will be filtered to the required properties ('comment', 'description', 'disposition_id', 'enabled', 'field_values', 'instance_id', 'name', and 'pattern_severity') @@ -74,51 +74,57 @@ Requires 'Custom IOA rules: Write'. .PARAMETER Comment Audit log comment .PARAMETER RuleUpdate -An array of rule properties +One or more custom Indicator of Attack rules .PARAMETER RulegroupId Rule group identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoaRule #> - [CmdletBinding(DefaultParameterSetName='/ioarules/entities/rules/v1:patch',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/ioarules/entities/rules/v2:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:patch',Position=1)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v2:patch',Mandatory,ValueFromPipelineByPropertyName, + Position=1)] [string]$Comment, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:patch',ValueFromPipelineByPropertyName, - Position=2)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v2:patch',Mandatory,ValueFromPipelineByPropertyName, + Position=2)] [Alias('rule_updates','rules','RuleUpdates')] [object[]]$RuleUpdate, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:patch',Mandatory,ValueFromPipelineByPropertyName, + [Parameter(ParameterSetName='/ioarules/entities/rules/v2:patch',Mandatory,ValueFromPipelineByPropertyName, Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('rulegroup_id','id')] [string]$RulegroupId ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ Body = @{ root = @('rulegroup_id','comment','rule_updates','rulegroup_version') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + [System.Collections.Generic.List[object]]$List = @() } process { if ($RuleUpdate) { - # Filter 'rule_updates' to required fields - [object[]]$RuleRequired = 'instance_id','pattern_severity','enabled','disposition_id','name', - 'description','comment',@{ label = 'field_values'; expression = { $_.field_values | - Select-Object name,label,type,values }} - [object[]]$RuleUpdate = $RuleUpdate | Select-Object $RuleRequired - } - @($Param.Format.Body.root | Where-Object { $_ -ne 'rule_updates' }).foreach{ - # When not provided, add required fields using existing policy settings - if (!$PSBoundParameters.$_) { - if (!$Existing) { $Existing = Get-FalconIoaGroup -Id $PSBoundParameters.RulegroupId -EA 0 } - if ($Existing) { - $Value = if ($_ -eq 'rulegroup_version') { $Existing.version } else { $Existing.$_ } - $PSBoundParameters[$_] = $Value + foreach ($i in $RuleUpdate) { + if ($i.field_values) { + # Ensure that 'field_values' are submitted as an array with 'name', 'label', 'type' and 'values' + [PSCustomObject[]]$i.field_values = $i.field_values | Select-Object name,label,type,values } + # Select required properties defined by 'rule_updates' for endpoint + $i = [PSCustomObject]$i | Select-Object @($Param.Format.Body.rule_updates).Where({ + $_ -ne 'rulegroup_version'}) + $List.Add($i) } } + } + end { + # Add 'rulegroup_version' from existing IoaGroup + $PSBoundParameters['rulegroup_version'] = (Get-FalconIoaGroup -Id $RulegroupId -EA 0).version + if ($List) { + # Add 'rule_updates' as an array + [void]$PSBoundParameters.Remove('RuleUpdate') + $PSBoundParameters['rule_updates'] = @($List) + } + # Modify 'Format' to ensure 'rule_updates' is properly appended and make request + [void]$Param.Format.Body.Remove('rule_updates') + $Param.Format.Body.root += 'rule_updates' Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -151,10 +157,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaGroup #> [CmdletBinding(DefaultParameterSetName='/ioarules/queries/rule-groups/v1:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:get',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/ioarules/queries/rule-groups/v1:get',Position=1)] [Parameter(ParameterSetName='/ioarules/queries/rule-groups-full/v1:get',Position=1)] @@ -191,7 +197,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaGroup } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } @(Invoke-Falcon @Param -UserInput $PSBoundParameters).foreach{ if ($_.version -and $null -eq $_.version) { $_.version = 0 } $_ @@ -221,10 +227,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaPlatform #> [CmdletBinding(DefaultParameterSetName='/ioarules/queries/platforms/v1:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/platforms/v1:get',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Parameter(ParameterSetName='/ioarules/entities/platforms/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] [ValidateSet('windows','mac','linux',IgnoreCase=$false)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/ioarules/queries/platforms/v1:get',Position=1)] [ValidateRange(1,500)] @@ -242,10 +248,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaPlatform $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIoaRule { @@ -277,10 +287,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaRule #> [CmdletBinding(DefaultParameterSetName='/ioarules/queries/rules/v1:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/rules/GET/v1:post',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Parameter(ParameterSetName='/ioarules/entities/rules/GET/v1:post',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] [ValidatePattern('^\d+$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/ioarules/queries/rules/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -289,15 +299,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaRule [Alias('q')] [string]$Query, [Parameter(ParameterSetName='/ioarules/queries/rules/v1:get',Position=3)] - [ValidateSet('rules.created_by.asc','rules.created_by.desc','rules.created_on.asc', - 'rules.created_on.desc','rules.current_version.action_label.asc', - 'rules.current_version.action_label.desc','rules.current_version.description.asc', - 'rules.current_version.description.desc','rules.current_version.modified_by.asc', - 'rules.current_version.modified_by.desc','rules.current_version.modified_on.asc', - 'rules.current_version.modified_on.desc','rules.current_version.name.asc', - 'rules.current_version.name.desc','rules.current_version.pattern_severity.asc', - 'rules.current_version.pattern_severity.desc','rules.enabled.asc','rules.enabled.desc', - 'rules.ruletype_name.asc','rules.ruletype_name.desc',IgnoreCase=$false)] + [ValidateSet('rules.created_by.asc','rules.created_by.desc','rules.created_on.asc','rules.created_on.desc', + 'rules.current_version.action_label.asc','rules.current_version.action_label.desc', + 'rules.current_version.description.asc','rules.current_version.description.desc', + 'rules.current_version.modified_by.asc','rules.current_version.modified_by.desc', + 'rules.current_version.modified_on.asc','rules.current_version.modified_on.desc', + 'rules.current_version.name.asc','rules.current_version.name.desc', + 'rules.current_version.pattern_severity.asc','rules.current_version.pattern_severity.desc', + 'rules.enabled.asc','rules.enabled.desc','rules.ruletype_name.asc','rules.ruletype_name.desc', + IgnoreCase=$false)] [string]$Sort, [Parameter(ParameterSetName='/ioarules/queries/rules/v1:get',Position=4)] [ValidateRange(1,500)] @@ -315,10 +325,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaRule $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIoaSeverity { @@ -347,7 +361,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaSeverity [Parameter(ParameterSetName='/ioarules/entities/pattern-severities/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidateSet('critical','high','medium','low','informational',IgnoreCase=$false)] - [Alias('Ids','pattern_severity')] + [Alias('ids','pattern_severity')] [string[]]$Id, [Parameter(ParameterSetName='/ioarules/queries/pattern-severities/v1:get',Position=1)] [ValidateRange(1,500)] @@ -365,10 +379,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaSeverity $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIoaType { @@ -394,10 +412,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaType #> [CmdletBinding(DefaultParameterSetName='/ioarules/queries/rule-types/v1:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/rule-types/v1:get',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline)] + [Parameter(ParameterSetName='/ioarules/entities/rule-types/v1:get',Mandatory,ValueFromPipelineByPropertyName, + ValueFromPipeline)] [ValidatePattern('^\d{1,2}$')] - [Alias('Ids','ruletype_id')] + [Alias('ids','ruletype_id')] [string[]]$Id, [Parameter(ParameterSetName='/ioarules/queries/rule-types/v1:get',Position=1)] [ValidateRange(1,500)] @@ -415,10 +433,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaType $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconIoaGroup { @@ -440,11 +462,11 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoaGroup #> [CmdletBinding(DefaultParameterSetName='/ioarules/entities/rule-groups/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=1)] + [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=1)] [string]$Name, - [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=2)] + [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=2)] [ValidateSet('windows','mac','linux',IgnoreCase=$false)] [Alias('platform_name')] [string]$Platform, @@ -463,9 +485,6 @@ function New-FalconIoaRule { .SYNOPSIS Create a custom Indicator of Attack rule within a rule group .DESCRIPTION -'RuleTypeId' and 'DispositionId' values can be found using 'Get-FalconIoaType -Detailed' under the 'id' and -'disposition_map' properties. - Requires 'Custom IOA rules: Write'. .PARAMETER Name Rule name @@ -476,7 +495,7 @@ Rule type .PARAMETER DispositionId Disposition identifier [10: Monitor, 20: Detect, 30: Block] .PARAMETER FieldValue -An array of rule properties +An array of custom Indicator of Attack properties .PARAMETER Description Rule description .PARAMETER Comment @@ -491,23 +510,21 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoaRule [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory,ValueFromPipelineByPropertyName, Position=1)] [string]$Name, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=2)] - [ValidateSet('critical','high','medium','low','informational',IgnoreCase=$false)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=2)] [Alias('pattern_severity')] [string]$PatternSeverity, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=3)] - [ValidateSet(1,2,5,6,9,10,11,12)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=3)] [Alias('ruletype_id')] [string]$RuletypeId, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=4)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=4)] [ValidateSet(10,20,30)] [Alias('disposition_id')] [int32]$DispositionId, - [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory, - ValueFromPipelineByPropertyName,Position=5)] + [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',Mandatory,ValueFromPipelineByPropertyName, + Position=5)] [Alias('field_values','FieldValues')] [object[]]$FieldValue, [Parameter(ParameterSetName='/ioarules/entities/rules/v1:post',ValueFromPipelineByPropertyName,Position=6)] @@ -521,22 +538,18 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoaRule [string]$RulegroupId ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = $PSCmdlet.ParameterSetName - Format = @{ - Body = @{ - root = @('rulegroup_id','disposition_id','comment','description','pattern_severity', - 'ruletype_id','field_values','name') - } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint } process { if ($PSBoundParameters.FieldValue) { # Filter 'field_values' to required fields - $PSBoundParameters.FieldValue = $PSBoundParameters.FieldValue | Select-Object name,label,type,values + [PSCustomObject[]]$PSBoundParameters.FieldValue = $PSBoundParameters.FieldValue | Select-Object name,label, + type,values } + # Modify 'Format' to ensure 'field_values' is properly appended and make request + [void]$Param.Format.Body.Remove('field_values') + $Param.Format.Body.root += 'field_values' Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -560,7 +573,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaGroup [Parameter(ParameterSetName='/ioarules/entities/rule-groups/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -570,7 +583,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -602,7 +615,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaRule [Parameter(ParameterSetName='/ioarules/entities/rules/v1:delete',Mandatory,ValueFromPipelineByPropertyName, Position=3)] [ValidatePattern('^\d+$')] - [Alias('Ids','rule_ids','instance_id')] + [Alias('ids','rule_ids','instance_id')] [string[]]$Id ) begin { @@ -612,7 +625,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaRule process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -643,4 +656,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Test-FalconIoaRule } } process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +Register-ArgumentCompleter -CommandName New-FalconIoaRule -ParameterName RuleTypeId -ScriptBlock { + Get-FalconIoaType +} +Register-ArgumentCompleter -CommandName New-FalconIoaRule -ParameterName PatternSeverity -ScriptBlock { + Get-FalconIoaSeverity } \ No newline at end of file diff --git a/public/iocs.ps1 b/public/iocs.ps1 index e135eb2a..a4e4e7c1 100644 --- a/public/iocs.ps1 +++ b/public/iocs.ps1 @@ -4,8 +4,8 @@ function Edit-FalconIoc { Modify custom indicators .DESCRIPTION Requires 'IOC Manager APIs: Write'. -.PARAMETER Array -An array of indicators to modify in a single request +.PARAMETER InputObject +One or more indicators to modify in a single request .PARAMETER Action Action to perform when a host observes the indicator .PARAMETER Platform @@ -28,10 +28,10 @@ Host group identifier Assign to all host groups .PARAMETER Expiration Expiration date. When an indicator expires, its action is set to 'no_action' but it remains in your indicator list. -.PARAMETER Comment -Audit log comment .PARAMETER FromParent Inheritance from parent CID +.PARAMETER Comment +Audit log comment .PARAMETER Retrodetect Generate retroactive detections for hosts that have observed the indicator .PARAMETER IgnoreWarning @@ -43,23 +43,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoc #> [CmdletBinding(DefaultParameterSetName='/iocs/entities/indicators/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='Array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconIoc' - Endpoint = '/iocs/entities/indicators/v1:patch' - Required = @('id') - Content = @('action','platforms','severity') - Pattern = @('expiration','host_groups','id') - Format = @{ host_groups = 'HostGroup' } - } - Confirm-Parameter @Param - } - })] - [Alias('indicators')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'Edit-FalconIoc' '/iocs/entities/indicators/v1:patch' })] + [Alias('indicators','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=1)] [string]$Action, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=2)] @@ -92,15 +79,18 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoc [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=11)] [ValidatePattern('^(\d{4}-\d{2}-\d{2}|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)$')] [string]$Expiration, - [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=12)] - [string]$Comment, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=13)] [Alias('from_parent')] [boolean]$FromParent, + [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=12)] + [Parameter(ParameterSetName='Pipeline',Position=2)] + [string]$Comment, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=14)] + [Parameter(ParameterSetName='Pipeline',Position=3)] [Alias('retrodetects')] [boolean]$Retrodetect, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Position=15)] + [Parameter(ParameterSetName='Pipeline',Position=4)] [Alias('ignore_warnings','IgnoreWarnings')] [boolean]$IgnoreWarning, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:patch',Mandatory,Position=16)] @@ -111,21 +101,19 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoc $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = '/iocs/entities/indicators/v1:patch' - Format = @{ - Query = @('retrodetects','ignore_warnings') - Body = @{ - root = @('comment','indicators') - indicators = @('action','applied_globally','description','expiration','from_parent', - 'host_groups','id','metadata','mobile_action','platforms','severity','source','tags') - } - } Max = 2000 } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - @($Array).foreach{ $List.Add($_) } + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'indicators' properties and remove empty values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.indicators + Remove-EmptyValue $i comment,expiration,tag + $List.Add($i) + } } else { if ($PSBoundParameters.Filename) { $PSBoundParameters['metadata'] = @{ filename = $PSBoundParameters.Filename } @@ -136,7 +124,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconIoc } end { if ($List) { - $PSBoundParameters['Array'] = @($List) + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format.Body = @{ root = @('comment','indicators') } + $PSBoundParameters['indicators'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -175,7 +165,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoc [Parameter(ParameterSetName='/iocs/entities/indicators/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/iocs/queries/indicators/v1:get',Position=1)] [Parameter(ParameterSetName='/iocs/combined/indicator/v1:get',Position=1)] @@ -219,10 +209,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoc $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconIocAction { @@ -349,8 +343,8 @@ function New-FalconIoc { Create custom indicators .DESCRIPTION Requires 'IOC Manager APIs: Write'. -.PARAMETER Array -An array of indicators to create in a single request +.PARAMETER InputObject +One or more indicators to create in a single request .PARAMETER Type Indicator type .PARAMETER Value @@ -388,23 +382,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoc #> [CmdletBinding(DefaultParameterSetName='/iocs/entities/indicators/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='Array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconIoc' - Endpoint = '/iocs/entities/indicators/v1:post' - Required = @('type','value','action','platforms') - Content = @('action','platforms','severity','type') - Pattern = @('expiration','host_groups') - Format = @{ host_groups = 'HostGroup' } - } - Confirm-Parameter @Param - } - })] - [Alias('indicators')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconIoc' '/iocs/entities/indicators/v1:post' })] + [Alias('indicators','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Mandatory,Position=1)] [string]$Action, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Mandatory,Position=2)] @@ -438,41 +419,38 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoc [ValidatePattern('^(\d{4}-\d{2}-\d{2}|\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)$')] [string]$Expiration, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Position=12)] - [Parameter(ParameterSetName='array',Position=2)] + [Parameter(ParameterSetName='Pipeline',Position=2)] [string]$Comment, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Position=13)] - [Parameter(ParameterSetName='array',Position=3)] + [Parameter(ParameterSetName='Pipeline',Position=3)] [Alias('Retrodetects')] [boolean]$Retrodetect, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Position=14)] - [Parameter(ParameterSetName='array',Position=4)] + [Parameter(ParameterSetName='Pipeline',Position=4)] [Alias('ignore_warnings','IgnoreWarnings')] [boolean]$IgnoreWarning, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Mandatory,Position=15)] [string]$Type, [Parameter(ParameterSetName='/iocs/entities/indicators/v1:post',Mandatory,Position=16)] - [Alias('indicator')] [string]$Value ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name Endpoint = '/iocs/entities/indicators/v1:post' - Format = @{ - Query = @('retrodetects','ignore_warnings') - Body = @{ - root = @('comment','indicators') - indicators = @('tags','applied_globally','expiration','description','value','metadata','type', - 'source','host_groups','severity','action','platforms','mobile_action') - } - } Max = 2000 } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - @($Array).foreach{ $List.Add($_) } + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'indicators' properties and remove empty values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.indicators + Remove-EmptyValue $i comment,expiration,tag + $List.Add($i) + } } elseif (!$PSBoundParameters.HostGroup -and !$PSBoundParameters.AppliedGlobally) { throw "'HostGroup' or 'AppliedGlobally' must be provided." } else { @@ -485,7 +463,9 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoc } end { if ($List) { - $PSBoundParameters['Array'] = @($List) + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format.Body = @{ root = @('comment','indicators') } + $PSBoundParameters['indicators'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -522,7 +502,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoc [Parameter(ParameterSetName='/iocs/entities/indicators/v1:delete',ValueFromPipelineByPropertyName, ValueFromPipeline,Position=2)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -544,7 +524,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoc if (!$Id -and !$Filter) { throw "'Filter' or 'Id' must be provided." } elseif ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/kubernetes-protection.ps1 b/public/kubernetes-protection.ps1 index e76a15db..243fc897 100644 --- a/public/kubernetes-protection.ps1 +++ b/public/kubernetes-protection.ps1 @@ -19,7 +19,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerAwsAccount [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^\d{12}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -29,7 +29,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerAwsAccount process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -52,12 +52,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconContainerAzureAccount param( [Parameter(ParameterSetName='/kubernetes-protection/entities/service-principal/azure/v1:patch',Mandatory, 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('client_id')] [string]$ClientId, [Parameter(ParameterSetName='/kubernetes-protection/entities/service-principal/azure/v1:patch',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -119,10 +119,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAccount $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerAwsAccount { @@ -135,8 +139,8 @@ Requires 'Kubernetes Protection: Read'. AWS account identifier .PARAMETER Status Filter by account status -.PARAMETER IsHorizonAcct -Restrict results to Falcon Horizon +.PARAMETER IsFcsAcct +Restrict results to Falcon Cloud Security .PARAMETER Limit Maximum number of results per request .PARAMETER Offset @@ -154,15 +158,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAwsAccount [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:get', ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^\d{12}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:get',Position=2)] [ValidateSet('provisioned','operational',IgnoreCase=$false)] [string]$Status, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:get',Position=3)] [ValidateSet('false','true',IgnoreCase=$false)] - [Alias('is_horizon_acct')] - [string]$IsHorizonAcct, + [Alias('is_horizon_acct','IsHorizonAcct')] + [string]$IsFcsAcct, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:get',Position=4)] [int32]$Limit, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:get')] @@ -176,10 +180,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAwsAccount $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerAzureAccount { @@ -194,8 +202,8 @@ Azure tenant identifier Azure subscription identifier .PARAMETER Status Filter by account status -.PARAMETER IsHorizonAcct -Filter by whether an account originates from Horizon or not +.PARAMETER IsFcsAcct +Restrict results to Falcon Cloud Security .PARAMETER Limit Maximum number of results per request .PARAMETER Offset @@ -212,19 +220,19 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureAccount param( [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_id')] [string[]]$SubscriptionId, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get',Position=3)] [ValidateSet('operational','provisioned',IgnoreCase=$false)] [string]$Status, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get',Position=4)] - [Alias('is_horizon_acct')] - [boolean]$IsHorizonAcct, + [Alias('is_horizon_acct','IsHorizonAcct')] + [boolean]$IsFcsAcct, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get',Position=5)] [int]$Limit, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:get')] @@ -238,10 +246,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureAccount $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerAzureConfig { @@ -283,10 +295,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureConfig $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerAzureScript { @@ -307,10 +323,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureScript param( [Parameter(ParameterSetName='/kubernetes-protection/entities/user-script/azure/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id, [Parameter(ParameterSetName='/kubernetes-protection/entities/user-script/azure/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_id')] [string[]]$SubscriptionId ) @@ -343,7 +359,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureTenant param( [Parameter(ParameterSetName='/kubernetes-protection/entities/tenants/azure/v1:get', 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/kubernetes-protection/entities/tenants/azure/v1:get',Position=2)] @@ -362,10 +378,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerAzureTenant $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconContainerCloud { @@ -392,82 +412,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconContainerCloud $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { - if ($Cloud) { @($Cloud).foreach{ $List.Add($_) }} - } + process { if ($Cloud) { @($Cloud).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Cloud'] = @($List | Select-Object -Unique) + $PSBoundParameters['Cloud'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } } -function Get-FalconContainerCluster { -<# -.SYNOPSIS -Search for Falcon Container Security clusters -.DESCRIPTION -Requires 'Kubernetes Protection: Read'. -.PARAMETER Id -Cluster account identifier -.PARAMETER Location -Cloud provider location -.PARAMETER ClusterName -Cluster name -.PARAMETER ClusterService -Cluster service -.PARAMETER Status -Cluster Status -.PARAMETER Limit -Maximum number of results per request -.PARAMETER Offset -Position to begin retrieving results -.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-FalconContainerCluster -#> - [CmdletBinding(DefaultParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get', - SupportsShouldProcess)] - param( - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get', - ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] - [Alias('account_ids','Ids')] - [string[]]$Id, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get',Position=2)] - [Alias('locations')] - [string[]]$Location, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get',Position=3)] - [Alias('cluster_names','ClusterNames')] - [string[]]$ClusterName, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get',Position=4)] - [ValidateSet('eks',IgnoreCase=$false)] - [Alias('cluster_service')] - [string]$ClusterService, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get',Position=5)] - [ValidateSet('Not Installed','Running','Stopped',IgnoreCase=$false)] - [string[]]$Status, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get',Position=6)] - [int32]$Limit, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get')] - [int32]$Offset, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/v1:get')] - [switch]$All, - [Parameter(ParameterSetName='/kubernetes-protection/entities/kubernetes/clusters/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) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters - } -} function Get-FalconContainerScript { <# .SYNOPSIS @@ -548,11 +500,11 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerAzureAccount SupportsShouldProcess)] param( [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('subscription_id')] [string]$SubscriptionId, [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('tenant_id')] [string]$TenantId ) @@ -571,7 +523,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconContainerKey [CmdletBinding(DefaultParameterSetName='/kubernetes-protection/entities/integration/api-key/v1:post', SupportsShouldProcess)] param() - process { Invoke-Falcon -Endpoint $PSCmdlet.ParameterSetName } + process { Invoke-Falcon -Command $MyInvocation.MyCommand.Name -Endpoint $PSCmdlet.ParameterSetName } } function Receive-FalconContainerYaml { <# @@ -645,7 +597,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerAwsAccount [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/aws/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^\d{12}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -655,7 +607,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerAwsAccount process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -676,7 +628,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerAzureAccount param( [Parameter(ParameterSetName='/kubernetes-protection/entities/accounts/azure/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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string[]]$Id ) @@ -687,7 +639,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconContainerAzureAccount process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/loggingapi.ps1 b/public/loggingapi.ps1 new file mode 100644 index 00000000..c6de0bd4 --- /dev/null +++ b/public/loggingapi.ps1 @@ -0,0 +1,88 @@ +function Get-FalconFoundryRepository { +<# +.SYNOPSIS +List available Falcon Foundry repositories +.DESCRIPTION +Requires 'App Logs: Read'. +.PARAMETER CheckTestData +Include whether test data is present in the application repository +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFoundryRepository +#> + [CmdletBinding(DefaultParameterSetName='/loggingapi/combined/repos/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/loggingapi/combined/repos/v1:get',Position=1)] + [Alias('check_test_data')] + [boolean]$CheckTestData + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconFoundrySearch { +<# +.SYNOPSIS +Get the results of a saved search +.DESCRIPTION +Requires 'App Logs: Read'. +.PARAMETER Id +Search identifier +.PARAMETER AppId +Foundry application identifier +.PARAMETER InferJsonTypes +Whether to try to infer data types in json event response instead of returning map[string]string +.PARAMETER Limit +Maximum number of results per request +.PARAMETER MatchResponseSchema +Whether to validate search results against their schema +.PARAMETER Metadata +Whether to include metadata in the response +.PARAMETER Offset +Position to begin retrieving results +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFoundrySearch +#> + [CmdletBinding(DefaultParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get', + SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Mandatory,Position=0)] + [Alias('job_id')] + [string]$Id, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Position=0)] + [Alias('app_id')] + [string]$AppId, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Position=0)] + [Alias('infer_json_types')] + [boolean]$InferJsonTypes, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Position=0)] + [string]$Limit, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Position=0)] + [Alias('match_response_schema')] + [boolean]$MatchResponseSchema, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get',Position=0)] + [boolean]$Metadata, + [Parameter(ParameterSetName='/loggingapi/entities/saved-searches/execute/v1:get')] + [string]$Offset + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconFoundryView { +<# +.SYNOPSIS +List available Falcon Foundry views +.DESCRIPTION +Requires 'App Logs: Read'. +.PARAMETER CheckTestData +Include whether test data is present in the application repository +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFoundryView +#> + [CmdletBinding(DefaultParameterSetName='/loggingapi/entities/views/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/loggingapi/entities/views/v1:get',Position=1)] + [Alias('check_test_data')] + [boolean]$CheckTestData + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} \ No newline at end of file diff --git a/public/malquery.ps1 b/public/malquery.ps1 index bd358336..3ed84081 100644 --- a/public/malquery.ps1 +++ b/public/malquery.ps1 @@ -13,8 +13,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQuery param( [Parameter(ParameterSetName='/malquery/entities/requests/v1:get',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('Ids')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -58,7 +58,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQuerySample [Parameter(ParameterSetName='/malquery/entities/metadata/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -68,7 +68,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMalQuerySample process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -100,7 +100,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Group-FalconMalQuerySample process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -193,11 +193,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconMalQuery Format = @{ Body = @{ root = @('yara_rule','options'); patterns = @('type','value') }} } $Aliases = (Get-Command $MyInvocation.MyCommand.Name).Parameters.GetEnumerator().Where({ - $_.Value.Attributes.ParameterSetName -eq $PSCmdlet.ParameterSetName }) + $_.Value.Attributes.ParameterSetName -eq $PSCmdlet.ParameterSetName}) $Options = @{} foreach ($Opt in @('FilterFiletype','FilterMeta','Limit','MaxDate','MaxSize','MinDate','MinSize')) { if ($PSBoundParameters.$Opt) { - $Alias = $Aliases.Where({ $_.Key -eq $Opt }).Value.Aliases[0] + $Alias = $Aliases.Where({$_.Key -eq $Opt}).Value.Aliases[0] $Key = if ($Alias) { $Alias } else { $Opt.ToLower() } $Options[$Key] = $PSBoundParameters.$Opt [void]$PSBoundParameters.Remove($Opt) @@ -236,7 +236,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconMalQuerySample [Parameter(ParameterSetName='/malquery/entities/download-files/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^([A-Fa-f0-9]{64}|\w{8}-\w{4}-\w{4}-\w{4}-\w{12})$')] - [Alias('Ids')] + [Alias('ids')] [string]$Id, [Parameter(ParameterSetName='/malquery/entities/download-files/v1:get')] [switch]$Force diff --git a/public/message-center.ps1 b/public/message-center.ps1 index 1ecfd51a..18d1b2c5 100644 --- a/public/message-center.ps1 +++ b/public/message-center.ps1 @@ -27,7 +27,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconCompleteActivity [string]$Content, [Parameter(ParameterSetName='/message-center/entities/case-activity/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$UserId, [Parameter(ParameterSetName='/message-center/entities/case-activity/v1:post',Mandatory, @@ -130,7 +130,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCompleteActivity param( [Parameter(ParameterSetName='/message-center/entities/case-activities/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/message-center/queries/case-activities/v1:get',Mandatory,Position=1)] [Alias('case_id')] @@ -158,10 +158,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCompleteActivity $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconCompleteCase { @@ -193,7 +197,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCompleteCase param( [Parameter(ParameterSetName='/message-center/entities/cases/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/message-center/queries/cases/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -219,10 +223,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCompleteCase $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconCompleteCase { @@ -283,7 +291,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconCompleteCase [string[]]$IncidentId, [Parameter(ParameterSetName='/message-center/entities/case/v2:post',Mandatory, ValueFromPipelineByPropertyName,Position=6)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$UserId ) @@ -398,7 +406,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Send-FalconCompleteAttachment [string]$Path, [Parameter(ParameterSetName='/message-center/entities/case-attachment/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$UserId, [Parameter(ParameterSetName='/message-center/entities/case-attachment/v1:post',Mandatory, diff --git a/public/mssp.ps1 b/public/mssp.ps1 index e2890dc5..17ddf842 100644 --- a/public/mssp.ps1 +++ b/public/mssp.ps1 @@ -20,7 +20,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconCidGroupMember [string]$Id, [Parameter(ParameterSetName='/mssp/entities/cid-group-members/v1:post',Mandatory, ValueFromPipelineByPropertyName,Position=2)] - [ValidatePattern('^[a-fA-F0-9]{32}$')] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [Alias('cids','child_cid')] [string[]]$Cid ) @@ -28,10 +28,17 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconCidGroupMember $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Cid) { @($Cid).foreach{ $List.Add($_) }}} + process { + if ($Cid) { + @($Cid).foreach{ + $Value = Confirm-CidValue $_ + if ($Value) { $List.Add($Value) } + } + } + } end { if ($List) { - $PSBoundParameters['Cid'] = @($List | Select-Object -Unique) + $PSBoundParameters['Cid'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -75,7 +82,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconGroupRole process { if ($RoleId) { @($RoleId).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['RoleId'] = @($List | Select-Object -Unique) + $PSBoundParameters['RoleId'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -102,7 +109,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconUserGroupMember [string]$Id, [Parameter(ParameterSetName='/mssp/entities/user-group-members/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuids','UserIds')] [string[]]$UserId ) @@ -113,7 +120,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconUserGroupMember process { if ($UserId) { @($UserId).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['UserId'] = @($List | Select-Object -Unique) + $PSBoundParameters['UserId'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -236,10 +243,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCidGroup $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconCidGroupMember { @@ -250,8 +261,8 @@ Search for Falcon Flight Control CID group members Requires 'Flight Control: Read'. .PARAMETER Id CID group identifier -.PARAMETER CID -CID +.PARAMETER Cid +Customer identifier .PARAMETER Sort Property and direction to sort results .PARAMETER Limit @@ -276,7 +287,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCidGroupMember [string[]]$Id, [Parameter(ParameterSetName='/mssp/queries/cid-group-members/v1:get',Mandatory, ValueFromPipelineByPropertyName,Position=1)] - [ValidatePattern('^[a-fA-F0-9]{32}$')] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [Alias('child_cid')] [string]$Cid, [Parameter(ParameterSetName='/mssp/queries/cid-group-members/v1:get',Position=2)] @@ -298,10 +309,20 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCidGroupMember $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { + @($Id).foreach{ $List.Add($_) } + } else { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconGroupRole { @@ -337,7 +358,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconGroupRole param( [Parameter(ParameterSetName='/mssp/entities/mssp-roles/v1:get',Mandatory,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}:[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/mssp/queries/mssp-roles/v1:get',ValueFromPipelineByPropertyName,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] @@ -380,7 +401,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconGroupRole } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -415,7 +436,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMemberCid [Parameter(ParameterSetName='/mssp/entities/children/GET/v2:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','child_cid')] + [Alias('ids','child_cid')] [string[]]$Id, [Parameter(ParameterSetName='/mssp/queries/children/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -439,10 +460,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMemberCid $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconUserGroup { @@ -499,10 +524,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUserGroup $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconUserGroupMember { @@ -539,7 +568,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUserGroupMember [string[]]$Id, [Parameter(ParameterSetName='/mssp/queries/user-group-members/v1:get',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$UserId, [Parameter(ParameterSetName='/mssp/queries/user-group-members/v1:get',Position=2)] @@ -561,10 +590,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUserGroupMember $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconCidGroup { @@ -629,7 +662,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCidGroup [Parameter(ParameterSetName='/mssp/entities/cid-groups/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('cid_group_ids','cid_group_id','Ids')] + [Alias('cid_group_ids','cid_group_id','ids')] [string[]]$Id ) begin { @@ -639,7 +672,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCidGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -666,7 +699,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCidGroupMember [string]$Id, [Parameter(ParameterSetName='/mssp/entities/cid-group-members/v2:delete',Mandatory, ValueFromPipelineByPropertyName,Position=2)] - [ValidatePattern('^[a-fA-F0-9]{32}$')] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [Alias('cids','child_cid')] [string[]]$Cid ) @@ -674,10 +707,17 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCidGroupMember $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Cid) { @($Cid).foreach{ $List.Add($_) }}} + process { + if ($Cid) { + @($Cid).foreach{ + $Value = Confirm-CidValue $_ + if ($Value) { $List.Add($Value) } + } + } + } end { if ($List) { - $PSBoundParameters['Cid'] = @($List | Select-Object -Unique) + $PSBoundParameters['Cid'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -727,7 +767,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconGroupRole } end { if ($List) { - $PSBoundParameters['RoleId'] = @($List | Select-Object -Unique) + $PSBoundParameters['RoleId'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -748,7 +788,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconUserGroup [Parameter(ParameterSetName='/mssp/entities/user-groups/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('user_group_ids','user_group_id','Ids')] + [Alias('user_group_ids','user_group_id','ids')] [string[]]$Id ) begin { @@ -758,7 +798,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconUserGroup process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -784,7 +824,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconUserGroupMember [string]$Id, [Parameter(ParameterSetName='/mssp/entities/user-group-members/v1:delete',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuids','uuid','UserIds')] [string[]]$UserId ) @@ -795,7 +835,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconUserGroupMember process { if ($UserId) { @($UserId).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['UserId'] = @($List | Select-Object -Unique) + $PSBoundParameters['UserId'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/oauth2.ps1 b/public/oauth2.ps1 index 911a2329..9399ea3d 100644 --- a/public/oauth2.ps1 +++ b/public/oauth2.ps1 @@ -10,7 +10,7 @@ If an active OAuth2 access token is due to expire in less than 60 seconds, a new requested using your cached credentials. The 'Collector' parameter allows for the submission of a [System.Collections.Hashtable] object containing the -parameters included with a 'Register-FalconEventCollector' command ('Path', 'Token' and 'Enabled') in order to +parameters included with a 'Register-FalconEventCollector' command ('Path', 'Token' and 'Enable') in order to log an initial OAuth2 access token request. .PARAMETER ClientId OAuth2 client identifier @@ -21,11 +21,11 @@ CrowdStrike cloud [default: 'us-1'] .PARAMETER CustomUrl Custom API URL for module troubleshooting .PARAMETER Hostname -CrowdStrike API hostname +CrowdStrike API hostname [default: 'https://api.crowdstrike.com'] .PARAMETER MemberCid Member CID, used when authenticating within a multi-CID environment ('Falcon Flight Control') .PARAMETER Collector -A hashtable containing 'Path', 'Token' and 'Enabled' properties for 'Register-FalconEventCollector' +A hashtable containing 'Path', 'Token' and 'Enable' properties for 'Register-FalconEventCollector' .LINK https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken #> @@ -45,13 +45,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken [ValidatePattern('^\w{40}$')] [string]$ClientSecret, [Parameter(ParameterSetName='Cloud',ValueFromPipelineByPropertyName,Position=3)] - [ValidateSet('eu-1','us-gov-1','us-1','us-2',IgnoreCase=$false)] + [ValidateSet('eu-1','us-1','us-2','us-gov-1','us-gov-2',IgnoreCase=$false)] [string]$Cloud, [Parameter(ParameterSetName='Custom',ValueFromPipelineByPropertyName,Position=3)] [string]$CustomUrl, [Parameter(ParameterSetName='/oauth2/token:post',ValueFromPipelineByPropertyName,Position=3)] [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', - 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + 'https://api.laggar.gcw.crowdstrike.com','https://api.us-gov-2.crowdstrike.mil', + 'https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] [string]$Hostname, [Parameter(ParameterSetName='Cloud',ValueFromPipelineByPropertyName,Position=4)] [Parameter(ParameterSetName='Custom',ValueFromPipelineByPropertyName,Position=4)] @@ -73,9 +74,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken [System.Collections.Hashtable]$Collector ) begin { - if ($PSBoundParameters.MemberCid -match '^[a-fA-F0-9]{32}-\w{2}$') { - $PSBoundParameters.MemberCid = $PSBoundParameters.MemberCid.Split('-')[0] - } function Get-ApiCredential ($UserInput) { $Output = @{} @('ClientId','ClientSecret','Hostname','MemberCid').foreach{ @@ -101,6 +99,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken } } process { + if ($PSBoundParameters.MemberCid) { + # Validate MemberCid value + $PSBoundParameters.MemberCid = Confirm-CidValue $PSBoundParameters.MemberCid + } if ($PSBoundParameters.CustomUrl) { # Override Hostname with CustomUrl $PSBoundParameters['Hostname'] = $PSBoundParameters.CustomUrl @@ -109,9 +111,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken # Convert 'Cloud' to 'Hostname' $Value = switch ($PSBoundParameters.Cloud) { 'eu-1' { 'https://api.eu-1.crowdstrike.com' } - 'us-gov-1' { 'https://api.laggar.gcw.crowdstrike.com' } 'us-1' { 'https://api.crowdstrike.com' } 'us-2' { 'https://api.us-2.crowdstrike.com' } + 'us-gov-1' { 'https://api.laggar.gcw.crowdstrike.com' } + 'us-gov-2' { 'https://api.us-gov-2.crowdstrike.mil' } } $PSBoundParameters['Hostname'] = $Value [void]$PSBoundParameters.Remove('Cloud') @@ -136,7 +139,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken if ($String) { Write-Log 'Request-FalconToken' "Set TLS 1.2 via $String." } $Script:Falcon.Api.Handler.AutomaticDecompression = [System.Net.DecompressionMethods]::Gzip, [System.Net.DecompressionMethods]::Deflate - $Script:Falcon.Api.Client.DefaultRequestHeaders.UserAgent.ParseAdd("$((Show-FalconModule).UserAgent)") + $Script:Falcon.Api.Client.DefaultRequestHeaders.UserAgent.ParseAdd($Script:Falcon.Api.UserAgent) } else { $PSCmdlet.WriteError('Unable to initialize [ApiClient] object.') } @@ -168,13 +171,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Request-FalconToken if ($Script:Falcon.MemberCid) { $Param.Body += "&member_cid=$($Script:Falcon.MemberCid)" } $Request = $Script:Falcon.Api.Invoke($Param) if ($Request.Result) { - $Region = $Request.Result.Headers.GetEnumerator().Where({ $_.Key -eq 'X-Cs-Region' }).Value + $Region = $Request.Result.Headers.GetEnumerator().Where({$_.Key -eq 'X-Cs-Region'}).Value $Redirect = switch ($Region) { # Update ApiClient hostname if redirected + 'eu-1' { 'https://api.eu-1.crowdstrike.com' } 'us-1' { 'https://api.crowdstrike.com' } 'us-2' { 'https://api.us-2.crowdstrike.com' } 'us-gov-1' { 'https://api.laggar.gcw.crowdstrike.com' } - 'eu-1' { 'https://api.eu-1.crowdstrike.com' } + 'us-gov-2' { 'https://api.us-gov-2.crowdstrike.mil' } } if ($Redirect -and $Script:Falcon.Hostname -ne $Redirect) { Write-Log 'Request-FalconToken' "Redirected to '$Region'." diff --git a/public/ods.ps1 b/public/ods.ps1 index 273da297..267c2ad2 100644 --- a/public/ods.ps1 +++ b/public/ods.ps1 @@ -50,6 +50,8 @@ Property and direction to sort results Maximum number of results per request .PARAMETER Offset Position to begin retrieving results +.PARAMETER Include +Include additional properties .PARAMETER Detailed Retrieve detailed information .PARAMETER All @@ -80,7 +82,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScan 'last_updated|desc',IgnoreCase=$false)] [string]$Sort, [Parameter(ParameterSetName='/ods/queries/scans/v1:get',Position=3)] + [ValidateRange(1,500)] [int32]$Limit, + [Parameter(ParameterSetName='/ods/queries/scans/v1:get',Position=4)] + [ValidateSet('scan_file',IgnoreCase=$false)] + [string[]]$Include, [Parameter(ParameterSetName='/ods/queries/scans/v1:get')] [int32]$Offset, [Parameter(ParameterSetName='/ods/queries/scans/v1:get')] @@ -96,8 +102,26 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScan } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } elseif ($Include -and $Include -contains 'scan_file') { + $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters + @($Request).foreach{ + if ($_.id) { + if ($_.filecount.malicious -or $_.filecount.quarantined) { + # Append 'scan_file' when 'malicious' or 'quarantined' values are present under 'filecount' + Set-Property $_ scan_file @(Get-FalconScanFile -ScanId $_.id -Detailed -All -EA 0) + } + $_ + } else { + # Check for 'scan_file' for all identifiers when not returning 'Detailed' result + [PSCustomObject]@{ id = $_; scan_file = @(Get-FalconScanFile -ScanId $_ -All -EA 0) } + } + } + } else { + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconScanFile { @@ -108,6 +132,8 @@ Search for files found by on-demand or scheduled scans Requires 'On-demand scans (ODS): Read'. .PARAMETER Id Malicious file identifier +.PARAMETER ScanId +On-demand scan identifier .PARAMETER Filter Falcon Query Language expression to limit results .PARAMETER Sort @@ -132,34 +158,59 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScanFile [ValidatePattern('^[a-fA-F0-9]{32}$')] [Alias('ids')] [string[]]$Id, + [Parameter(ParameterSetName='filter_by_scan_id',Mandatory)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$ScanId, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] [string]$Filter, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get',Position=2)] + [Parameter(ParameterSetName='filter_by_scan_id')] [ValidateSet('id|asc','id|desc','scan_id|asc','scan_id|desc','host_id|asc','host_id|desc', 'host_scan_id|asc','host_scan_id|desc','filename|asc','filename|desc','hash|asc','hash|desc', 'pattern_id|asc','pattern_id|desc','severity|asc','severity|desc','last_updated|asc', 'last_updated|desc',IgnoreCase=$false)] [string]$Sort, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get',Position=3)] + [Parameter(ParameterSetName='filter_by_scan_id')] + [ValidateRange(1,500)] [int32]$Limit, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get')] [int32]$Offset, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get')] + [Parameter(ParameterSetName='filter_by_scan_id')] [switch]$Detailed, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get')] + [Parameter(ParameterSetName='filter_by_scan_id')] [switch]$All, [Parameter(ParameterSetName='/ods/queries/malicious-files/v1:get')] + [Parameter(ParameterSetName='filter_by_scan_id')] [switch]$Total ) begin { - $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = if ($PSCmdlet.ParameterSetName -eq 'filter_by_scan_id') { + '/ods/queries/malicious-files/v1:get' + } else { + $PSCmdlet.ParameterSetName + } + } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { + @($Id).foreach{ $List.Add($_) } + } else { + if ($ScanId) { $PSBoundParameters['Filter'] = "scan_id:'$ScanId'" } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconScanHost { @@ -230,7 +281,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScanHost } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -291,10 +342,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScheduledScan $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconScheduledScan { @@ -419,7 +474,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconScheduledScan process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $UserInput = Set-ScanInteger $PSBoundParameters $UserInput['Schedule'] = @{ start_timestamp = $UserInput.StartTime; interval = $UserInput.Repeat } @('StartTime','Repeat').foreach{ [void]$UserInput.Remove($_) } @@ -462,7 +517,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconScheduledScan process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -581,7 +636,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Start-FalconScan } end { if ($List -or $PSBoundParameters.GroupId) { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } Invoke-Falcon @Param -UserInput (Set-ScanInteger $PSBoundParameters) } } @@ -613,7 +668,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Stop-FalconScan process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/plugins.ps1 b/public/plugins.ps1 new file mode 100644 index 00000000..c3310714 Binary files /dev/null and b/public/plugins.ps1 differ diff --git a/public/policy-device-control.ps1 b/public/policy-device-control.ps1 index 1b4d254e..a6a6b166 100644 --- a/public/policy-device-control.ps1 +++ b/public/policy-device-control.ps1 @@ -4,8 +4,8 @@ function Edit-FalconDeviceControlPolicy { Modify Falcon Device Control policies .DESCRIPTION Requires 'Device control policies: Write'. -.PARAMETER Array -An array of policies to modify in a single request +.PARAMETER InputObject +One or more policies to modify in a single request .PARAMETER Id Policy identifier .PARAMETER Name @@ -29,21 +29,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconDeviceControlPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/device-control/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconDeviceControlPolicy' - Endpoint = '/policy/entities/device-control/v1:patch' - Required = @('id') - Pattern = @('id') - } - Confirm-Parameter @Param - } + Confirm-Parameter $_ 'Edit-FalconDeviceControlPolicy' '/policy/entities/device-control/v1:patch' })] - [Alias('resources')] - [object[]]$Array, + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/device-control/v1:patch',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id, @@ -73,24 +64,20 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconDeviceControlPolicy } else { '/policy/entities/device-control/v1:patch' } - Format = if ($PSCmdlet.ParameterSetName -match 'default-device-control') { - @{ Body = @{ root = @('custom_notifications') }} - } else { - @{ Body = @{ resources = @('name','id','description','settings'); root = @('resources') }} - } } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources if ($i.settings.classes.exceptions) { # Remove exception 'id' values from 'settings' object - @($i.settings.classes.exceptions).Where({ $_.id }).foreach{ $_.PSObject.Properties.Remove('id') } + @($i.settings.classes.exceptions).Where({$_.id}).foreach{ [void]$_.PSObject.Properties.Remove('id') } } - # Select allowed fields, when populated - [string[]]$Select = @('id','name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + $List.Add($i) } } else { if ($PSCmdlet.ParameterSetName -match 'default-device-control') { @@ -118,8 +105,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconDeviceControlPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -159,7 +148,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconDeviceControlPolicy [Parameter(ParameterSetName='/policy/entities/device-control/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/combined/device-control/v1:get',Position=1)] [Parameter(ParameterSetName='/policy/queries/device-control/v1:get',Position=1)] @@ -200,7 +189,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconDeviceControlPolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters @{ members = 'Get-FalconDeviceControlPolicyMember' } @@ -307,7 +296,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconDeviceControlPolicyAct } } process { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('Id') if ($PSBoundParameters.GroupId) { $PSBoundParameters['action_parameters'] = @(@{ name = 'group_id'; value = $PSBoundParameters.GroupId }) @@ -322,8 +311,8 @@ function New-FalconDeviceControlPolicy { Create Falcon Device Control policies .DESCRIPTION Requires 'Device control policies: Write'. -.PARAMETER Array -An array of policies to create in a single request +.PARAMETER InputObject +One or more policies to create in a single request .PARAMETER Name Policy name .PARAMETER PlatformName @@ -337,22 +326,12 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconDeviceControlPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/device-control/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconDeviceControlPolicy' - Endpoint = '/policy/entities/device-control/v1:post' - Required = @('name','platform_name') - Content = @('platform_name') - Format = @{ platform_name = 'PlatformName' } - } - Confirm-Parameter @Param - } + Confirm-Parameter $_ 'New-FalconDeviceControlPolicy' '/policy/entities/device-control/v1:post' })] - [Alias('resources')] - [object[]]$Array, + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/device-control/v1:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/policy/entities/device-control/v1:post',Mandatory,Position=2)] @@ -366,27 +345,20 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconDeviceControlPolicy [object]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/device-control/v1:post' - Format = @{ - Body = @{ resources = @('name','description','platform_name','settings'); root = @('resources') } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/device-control/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources if ($i.settings.classes.exceptions) { - @($i.settings.classes.exceptions).Where({ $_.id }).foreach{ - # Remove exception 'id' values from 'settings' object - $_.PSObject.Properties.Remove('id') - } + # Remove exception 'id' values from 'settings' object + @($i.settings.classes.exceptions).Where({$_.id}).foreach{ [void]$_.PSObject.Properties.Remove('id') } } - # Select allowed fields, when populated - [string[]]$Select = @('name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -394,8 +366,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconDeviceControlPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -417,7 +391,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconDeviceControlPolicy [Parameter(ParameterSetName='/policy/entities/device-control/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -427,7 +401,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconDeviceControlPolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -457,7 +431,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconDeviceControlPrecedence [string]$PlatformName, [Parameter(ParameterSetName='/policy/entities/device-control-precedence/v1:post',Mandatory,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/policy-firewall-management.ps1 b/public/policy-firewall-management.ps1 index 7e2e821e..5306d153 100644 --- a/public/policy-firewall-management.ps1 +++ b/public/policy-firewall-management.ps1 @@ -4,8 +4,8 @@ function Edit-FalconFirewallPolicy { Modify Falcon Firewall Management policies .DESCRIPTION Requires 'Firewall management: Write'. -.PARAMETER Array -An array of policies to modify in a single request +.PARAMETER InputObject +One or more policies to modify in a single request .PARAMETER Id Policy identifier .PARAMETER Name @@ -17,21 +17,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/firewall/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconFirewallPolicy' - Endpoint = '/policy/entities/firewall/v1:patch' - Required = @('id') - Pattern = @('id') - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'Edit-FalconFirewallPolicy' '/policy/entities/firewall/v1:patch' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/firewall/v1:patch',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id, @@ -41,19 +30,16 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallPolicy [string]$Description ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/firewall/v1:patch' - Format = @{ Body = @{ resources = @('name','id','description'); root = @('resources') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/firewall/v1:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('id','name','description').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -61,8 +47,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconFirewallPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -100,7 +88,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallPolicy [Parameter(ParameterSetName='/policy/entities/firewall/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/combined/firewall/v1:get',Position=1)] [Parameter(ParameterSetName='/policy/queries/firewall/v1:get',Position=1)] @@ -139,7 +127,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconFirewallPolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { $Request = Add-Include $_ $PSBoundParameters @{ @@ -248,7 +236,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconFirewallPolicyAction } } process { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('Id') if ($PSBoundParameters.GroupId) { $PSBoundParameters['action_parameters'] = @(@{ name = 'group_id'; value = $PSBoundParameters.GroupId }) @@ -263,8 +251,8 @@ function New-FalconFirewallPolicy { Create Falcon Firewall Management policies .DESCRIPTION Requires 'Firewall management: Write'. -.PARAMETER Array -An array of policies to create in a single request +.PARAMETER InputObject +One or more policies to create in a single request .PARAMETER Name Policy name .PARAMETER PlatformName @@ -276,22 +264,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFirewallPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/firewall/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconFirewallPolicy' - Endpoint = '/policy/entities/firewall/v1:post' - Required = @('name','platform_name') - Content = @('platform_name') - Format = @{ platform_name = 'PlatformName' } - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconFirewallPolicy' '/policy/entities/firewall/v1:post' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/firewall/v1:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/policy/entities/firewall/v1:post',Mandatory,Position=2)] @@ -302,19 +278,16 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFirewallPolicy [string]$Description ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/firewall/v1:post' - Format = @{ Body = @{ resources = @('description','platform_name','name'); root = @('resources') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/firewall/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('name','description','platform_name').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -322,8 +295,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconFirewallPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -345,7 +320,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFirewallPolicy [Parameter(ParameterSetName='/policy/entities/firewall/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -355,7 +330,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconFirewallPolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -384,7 +359,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconFirewallPrecedence [string]$PlatformName, [Parameter(ParameterSetName='/policy/entities/firewall-precedence/v1:post',Mandatory,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/policy-ioa-exclusions.ps1 b/public/policy-ioa-exclusions.ps1 index 5633ea01..d5107c59 100644 --- a/public/policy-ioa-exclusions.ps1 +++ b/public/policy-ioa-exclusions.ps1 @@ -31,7 +31,7 @@ https://github.com/crowdstrike/psfalcon/wiki/ConvertTo-FalconIoaExclusion begin { [System.Collections.Generic.List[PSCustomObject]]$Output = @() } process { if ($Detection.behaviors -and $Detection.device) { - @($Detection.behaviors).Where({ $_.tactic -notmatch '^(Machine Learning|Malware)$' }).foreach{ + @($Detection.behaviors).Where({$_.tactic -notmatch '^(Machine Learning|Malware)$'}).foreach{ $Output.Add(([PSCustomObject]@{ pattern_id = $_.behavior_id pattern_name = $_.display_name @@ -158,7 +158,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaExclusion [Parameter(ParameterSetName='/policy/entities/ioa-exclusions/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/queries/ioa-exclusions/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -185,10 +185,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconIoaExclusion $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconIoaExclusion { @@ -258,7 +262,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconIoaExclusion if ($PSBoundParameters.GroupId.id) { [string[]]$PSBoundParameters.GroupId = $PSBoundParameters.GroupId.id } if ($PSBoundParameters.GroupId -eq 'all') { # Remove 'all' from 'GroupId', and remove 'GroupId' if 'all' was the only value - $PSBoundParameters.GroupId = @($PSBoundParameters.GroupId).Where({ $_ -ne 'all' }) + $PSBoundParameters.GroupId = @($PSBoundParameters.GroupId).Where({$_ -ne 'all'}) if ([string]::IsNullOrEmpty($PSBoundParameters.GroupId)) { [void]$PSBoundParameters.Remove('GroupId') } } if ($PSBoundParameters.GroupId) { @@ -289,7 +293,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaExclusion [Parameter(ParameterSetName='/policy/entities/ioa-exclusions/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -299,7 +303,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconIoaExclusion process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/policy-ml-exclusions.ps1 b/public/policy-ml-exclusions.ps1 index b99bd6cc..25f3bb39 100644 --- a/public/policy-ml-exclusions.ps1 +++ b/public/policy-ml-exclusions.ps1 @@ -7,7 +7,7 @@ Uses the 'behaviors' and 'device' properties of a detection to generate the nece Machine Learning exclusion. Specfically, it maps the following properties these fields: behaviors.filepath > value -device.groups > groups +device.groups > groups The 'value' field is stripped of any leading NT file path ('Device/HarddiskVolume'). @@ -27,7 +27,7 @@ https://github.com/crowdstrike/psfalcon/wiki/ConvertTo-FalconMlExclusion begin { [System.Collections.Generic.List[PSCustomObject]]$Output = @() } process { if ($Detection.behaviors -and $Detection.device) { - @($Detection.behaviors).Where({ $_.tactic -match '^(Machine Learning|Malware)$' }).foreach{ + @($Detection.behaviors).Where({$_.tactic -match '^(Machine Learning|Malware)$'}).foreach{ $Output.Add(([PSCustomObject]@{ value = $_.filepath -replace '\\Device\\HarddiskVolume\d+\\',$null excluded_from = @('blocking') @@ -53,6 +53,8 @@ Requires 'Machine Learning Exclusions: Write'. RegEx pattern value .PARAMETER GroupId Host group identifier or 'all' to apply to all hosts +.PARAMETER DescendantProcess +Apply to descendant processes .PARAMETER Comment Audit log comment .PARAMETER Id @@ -71,9 +73,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconMlExclusion [object[]]$GroupId, [Parameter(ParameterSetName='/policy/entities/ml-exclusions/v1:patch',ValueFromPipelineByPropertyName, Position=3)] + [Alias('is_descendant_process')] + [boolean]$DescendantProcess, + [Parameter(ParameterSetName='/policy/entities/ml-exclusions/v1:patch',ValueFromPipelineByPropertyName, + Position=4)] [string]$Comment, [Parameter(ParameterSetName='/policy/entities/ml-exclusions/v1:patch',Mandatory, - ValueFromPipelineByPropertyName,Position=4)] + ValueFromPipelineByPropertyName,Position=5)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id ) @@ -121,7 +127,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMlExclusion [Parameter(ParameterSetName='/policy/entities/ml-exclusions/v1:get',ValueFromPipelineByPropertyName, ValueFromPipeline,Mandatory)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/queries/ml-exclusions/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -147,10 +153,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconMlExclusion $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconMlExclusion { @@ -223,7 +233,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconMlExclusion [Parameter(ParameterSetName='/policy/entities/ml-exclusions/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -233,7 +243,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconMlExclusion process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/policy-prevention.ps1 b/public/policy-prevention.ps1 index 31a1a1ae..7ec570ad 100644 --- a/public/policy-prevention.ps1 +++ b/public/policy-prevention.ps1 @@ -4,8 +4,8 @@ function Edit-FalconPreventionPolicy { Modify Prevention policies .DESCRIPTION Requires 'Prevention Policies: Write'. -.PARAMETER Array -An array of policies to modify in a single request +.PARAMETER InputObject +One or more policies to modify in a single request .PARAMETER Id Policy identifier .PARAMETER Name @@ -19,21 +19,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconPreventionPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/prevention/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconPreventionPolicy' - Endpoint = '/policy/entities/prevention/v1:patch' - Required = @('id') - Pattern = @('id') - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'Edit-FalconPreventionPolicy' '/policy/entities/prevention/v1:patch' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/prevention/v1:patch',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id, @@ -46,24 +35,21 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconPreventionPolicy [object[]]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/prevention/v1:patch' - Format = @{ Body = @{ resources = @('name','id','description','settings'); root = @('resources') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/prevention/v1:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources if ($i.prevention_settings.settings) { # Migrate 'prevention_settings' to 'settings' containing required values Set-Property $i settings ($i.prevention_settings.settings | Select-Object id,value) - $i.PSObject.Properties.Remove('prevention_settings') + [void]$i.PSObject.Properties.Remove('prevention_settings') } - # Select allowed fields, when populated - [string[]]$Select = @('id','name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -71,8 +57,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconPreventionPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -110,7 +98,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconPreventionPolicy [Parameter(ParameterSetName='/policy/entities/prevention/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/combined/prevention/v1:get',Position=1)] [Parameter(ParameterSetName='/policy/queries/prevention/v1:get',Position=1)] @@ -149,7 +137,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconPreventionPolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters @{ members = 'Get-FalconPreventionPolicyMember' } @@ -257,7 +245,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconPreventionPolicyAction } process { if ($PSCmdlet.ShouldProcess($Id,$Message)) { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('Id') if ($PSBoundParameters.GroupId) { $PSBoundParameters['action_parameters'] = @( @@ -278,8 +266,8 @@ function New-FalconPreventionPolicy { Create Prevention policies .DESCRIPTION Requires 'Prevention Policies: Write'. -.PARAMETER Array -An array of policies to create in a single request +.PARAMETER InputObject +One or more policies to create in a single request .PARAMETER Name Policy name .PARAMETER PlatformName @@ -293,22 +281,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconPreventionPolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/prevention/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='Array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconPreventionPolicy' - Endpoint = '/policy/entities/prevention/v1:post' - Required = @('name','platform_name') - Content = @('platform_name') - Format = @{ platform_name = 'PlatformName' } - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconPreventionPolicy' '/policy/entities/prevention/v1:post' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/prevention/v1:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/policy/entities/prevention/v1:post',Mandatory,Position=2)] @@ -322,26 +298,21 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconPreventionPolicy [object[]]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/prevention/v1:post' - Format = @{ - Body = @{ resources = @('description','platform_name','name','settings'); root = @('resources') } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/prevention/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources if ($i.prevention_settings.settings) { # Migrate 'prevention_settings' to 'settings' containing required values - Set-Property $i settings @(($i.prevention_settings.settings | Select-Object id,value)) - $i.PSObject.Properties.Remove('prevention_settings') + Set-Property $i settings ($i.prevention_settings.settings | Select-Object id,value) + [void]$i.PSObject.Properties.Remove('prevention_settings') } - # Select allowed fields, when populated - [string[]]$Select = @('name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -349,8 +320,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconPreventionPolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -372,7 +345,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconPreventionPolicy [Parameter(ParameterSetName='/policy/entities/prevention/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -382,7 +355,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconPreventionPolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -411,7 +384,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconPreventionPrecedence [string]$PlatformName, [Parameter(ParameterSetName='/policy/entities/prevention-precedence/v1:post',Mandatory,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/policy-response.ps1 b/public/policy-response.ps1 index a17dff27..1a91db6f 100644 --- a/public/policy-response.ps1 +++ b/public/policy-response.ps1 @@ -4,8 +4,8 @@ function Edit-FalconResponsePolicy { Modify Real-time Response policies .DESCRIPTION Requires 'Response policies: Write'. -.PARAMETER Array -An array of policies to modify in a single request +.PARAMETER InputObject +One or more policies to modify in a single request .PARAMETER Id Policy identifier .PARAMETER Name @@ -19,21 +19,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconResponsePolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/response/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconResponsePolicy' - Endpoint = '/policy/entities/response/v1:patch' - Required = @('id') - Pattern = @('id') - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'Edit-FalconResponsePolicy' '/policy/entities/response/v1:patch' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/response/v1:patch',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id, @@ -46,21 +35,17 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconResponsePolicy [object[]]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/response/v1:patch' - Format = @{ Body = @{ resources = @('name','id','description','settings'); root = @('resources') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/response/v1:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select required values from 'settings' sub-object - if ($i.settings.settings) { $i.settings = $i.settings.settings | Select-Object id,value } - # Select allowed fields, when populated - [string[]]$Select = @('id','name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties and modify 'settings' to contain required values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + if ($i.settings.settings) { Set-Property $i settings ($i.settings.settings | Select-Object id,value) } + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -68,8 +53,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconResponsePolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -107,7 +94,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconResponsePolicy [Parameter(ParameterSetName='/policy/entities/response/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/combined/response/v1:get',Position=1)] [Parameter(ParameterSetName='/policy/queries/response/v1:get',Position=1)] @@ -146,7 +133,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconResponsePolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters @{ members = 'Get-FalconResponsePolicyMember' } @@ -251,7 +238,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconResponsePolicyAction } } process { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('Id') if ($PSBoundParameters.GroupId) { $PSBoundParameters['action_parameters'] = @(@{ name = 'group_id'; value = $PSBoundParameters.GroupId }) @@ -266,8 +253,8 @@ function New-FalconResponsePolicy { Create Real-time Response policies .DESCRIPTION Requires 'Response policies: Write'. -.PARAMETER Array -An array of policies to create in a single request +.PARAMETER InputObject +One or more policies to create in a single request .PARAMETER Name Policy name .PARAMETER PlatformName @@ -281,22 +268,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconResponsePolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/response/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconResponsePolicy' - Endpoint = '/policy/entities/response/v1:post' - Required = @('name','platform_name') - Content = @('platform_name') - Format = @{ platform_name = 'PlatformName' } - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconResponsePolicy' '/policy/entities/response/v1:post' })] + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/response/v1:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/policy/entities/response/v1:post',Mandatory,Position=2)] @@ -310,23 +285,17 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconResponsePolicy [object[]]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/response/v1:post' - Format = @{ - Body = @{ resources = @('description','platform_name','name','settings'); root = @('resources') } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/response/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select required values from 'settings' sub-object - if ($i.settings.settings) { $i.settings = $i.settings.settings | Select-Object id,value } - # Select allowed fields, when populated - [string[]]$Select = @('name','description','platform_name','settings').foreach{ if ($i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties and modify 'settings' to contain required values + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + if ($i.settings.settings) { Set-Property $i settings ($i.settings.settings | Select-Object id,value) } + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -334,8 +303,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconResponsePolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -357,7 +328,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconResponsePolicy [Parameter(ParameterSetName='/policy/entities/response/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -367,7 +338,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconResponsePolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -396,7 +367,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconResponsePrecedence [string]$PlatformName, [Parameter(ParameterSetName='/policy/entities/response-precedence/v1:post',Mandatory,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/policy-sensor-update.ps1 b/public/policy-sensor-update.ps1 index 05c5c658..347cbd4b 100644 --- a/public/policy-sensor-update.ps1 +++ b/public/policy-sensor-update.ps1 @@ -4,8 +4,8 @@ function Edit-FalconSensorUpdatePolicy { Modify Sensor Update policies .DESCRIPTION Requires 'Sensor update policies: Write'. -.PARAMETER Array -An array of policies to modify in a single request +.PARAMETER InputObject +One or more policies to modify in a single request .PARAMETER Id Policy identifier .PARAMETER Name @@ -19,21 +19,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconSensorUpdatePolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/sensor-update/v2:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconSensorUpdatePolicy' - Endpoint = '/policy/entities/sensor-update/v2:patch' - Required = @('id') - Pattern = @('id') - } - Confirm-Parameter @Param - } + Confirm-Parameter $_ 'Edit-FalconSensorUpdatePolicy' '/policy/entities/sensor-update/v2:patch' })] - [Alias('resources')] - [object[]]$Array, + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/sensor-update/v2:patch',Mandatory,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id, @@ -46,33 +37,16 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconSensorUpdatePolicy [object]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/sensor-update/v2:patch' - Format = @{ Body = @{ resources = @('name','id','description','settings'); root = @('resources') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/sensor-update/v2:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('id','name','description','platform_name','settings').foreach{ - if ($_ -eq 'settings') { - # Filter 'settings' - $i.settings = $i.settings | Select-Object @($i.settings.PSObject.Properties | - Where-Object { $null -ne $_.Value -and $_.Value -ne '' }).Name - if ($i.settings.variants) { - # Filter 'variants' - $i.settings.variants = @($i.settings.variants).foreach{ - $_ | Select-Object @($_.PSObject.Properties | Where-Object { - $null -ne $_.Value -and $_.Value -ne '' }).Name - } - } - } - if ($i.$_) { $_ } - } - if ($Select) { $List.Add(($i | Select-Object $Select)) } + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -80,8 +54,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconSensorUpdatePolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -209,7 +185,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSensorUpdatePolicy [Parameter(ParameterSetName='/policy/entities/sensor-update/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/combined/sensor-update/v2:get',Position=1)] [Parameter(ParameterSetName='/policy/queries/sensor-update/v1:get',Position=1)] @@ -248,7 +224,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSensorUpdatePolicy } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['Id'] = @($List) } if ($Include) { Invoke-Falcon @Param -UserInput $PSBoundParameters | ForEach-Object { Add-Include $_ $PSBoundParameters @{ members = 'Get-FalconSensorUpdatePolicyMember' } @@ -331,8 +307,7 @@ Host identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUninstallToken #> - [CmdletBinding(DefaultParameterSetName='/policy/combined/reveal-uninstall-token/v1:post', - SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/policy/combined/reveal-uninstall-token/v1:post',SupportsShouldProcess)] param( [Parameter(ParameterSetName='/policy/combined/reveal-uninstall-token/v1:post',Position=1)] [Alias('audit_message')] @@ -348,18 +323,26 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUninstallToken [ValidatePattern('^([a-fA-F0-9]{32}|MAINTENANCE)$')] [string]$Id ) - begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} - process { - if ($Include) { - # Append properties from 'Include' - foreach ($Request in (Invoke-Falcon @Param -UserInput $PSBoundParameters)) { - @($Request | Get-FalconHost -EA 0 | Select-Object @($Include + 'device_id')).foreach{ - @($_.PSObject.Properties).foreach{ Set-Property $Request $_.Name $_.Value } + 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) { + $Request = @($List).foreach{ + $PSBoundParameters['Id'] = $_ + Invoke-Falcon @Param -UserInput $PSBoundParameters -EA 1 + } + if ($Request -and $Include) { + [string[]]$ReqProperty = @($Request[0].PSObject.Properties.Name).Where({$_ -ne 'device_id'}) + foreach ($i in ($Request.device_id | Get-FalconHost -EA 0 | Select-Object @($Include + 'device_id'))) { + @($ReqProperty).foreach{ Set-Property $i $_ @($Request).Where({$_.device_id -eq $i.device_id}).$_ } + $i } + } else { $Request } - } else { - Invoke-Falcon @Param -UserInput $PSBoundParameters } } } @@ -400,7 +383,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconSensorUpdatePolicyActi } } process { - $PSBoundParameters['Ids'] = @($PSBoundParameters.Id) + $PSBoundParameters['ids'] = @($PSBoundParameters.Id) [void]$PSBoundParameters.Remove('Id') if ($PSBoundParameters.GroupId) { $PSBoundParameters['action_parameters'] = @(@{ name = 'group_id'; value = $PSBoundParameters.GroupId }) @@ -415,8 +398,8 @@ function New-FalconSensorUpdatePolicy { Create Sensor Update policies .DESCRIPTION Requires 'Sensor update policies: Write'. -.PARAMETER Array -An array of policies to create in a single request +.PARAMETER InputObject +One or more policies to create in a single request .PARAMETER PlatformName Operating system platform .PARAMETER Name @@ -430,22 +413,12 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconSensorUpdatePolicy #> [CmdletBinding(DefaultParameterSetName='/policy/entities/sensor-update/v2:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconSensorUpdatePolicy' - Endpoint = '/policy/entities/sensor-update/v2:post' - Required = @('name','platform_name') - Content = @('platform_name') - Format = @{ platform_name = 'PlatformName' } - } - Confirm-Parameter @Param - } + Confirm-Parameter $_ 'New-FalconSensorUpdatePolicy' '/policy/entities/sensor-update/v2:post' })] - [Alias('resources')] - [object[]]$Array, + [Alias('resources','Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/policy/entities/sensor-update/v2:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/policy/entities/sensor-update/v2:post',Mandatory,Position=2)] @@ -459,39 +432,20 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconSensorUpdatePolicy [object]$Setting ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/policy/entities/sensor-update/v2:post' - Format = @{ - Body = @{ resources = @('description','platform_name','name','settings'); root = @('resources') } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/policy/entities/sensor-update/v2:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('name','description','platform_name','settings').foreach{ - if ($_ -eq 'settings') { - if ($i.settings.scheduler -and $i.settings.scheduler.enabled -eq $false) { - # Remove 'scheduler' if disabled - $i.settings.PSObject.Properties.Remove('scheduler') - } - # Filter 'settings' to remove empty values - $i.settings = $i.settings | Select-Object @($i.settings.PSObject.Properties | - Where-Object { $null -ne $_.Value -and $_.Value -ne '' }).Name - if ($i.settings.variants) { - # Filter 'variants' to remove empty values - $i.settings.variants = @($i.settings.variants).foreach{ - $_ | Select-Object @($_.PSObject.Properties | Where-Object { - $null -ne $_.Value -and $_.Value -ne '' }).Name - } - } - } - if ($i.$_) { $_ } + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined 'resources' properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.resources + if ($i.settings.scheduler -and $i.settings.scheduler.enabled -eq $false) { + # Remove 'scheduler' if disabled + [void]$i.settings.PSObject.Properties.Remove('scheduler') } - if ($Select) { $List.Add(($i | Select-Object $Select)) } + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -499,8 +453,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconSensorUpdatePolicy } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('resources') } } for ($i = 0; $i -lt $List.Count; $i += 100) { - $PSBoundParameters['Array'] = @($List[$i..($i + 99)]) + $PSBoundParameters['resources'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -522,7 +478,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSensorUpdatePolicy [Parameter(ParameterSetName='/policy/entities/sensor-update/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -532,7 +488,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSensorUpdatePolicy process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -562,7 +518,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Set-FalconSensorUpdatePrecedence [string]$PlatformName, [Parameter(ParameterSetName='/policy/entities/sensor-update-precedence/v1:post',Mandatory,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/policy-sv-exclusions.ps1 b/public/policy-sv-exclusions.ps1 index 35ff1147..67f88481 100644 --- a/public/policy-sv-exclusions.ps1 +++ b/public/policy-sv-exclusions.ps1 @@ -4,14 +4,16 @@ function Edit-FalconSvExclusion { Modify a Sensor Visibility exclusion .DESCRIPTION Requires 'Sensor Visibility Exclusions: Write'. -.PARAMETER Id -Exclusion identifier .PARAMETER Value RegEx pattern value .PARAMETER GroupId Host group identifier or 'all' to apply to all hosts +.PARAMETER DescendantProcess +Apply to descendant processes .PARAMETER Comment Audit log comment +.PARAMETER Id +Exclusion identifier .LINK https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconSvExclusion #> @@ -26,9 +28,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconSvExclusion [object[]]$GroupId, [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:patch',ValueFromPipelineByPropertyName, Position=3)] + [Alias('is_descendant_process')] + [boolean]$DescendantProcess, + [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:patch',ValueFromPipelineByPropertyName, + Position=4)] [string]$Comment, [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:patch',Mandatory, - ValueFromPipelineByPropertyName,ValueFromPipeline,Position=4)] + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=5)] [ValidatePattern('^[a-fA-F0-9]{32}$')] [string]$Id ) @@ -76,7 +82,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSvExclusion [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/policy/queries/sv-exclusions/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -102,10 +108,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSvExclusion $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function New-FalconSvExclusion { @@ -116,10 +126,12 @@ Create a Sensor Visibility exclusion Requires 'Sensor Visibility Exclusions: Write'. .PARAMETER Value RegEx pattern value -.PARAMETER Comment -Audit log comment .PARAMETER GroupId Host group identifier or 'all' to apply to all hosts +.PARAMETER DescendantProcess +Apply to descendant processes +.PARAMETER Comment +Audit log comment .LINK https://github.com/crowdstrike/psfalcon/wiki/New-FalconSvExclusion #> @@ -134,6 +146,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconSvExclusion [object[]]$GroupId, [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:post',ValueFromPipelineByPropertyName, Position=3)] + [Alias('is_descendant_process')] + [boolean]$DescendantProcess, + [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:post',ValueFromPipelineByPropertyName, + Position=4)] [string]$Comment ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -167,7 +183,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSvExclusion [string]$Comment, [Parameter(ParameterSetName='/policy/entities/sv-exclusions/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -177,7 +193,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSvExclusion process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/psf-config.ps1 b/public/psf-config.ps1 index 5e45677c..13b5ee6b 100644 --- a/public/psf-config.ps1 +++ b/public/psf-config.ps1 @@ -74,8 +74,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Export-FalconConfig } } # Export results to json file and output created file name - ConvertTo-Json @($Config) -Depth 32 | Out-File $ConfigFile -Append - $ConfigFile + try { + ConvertTo-Json @($Config) -Depth 32 | Out-File $ConfigFile -Append + $ConfigFile + } catch { + throw "Unable to write to '$((Get-Location).Path)'. Try 'Export-FalconConfig' in a new location." + } } } # Get current location and set output archive path @@ -89,8 +93,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Export-FalconConfig } else { if (!$Select) { # Use items in 'ValidateSet' when not provided - [string[]]$Select = @((Get-Command $MyInvocation.MyCommand.Name).ParameterSets.Where({ $_.Name -eq - 'ExportItem' }).Parameters.Where({ $_.Name -eq 'Select' }).Attributes.ValidValues).foreach{ $_ } + [string[]]$Select = @((Get-Command $MyInvocation.MyCommand.Name).ParameterSets.Where({$_.Name -eq + 'ExportItem'}).Parameters.Where({$_.Name -eq 'Select'}).Attributes.ValidValues).foreach{ $_ } } if ($Select -contains 'FileVantagePolicy' -and $Select -notcontains 'FileVantageRuleGroup') { # Force 'FileVantageRuleGroup' when exporting 'FileVantagePolicy' for 'rule_groups' @@ -161,7 +165,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig [string]$Path, [Alias('Force')] [switch]$AssignExisting, - [ValidateSet('DeviceControlPolicy','FirewallPolicy','PreventionPolicy','ResponsePolicy','SensorUpdatePolicy')] + [ValidateSet('DeviceControlPolicy','PreventionPolicy','ResponsePolicy','SensorUpdatePolicy')] [string[]]$ModifyDefault, [ValidateSet('DeviceControlPolicy','FileVantagePolicy','FileVantageRuleGroup','FirewallGroup','FirewallPolicy', 'HostGroup','IoaExclusion','IoaGroup','Ioc','MlExclusion','PreventionPolicy','ResponsePolicy','Script', @@ -208,7 +212,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } elseif ($Type -match '^FileVantageRule(Group)?$') { $Item.type } elseif ($Type -eq 'FileVantageExclusion' -and $Item.policy_id) { - @($Config.FileVantagePolicy.PSObject.Properties.Value).Where({ $_.id -eq $Item.policy_id }).platform | + @($Config.FileVantagePolicy.PSObject.Properties.Value).Where({$_.id -eq $Item.policy_id}).platform | Select-Object -Unique } else { $null @@ -235,11 +239,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } $Notify.Add($Type) if ($Type -eq 'FileVantageRule') { - $Notify.Add("$($Obj.name) in '$(@($Config.Ids.FileVantageRuleGroup).Where({ - $_.new_id -eq $Item.rule_group_id }).name)'.") + $Notify.Add("$($Obj.name) in '$(@($Config.Ids.FileVantageRuleGroup).Where({$_.new_id -eq + $Item.rule_group_id}).name)'.") } elseif ($Type -eq 'FileVantageExclusion') { - $Notify.Add("'$($Obj.name)' in '$(@($Config.Ids.FileVantagePolicy).Where({ - $_.new_id -eq $Item.policy_id }).name)'.") + $Notify.Add("'$($Obj.name)' in '$(@($Config.Ids.FileVantagePolicy).Where({$_.new_id -eq + $Item.policy_id}).name)'.") } else { $Notify.Add("'$($Obj.name)'.") } @@ -248,40 +252,178 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } function Compare-ImportData ([string]$Item) { if ($Config.$Item.Cid) { - # Define properties for comparison between imported and existing items - [string[]]$Compare = @('name','platform','platform_name','type','value').Where({ - ($Config.$Item.Cid | Get-Member -MemberType NoteProperty).Name -contains $_ - }) - # Capture non-existing items for future modification - $FilterScript = [scriptblock]::Create((@($Compare).foreach{ - "`$Config.$($Item).Cid.$($_) -notcontains `$_.$($_)" }) -join ' -and ') - @($Config.$Item.Import | Where-Object -FilterScript $FilterScript).foreach{ $_ } - if ($ModifyExisting -contains $Item) { - # Capture (non-policy) items to modify - $FilterScript = [scriptblock]::Create((@($Compare).foreach{ - "`$Config.$($Item).Cid.$($_) -eq `$_.$($_)" }) -join ' -and ') + $Platform = @{} + @('platform','platform_name').foreach{ + if ($Config.$Item.Cid.$_) { + @($Config.$Item.Cid.$_ | Select-Object -Unique).foreach{ $Platform[$_] = @{} } + } + } + if ($Platform.Count -gt 0) { + foreach ($Key in $Platform.Keys) { + # Define properties for comparison between imported and existing items (by platform) + @('Cid','Import').foreach{ + $Platform.$Key[$_] = @($Config.$Item.$_).Where({$_.platform -eq $Key -or $_.platform_name -eq $Key}) + } + [string[]]$Available = ($Platform.$Key.Cid | Get-Member -MemberType NoteProperty | + Select-Object -Unique).Name + [string[]]$Compare = @('name','type','value').Where({$Available -contains $_}) + Write-Log 'Import-FalconConfig' "Evaluating $Key $Item using '$($Compare -join ',')'" + $FilterScript = [scriptblock]::Create( + (@($Compare).foreach{ "`$Platform.`$Key.Cid.$_ -notcontains `$_.$_" }) -join ' -and ' + ) + @($Platform.$Key.Import | Where-Object -FilterScript $FilterScript).foreach{ + # Capture items for import (by platform) + Write-Log 'Import-FalconConfig' "Selecting '$( + if ($_.value) { + if ($_.type) { $_.type,$_.value -join ':' } else { $_.value } + } elseif ($_.precedence -and $Item -eq 'FileVantageRule') { + $_.precedence + } else { + $_.name + } + )' for import" + $_ + } + if ($ModifyExisting -contains $Item) { + # Capture (non-policy) items to modify + $FilterScript = [scriptblock]::Create( + (@($Compare).foreach{ "`$Platform.`$Key.Cid.$_ -eq `$_.$_" }) -join ' -and ' + ) + @($Platform.$Key.Import | Where-Object -FilterScript $FilterScript).foreach{ + Write-Log 'Import-FalconConfig' "Selecting '$( + if ($_.value) { + if ($_.type) { $_.type,$_.value -join ':' } else { $_.value } + } elseif ($_.precedence -and $Item -eq 'FileVantageRule') { + $_.precedence + } else { + $_.name + } + )' for modification" + $Config.$Item.Modify.Add($_) + } + } + } + } else { + # Define properties for comparison between imported and existing items + [string[]]$Available = ($Config.$Item.Cid | Get-Member -MemberType NoteProperty | + Select-Object -Unique).Name + [string[]]$Compare = @('name','type','value').Where({$Available -contains $_}) + Write-Log 'Import-FalconConfig' "Evaluating $Item using '$($Compare -join ',')'" + $FilterScript = [scriptblock]::Create( + (@($Compare).foreach{ "`$Config.$Item.Cid.$_ -notcontains `$_.$_" }) -join ' -and ' + ) @($Config.$Item.Import | Where-Object -FilterScript $FilterScript).foreach{ - $Config.$Item.Modify.Add($_) + # Capture items for import + Write-Log 'Import-FalconConfig' "Selecting '$( + if ($_.value) { + if ($_.type) { $_.type,$_.value -join ':' } else { $_.value } + } elseif ($_.precedence -and $Item -eq 'FileVantageRule') { + $_.precedence + } else { + $_.name + } + )' for import" + $_ + } + if ($ModifyExisting -contains $Item) { + # Capture (non-policy) items to modify + $FilterScript = [scriptblock]::Create((@($Compare).foreach{ + "`$Config.$Item.Cid.$_ -eq `$_.$_" }) -join ' -and ') + @($Config.$Item.Import | Where-Object -FilterScript $FilterScript).foreach{ + Write-Log 'Import-FalconConfig' "Selecting '$( + if ($_.value) { + if ($_.type) { $_.type,$_.value -join ':' } else { $_.value } + } elseif ($_.precedence -and $Item -eq 'FileVantageRule') { + $_.precedence + } else { + $_.name + } + )' for modification" + $Config.$Item.Modify.Add($_) + } } } } elseif ($Config.$Item.Import) { - # Output all items + # Capture all items for import when none are present in target environment @($Config.$Item.Import) } } function Compare-Setting ([object]$New,[object]$Old,[string]$Type,[string]$Property,[switch]$Result) { - if ($Type -match 'Policy$') { - # Compare modified policy settings + if ($Type -eq 'DeviceControlPolicy') { + [string[]]$Select = if ($Old) { + foreach ($i in @($New.settings.PSObject.Properties)) { + if ($i.Name -match '^(enforcement_mode|end_user_notification|enhanced_file_metadata)$') { + if ($i.Value -ne $Old.settings.($i.Name)) { + if ($Result) { + # Capture result + Add-Result Modified $New $Type $i.Name $Old.settings.($i.Name) $i.Value + } else { + # Output modified property name + $i.Name + } + } + } + } + } + # Output settings to be modified by property name + if ($Select) { $New.settings | Select-Object $Select } + } elseif ($Type -eq 'SensorUpdatePolicy') { + [string[]]$Select = if ($Old) { + foreach ($i in @($New.settings.PSObject.Properties)) { + # Check SensorUpdatePolicy settings sub-properties for changes + if ($i.Name -match '^(scheduler|variants)$') { + # Check 'scheduler' and 'variants' sub-properties + if ($Result -and $null -eq $New.settings.($i.Name)) { + @($Old.settings.($i.Name)).foreach{ + @($_.PSObject.Properties).foreach{ + Add-Result Modified $New $Type ($i.Name,$_.Name -join '.') $_.Value $null + } + } + } else { + [boolean[]]$SubProp = @($i.Value).foreach{ + @($_.PSObject.Properties).foreach{ + if ($_.Value -ne $Old.settings.($i.Name).($_.Name)) { + if ($Result) { + # Capture sub-property result + Add-Result Modified $New $Type ($i.Name,$_.Name -join '.') $Old.settings.($i.Name).( + $_.Name) $_.Value + } else { + # Output true for modified sub-property + $true + } + } + } + } + # Output property name when modified sub-properties are present + if ($SubProp -eq $true) { $i.Name } + } + } else { + if ($i.Value -ne $Old.settings.($i.Name)) { + if ($Result) { + # Capture result + Add-Result Modified $New $Type $i.Name $Old.settings.($i.Name) $i.Value + } else { + # Output modified property name + $i.Name + } + } + } + } + } + # Output settings to be modified by property name + if ($Select) { $New.settings | Select-Object $Select } + } elseif ($Type -match 'Policy$') { + # Compare modified policy settings with 'id' and 'value' sub-properties $NewArr = if ($New.prevention_settings) { $New.prevention_settings } else { $New.settings } $OldArr = if ($Old.prevention_settings) { $Old.prevention_settings } else { $Old.settings } if ($OldArr -or $Result) { foreach ($Item in $NewArr) { if ($Item.value.PSObject.Properties.Name -eq 'enabled') { - if ($OldArr.Where({ $_.id -eq $Item.id }).value.enabled -ne $Item.value.enabled) { + if ($OldArr.Where({$_.id -eq $Item.id}).value.enabled -ne $Item.value.enabled) { if ($Result) { # Capture modified result for boolean settings - Add-Result Modified $New $Type $Item.id ($OldArr.Where({ $_.id -eq - $Item.id }).value.enabled) $Item.value.enabled + Add-Result Modified $New $Type $Item.id ($OldArr.Where({$_.id -eq + $Item.id}).value.enabled) $Item.value.enabled } else { # Output setting to be modified $Item | Select-Object id,value @@ -289,7 +431,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } else { foreach ($Name in $Item.value.PSObject.Properties.Name) { - if ($OldArr.Where({ $_.id -eq $Item.id }).value.$Name -ne $Item.value.$Name) { + if ($OldArr.Where({$_.id -eq $Item.id}).value.$Name -ne $Item.value.$Name) { if ($Result) { # Capture modified result for sub-settings Add-Result Modified $New $Type ($Item.id,$Name -join ':') (($OldArr | Where-Object { @@ -311,8 +453,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig if ($Property -eq 'field_values') { foreach ($Name in $New.$Property.name) { # Track 'field_values' for IoaRule for each modified value - $OldValue = ($Old.$Property | Where-Object { $_.name -eq $Name }).values | ConvertTo-Json -Compress - $NewValue = ($New.$Property | Where-Object { $_.name -eq $Name }).values | ConvertTo-Json -Compress + $OldValue = @($Old.$Property).Where({$_.name -eq $Name}).values | ConvertTo-Json -Compress + $NewValue = @($New.$Property).Where({$_.name -eq $Name}).values | ConvertTo-Json -Compress if ($NewValue -ne $OldValue) { Add-Result Modified $New $Type $Name $OldValue $NewValue } } } elseif ($Property) { @@ -320,7 +462,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig Add-Result Modified $New $Type $Property $Old.$Property $New.$Property } } else { - @($New.PSObject.Properties.Name).Where({ $_ -notmatch '^(id|comment)$' }).foreach{ + @($New.PSObject.Properties.Name).Where({$_ -notmatch '^(id|comment)$'}).foreach{ if ($New.$_ -ne $Old.$_) { Add-Result Modified $New $Type $_ $Old.$_ $New.$_ } } } @@ -342,6 +484,20 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } return $Object } + function Get-CurrentBuild ([string]$String,[object[]]$List,[string]$Platform) { + if ($String -match '\|') { + # Match by sensor build tag, replacing suffix with wildcard for cloud disparities + if ($String -match '^n\|tagged\|\d{1,}$') { $String = $String -replace '\d{1,}$','*' } + @($List).Where({$_.platform -eq $Platform -and $_.build -like "*|$String"}) | + Select-Object build,sensor_version + } elseif ($String) { + # Check for exact sensor build version match + @($List).Where({$_.platform -eq $Platform -and $_.build -eq $String}) | + Select-Object build,sensor_version,stage + } else { + $null + } + } function Import-ConfigData ([string]$FilePath) { # Load 'FalconConfig' archive into memory [hashtable]$Output = @{ Ids = @{}; Result = [System.Collections.Generic.List[object]]@() } @@ -380,8 +536,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } # Remove created and failed Ioc from 'Import' using 'id' value - [string[]]$Remove = @($Object.Value.Import).Where({ $_.type -eq $i.type -and $_.value -eq $i.value }).id - $Object.Value.Import = @($Object.Value.Import).Where({ $Remove -notcontains $_.id }) + [string[]]$Remove = @($Object.Value.Import).Where({$_.type -eq $i.type -and $_.value -eq $i.value}).id + $Object.Value.Import = @($Object.Value.Import).Where({$Remove -notcontains $_.id}) } # Repeat until 'Import' is empty if ($Object.Value.Import) { Invoke-CreateIoc $Object } @@ -405,12 +561,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig foreach ($OldId in $Object.rule_groups) { # Update rule_groups with new identifier(s) $Object.rule_groups = $Object.rule_groups -replace $OldId, - @($Config.Ids.FileVantageRuleGroup).Where({ $_.old_id -eq $OldId }).new_id + @($Config.Ids.FileVantageRuleGroup).Where({$_.old_id -eq $OldId}).new_id } if ($Object.rule_groups) { # Filter to rule_groups that are missing - [string[]]$Add = @($Object.rule_groups).Where({ $Cid.rule_groups -notcontains $_ -and - ![string]::IsNullOrWhiteSpace($_) }) + [string[]]$Add = @($Object.rule_groups).Where({$Cid.rule_groups -notcontains $_ -and + ![string]::IsNullOrWhiteSpace($_)}) if ($Add) { # Assign and capture result @(Add-FalconFileVantageRuleGroup -PolicyId $Object.id -Id $Add).foreach{ @@ -422,7 +578,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } elseif ($Property -eq 'host_groups' -and $Object.host_groups) { # Filter to host_groups that are missing - [string[]]$Add = @($Object.host_groups).Where({ $Cid.host_groups -notcontains $_ }) + [string[]]$Add = @($Object.host_groups).Where({$Cid.host_groups -notcontains $_}) if ($Add) { # Assign and capture result @(Add-FalconFileVantageHostGroup -PolicyId $Object.id -Id $Add).foreach{ @@ -434,12 +590,23 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } else { # Assign group(s) to target object [string]$Invoke = if ($Property -eq 'ioa_rule_groups') { 'add-rule-group' } else { 'add-host-group' } - $Req = foreach ($Id in $Object.$Property) { - if ($Cid.$Property -notcontains $Id) { @(Invoke-PolicyAction $Type $Invoke $Object.id $Id).foreach{ $_ }} + [object[]]$Req = foreach ($Id in $Object.$Property) { + if ($Cid.$Property -notcontains $Id) { + @(Invoke-PolicyAction $Type $Invoke $Object.id $Id).foreach{ + # Output entire result if object is returned, otherwise return '$Property.$Id' + if ($_.$Property) { $_ } else { $Id } + } + } } if ($Req) { - # Capture result - Add-Result Modified $Req[-1] $Type $Property ($Cid.$Property -join ',') ($Req[-1].$Property.id -join ',') + if ($Req[-1].$Property.id) { + # Capture result if entire object is returned + Add-Result Modified $Req[-1] $Type $Property ($Cid.$Property -join ',') ( + $Req[-1].$Property.id -join ',') + } else { + # Combine '$Property.$Id' values + Add-Result Modified $Object $Type $Property ($Cid.$Property -join ',') ($Req -join ',') + } } } } @@ -464,7 +631,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig # Import configuration files and capture identifiers for comparison if (!$ArchivePath) { throw "Failed to resolve '$($PSBoundParameters.Path)'." } $Config = Import-ConfigData $ArchivePath - @($Config.Keys).Where({ $_ -notmatch '^(Ids|FirewallRule|Result)$' }).foreach{ + @($Config.Keys).Where({$_ -notmatch '^(Ids|FirewallRule|Result)$'}).foreach{ if ($Allowed -notcontains $_) { throw "'$($_,'json' -join '.')' is not a valid Json file name. Ensure that all files within '$( $ArchivePath)' correspond with output from 'Export-FalconConfig' [$(($Allowed | ForEach-Object { @@ -472,7 +639,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig }) -join ',')]." } } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Value.Import })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Value.Import})) { foreach ($Import in $Pair.Value.Import) { # Create a record of identifiers within CID to compare with imports $Import = Compress-Property $Import @@ -484,7 +651,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -notmatch '^(Ids|Result)$' })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -notmatch '^(Ids|Result)$'})) { $Pair.Value['Cid'] = try { if ($Pair.Key -match '^FileVantage(Policy|RuleGroup)$') { [string]$Property = if ($Pair.Key -eq 'FileVantagePolicy') { 'platform' } else { 'type' } @@ -498,7 +665,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig $Param = @{ Detailed = $true; All = $true } if ($Pair.Key -eq 'FileVantagePolicy' -and $Config.($Pair.Key).Import.exclusions) { # Include 'exclusions' if present in imported policies - $Param['include'] = 'exclusions' + $Param['Include'] = 'exclusions' } @($Pair.Value.Import.$Property | Select-Object -Unique).foreach{ # Retrieve FileVantagePolicy/RuleGroup for each 'Type' and update identifiers @@ -506,7 +673,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig foreach ($i in (& "Get-Falcon$($Pair.Key)" @Param -Type $_ | Where-Object -FilterScript ( [scriptblock]::Create($Filter)))) { if ($Pair.Key -eq 'FileVantageRuleGroup' -and $i.assigned_rules.id -and - @($Pair.Value.Import).Where({ $_.type -eq $i.type -and $_.name -eq $i.name })) { + @($Pair.Value.Import).Where({$_.type -eq $i.type -and $_.name -eq $i.name})) { # Update FileVantageRuleGroup 'assigned_rules' with rule content when matching import is present $RuleId = $i.assigned_rules.id | Where-Object { ![string]::IsNullOrWhiteSpace($_) } if ($RuleId) { @@ -521,7 +688,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } else { # Retrieve existing items from CID and update identifiers Write-Host "[Import-FalconConfig] Retrieving '$($Pair.Key)'..." - @(& "Get-Falcon$($Pair.Key)" -Detailed -All).foreach{ + $Param = @{ Detailed = $true; All = $true } + # Include 'settings' with 'FirewallPolicy' + if ($Pair.Key -eq 'FirewallPolicy') { $Param['Include'] = 'settings' } + @(& "Get-Falcon$($Pair.Key)" @Param).foreach{ Update-Id $_ $Pair.Key Compress-Property $_ } @@ -557,15 +727,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig # Track 'Ignored' items for final output [string]$Comment = if ($Item.deleted -eq $true) { 'Deleted' - } elseif ($Item.type -and $Item.value -and @($Pair.Value.Cid).Where({ $_.type -eq $Item.type -and - $_.value -eq $Item.value })) { + } elseif ($Item.type -and $Item.value -and @($Pair.Value.Cid).Where({$_.type -eq $Item.type -and + $_.value -eq $Item.value})) { 'Exists' - } elseif ($Item.type -and $Item.name -and @($Pair.Value.Cid).Where({ $_.type -eq $Item.type -and - $_.name -eq $Item.name })) { + } elseif ($Item.type -and $Item.name -and @($Pair.Value.Cid).Where({$_.type -eq $Item.type -and + $_.name -eq $Item.name})) { 'Exists' - } elseif ($Item.value -and @($Pair.Value.Cid).Where({ $_.value -eq $Item.value })) { + } elseif ($Item.value -and @($Pair.Value.Cid).Where({$_.value -eq $Item.value})) { 'Exists' - } elseif ($Item.name -and @($Pair.Value.Cid).Where({ $_.name -eq $Item.name })) { + } elseif ($Item.name -and @($Pair.Value.Cid).Where({$_.name -eq $Item.name})) { 'Exists' } if ($Comment -and $ModifyExisting -notcontains $Pair.Key) { @@ -576,7 +746,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } if ($Pair.Key -eq 'FileVantageRuleGroup') { $Pair.Value.Import = foreach ($i in $Pair.Value.Import) { - if (!@($Pair.Value.Cid).Where({ $_.type -eq $i.type -and $_.name -eq $i.name })) { + if (!@($Pair.Value.Cid).Where({$_.type -eq $i.type -and $_.name -eq $i.name})) { # Remove rule groups that will not be created from 'Import' $i } elseif ($ModifyExisting -contains $Pair.Key) { @@ -589,7 +759,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } if ($Pair.Key -eq 'SensorUpdatePolicy' -and ($Pair.Value.Import -or $Pair.Value.Modify)) { - # Retrieve available sensor build versions to update 'tags' + # Retrieve available sensor build versions to update build versions [object[]]$BuildList = try { Write-Host "[Import-FalconConfig] Retrieving available sensor builds..." Get-FalconBuild @@ -598,40 +768,62 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig $Pair.Key)' import. Verify 'Sensor update policies: Write' permission." } foreach ($Item in @(@($Pair.Value.Import) + @($Pair.Value.Modify))) { - # Update tagged builds with current tagged build versions - if ($Item.settings.build -match '^\d+\|') { - [string]$Tag = ($Item.settings.build -split '\|',2)[-1] - # Replace 'latest' tagged build suffix digits with wildcard for imports into different clouds - if ($Tag -match '^n|tagged|\d{1,}$') { $Tag = $Tag -replace '\d{1,}$','*' } - $Current = @($BuildList).Where({ $_.build -like "*|$Tag" -and $_.platform -eq - $Item.platform_name }).build - if ($Current -and $Item.settings.build -ne $Current) { - $Item.settings.build = $Current - Write-Log 'Import-FalconConfig' "Updated build from '$($Item.settings.build)' to '$Current'" - } elseif (!$Current) { - Write-Log 'Import-FalconConfig' "Failed to match '$Tag' to current build for '$( - $Item.platform_name)'" + # Update sensor builds with current available build values + if ($Item.settings.build) { + [string]$pBuild = if ($Item.settings.build -match '|') { + ($Item.settings.build -split '\|',2)[-1] + } else { + $Item.settings.build + } + $pNew = Get-CurrentBuild $pBuild $BuildList $Item.platform_name + if ($pNew -and $pNew.build -ne $Item.settings.build) { + # Replace build with current tagged version + Write-Log 'Import-FalconConfig' ( + 'Replaced build "{0}" with "{1}" for {2} policy "{3}"' -f $Item.settings.build,$pNew.build, + $Item.platform_name,$Item.name) + @('build','sensor_version','stage').foreach{ Set-Property $Item.settings $_ $pNew.$_ } + } elseif (!$pNew) { + # Strip build if build match is not available + Set-Property $Item.settings build $null } } + if (!$Item.settings.build) { + # Strip build, sensor_version and stage if 'build' is not present in policy + Write-Log 'Import-FalconConfig' ( + 'Removed build values from {0} policy "{1}"' -f $Item.platform_name,$Item.name) + @('build','sensor_version','stage').foreach{ Set-Property $Item.settings $_ $null } + } if ($Item.settings.variants) { - # Update tagged 'variant' builds with current tagged build versions - foreach ($Variant in @($Item.settings.variants | Where-Object { $_.build -match '^\d+\|' })) { - $Tag = ($Variant.build -split '\|',2)[-1] - $Current = ($BuildList | Where-Object { $_.build -like "*|$Tag" -and $_.platform -eq - $Variant.platform }).build - if ($Current -and $Variant.build -ne $Current) { - $Variant.build = $Current - Write-Log 'Import-FalconConfig' "Updated variant build from '$($Variant.build)' to '$Current'" - } elseif (!$Current) { - Write-Log 'Import-FalconConfig' "Failed to match '$Tag' to current build for variant '$( - $Variant.platform)'" + foreach ($Variant in $Item.settings.variants) { + # Update sensor variants with current available variant build values + [string]$vBuild = if ($Variant.build -match '|') { + ($Variant.build -split '\|',2)[-1] + } else { + $Variant.build + } + $vNew = Get-CurrentBuild $vBuild $BuildList $Variant.platform + if ($vNew -and $vNew.build -ne $Variant.build) { + # Replace build with current tagged version + Write-Log 'Import-FalconConfig' ( + 'Replaced build "{0}" with "{1}" for {2} variant for policy "{3}"' -f $Variant.build, + $vNew.build,$Variant.platform,$Item.name) + @('build','sensor_version','stage').foreach{ Set-Property $Variant $_ $vNew.$_ } + } elseif (!$vNew) { + # Strip build if match is not available + Set-Property $Variant build $null + } + if (!$Variant.build) { + # Strip build and sensor_version if 'build' is not present + Write-Log 'Import-FalconConfig' ( + 'Removed build values from {0} variant for policy "{1}"' -f $Variant.platform,$Item.name) + @('build','sensor_version','stage').foreach{ Set-Property $Variant $_ $null } } } } } } } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -eq 'HostGroup' -and $_.Value.Import })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -eq 'HostGroup' -and $_.Value.Import})) { foreach ($HostGroup in ($Pair.Value.Import | & "New-Falcon$($Pair.Key)")) { # Create HostGroup to prepare for assignment Update-Id $HostGroup $Pair.Key @@ -639,13 +831,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } [void]$Pair.Value.Remove('Import') } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Value.Import -or $_.Value.Modify })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Value.Import -or $_.Value.Modify})) { # Update 'Import' and 'Modify' HostGroup ids @('Import','Modify').foreach{ foreach ($Item in $Pair.Value.$_) { @('groups','host_groups').foreach{ foreach ($OldId in $Item.$_) { - [string]$NewId = @($Config.Ids.HostGroup).Where({ $_.old_id -eq $OldId }).new_id + [string]$NewId = @($Config.Ids.HostGroup).Where({$_.old_id -eq $OldId}).new_id if ($NewId) { [string[]]$Item.$_ = $Item.$_ -replace $OldId,$NewId if ($NewId -ne $OldId) { @@ -658,7 +850,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } } } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -match 'Policy$' -and $_.Value.Import })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -match 'Policy$' -and $_.Value.Import})) { @($Pair.Value.Import | & "New-Falcon$($Pair.Key)").foreach{ # Create Policy Update-Id $_ $Pair.Key @@ -666,7 +858,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } [void]$Pair.Value.Remove('Import') } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -ne 'FirewallRule' -and $_.Value.Import })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -ne 'FirewallRule' -and $_.Value.Import})) { if ($Pair.Key -eq 'FileVantageRuleGroup') { foreach ($Item in $Pair.Value.Import) { @($Item | & "New-Falcon$($Pair.Key)").foreach{ @@ -692,11 +884,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig [object[]]$Rules = foreach ($Id in $FwGroup.rule_ids) { $Config.FirewallRule.Import | Where-Object { $_.family -eq $Id -and $_.deleted -eq $false } } - @($Rules).foreach{ - # Trim rule names to 64 characters and use 'rules' as 'rule_ids' - if ($_.name.length -gt 64) { $_.name = ($_.name).SubString(0,63) } - } if ($Rules) { + @($Rules).foreach{ + # Trim rule names to 64 characters and use 'rules' as 'rule_ids' + if ($_.name.length -gt 64) { $_.name = ($_.name).SubString(0,63) } + } Set-Property $FwGroup rules $Rules [void]$FwGroup.PSObject.Properties.Remove('rule_ids') } @@ -712,6 +904,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } elseif ($Pair.Key -eq 'IoaGroup') { foreach ($Item in $Pair.Value.Import) { # Create IoaGroup + if (!$Item.comment) { Set-Property $Item comment ($UserAgent,"Import-FalconConfig" -join ': ') } [object]$IoaGroup = $Item | & "New-Falcon$($Pair.Key)" if ($IoaGroup) { Update-Id $IoaGroup $Pair.Key @@ -720,6 +913,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig # Create IoaRule [object[]]$IoaGroup.rules = foreach ($Rule in $Item.rules) { $Rule.rulegroup_id = $IoaGroup.id + if (!$Rule.comment) { Set-Property $Rule comment ($UserAgent,"Import-FalconConfig" -join ': ') } $Req = try { $Rule | New-FalconIoaRule } catch { Write-Error $_ } if ($Req) { Add-Result Created $Req IoaRule @@ -729,7 +923,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } if ($IoaGroup.rules.enabled -eq $true) { @($IoaGroup | Edit-FalconIoaRule).foreach{ - @($_.rules).Where({ $_.enabled -eq $true }).foreach{ + @($_.rules).Where({$_.enabled -eq $true}).foreach{ # Enable IoaRule Add-Result Modified $_ IoaRule enabled $false $_.enabled } @@ -749,8 +943,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig Invoke-CreateIoc $Pair } elseif ($Pair.Key -eq 'Script') { foreach ($Item in $Pair.Value.Import) { - # Create Script @($Item | & "Send-Falcon$($Pair.Key)").foreach{ + # Create Script Add-Result Created ($Item | Select-Object name,platform) $Pair.Key } } @@ -765,17 +959,17 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } [void]$Pair.Value.Remove('Import') } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -notmatch 'Policy$' -and $_.Value.Modify })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -notmatch 'Policy$' -and $_.Value.Modify})) { if ($Pair.Key -eq 'FileVantageRuleGroup') { foreach ($Group in $Pair.Value.Modify) { - $CidGroup = @($Config.($Pair.Key).Cid).Where({ $_.type -eq $Group.type -and $_.name -eq $Group.name }) + $CidGroup = @($Config.($Pair.Key).Cid).Where({$_.type -eq $Group.type -and $_.name -eq $Group.name}) if ($CidGroup) { foreach ($Rule in $Group.assigned_rules) { - $CidRule = @($CidGroup.assigned_rules).Where({ $_.type -eq $Rule.type -and $_.name -eq $Rule.name }) + $CidRule = @($CidGroup.assigned_rules).Where({$_.type -eq $Rule.type -and $_.name -eq $Rule.name}) if ($CidRule) { # Evaluate and update each FileVantageRule when required - [string[]]$Modified = @($Rule.PSObject.Properties.Name).Where({ $_ -notmatch - '^(type|(rule_group_)?id)$' }).foreach{ + [string[]]$Modified = @($Rule.PSObject.Properties.Name).Where({$_ -notmatch + '^(type|(rule_group_)?id)$'}).foreach{ if (!$CidRule.$_ -or $CidRule.$_ -ne $Rule.$_) { if (($_ -eq 'content_files' -and ![string]::IsNullOrWhiteSpace($CidRule.$_) -or ![string]::IsNullOrWhiteSpace($Rule.$_)) -or $_ -ne 'content_files') { @@ -828,22 +1022,20 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig [scriptblock]::Create($Filter)) if ($Cid) { [System.Collections.Generic.List[string]]$Modify = @('id') - @($Select).Where({ $_ -ne 'id' }).foreach{ + @($Select).Where({$_ -ne 'id'}).foreach{ [object]$Diff = if ($null -ne $Item.$_ -and $null -ne $Cid.$_) { # Compare properties that exist in both 'Modify' and CID if ($Pair.Key -eq 'FirewallGroup' -and $_ -eq 'rule_ids') { - <# - if ($Item.rule_ids) { + # if ($Item.rule_ids) { # Select FirewallRule from import using 'family' as 'id' value - [object[]]$FwRule = foreach ($Rule in $Item.rule_ids) { - $Config.FirewallRule.Import | Where-Object { $_.family -eq $Rule -and - $_.deleted -eq $false } - } - if ($FwRule) { + # [object[]]$FwRule = foreach ($Rule in $Item.rule_ids) { + # $Config.FirewallRule.Import | Where-Object { $_.family -eq $Rule -and + # $_.deleted -eq $false } + # } + # if ($FwRule) { # Evaluate rules for modification - } - } - #> + # } + # } } elseif ($Pair.Key -eq 'IoaGroup' -and $_ -eq 'rules') { foreach ($Rule in $Item.$_) { # Evaluate each IoaRule @@ -910,7 +1102,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } else { foreach ($Item in ($EditList | & "Edit-Falcon$($Pair.Key)")) { foreach ($Result in ($EditList | Where-Object { $_.id -eq $Item.id })) { - @($Result.PSObject.Properties.Name).Where({ $_ -ne 'id' -and $_ -ne 'comment' }).foreach{ + @($Result.PSObject.Properties.Name).Where({$_ -ne 'id' -and $_ -ne 'comment'}).foreach{ # Modify item and capture result Compare-Setting $Item ($Config.($Pair.Key).Cid | Where-Object { $_.id -eq $Item.id }) $Pair.Key $_ -Result @@ -934,28 +1126,51 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig } [void]$Pair.Value.Remove('Modify') } - foreach ($Pair in $Config.GetEnumerator().Where({ $_.Key -match 'Policy$' -and $_.Value.Modify })) { + foreach ($Pair in $Config.GetEnumerator().Where({$_.Key -match 'Policy$' -and $_.Value.Modify})) { foreach ($Policy in $Pair.Value.Modify) { # Update policy with current id value and use CID value for comparison - [string]$Policy.id = @($Config.Ids.($Pair.Key)).Where({ $_.name -eq $Policy.name -and - $_.platform_name -eq $Policy.platform_name }).new_id - [object]$Cid = @($Config.($Pair.Key).cid).Where({ $_.id -eq $Policy.id }) + [string]$Policy.id = @($Config.Ids.($Pair.Key)).Where({$_.name -eq $Policy.name -and + $_.platform_name -eq $Policy.platform_name}).new_id + [object]$Cid = @($Config.($Pair.Key).cid).Where({$_.id -eq $Policy.id}) if ($Policy.id -and $Pair.Key -eq 'FirewallPolicy') { + # Check 'FirewallPolicy' for changes if ($Policy.settings.policy_id) { $Policy.settings.policy_id = $Policy.id } - foreach ($Id in $Policy.rule_group_ids) { - # Update 'rule_group_ids' with new id values - [object]$Group = $Config.Ids.FirewallGroup | Where-Object { $_.old_id -eq $Id } - if ($Group -and $Policy.rule_group_ids -contains $Id) { - [string[]]$Policy.rule_group_ids = $Policy.rule_group_ids -replace $Id,$Group.new_id + foreach ($Id in $Policy.settings.rule_group_ids) { + [object]$Group = @($Config.Ids.FirewallGroup).Where({$_.old_id -eq $Id}) + [string[]]$Policy.settings.rule_group_ids = if ($Group) { + # Update 'rule_group_ids' with new id values + Write-Log 'Import-FalconConfig' ('Updated FirewallGroup "{0}" to "{1}" under {2} "{3}"' -f + $Id,$Group.id,$Pair.Key,$Policy.id) + $Policy.settings.rule_group_ids -replace $Id,$Group.new_id + } else { + # Remove unmatched 'rule_group_ids' values + Write-Log 'Import-FalconConfig' ('Removed unmatched FirewallGroup "{0}" from {1} "{2}"' -f + $Id,$Pair.Key,$Policy.id) + $Policy.settings.rule_group_ids -replace $Id,$null } } + if (!$Policy.settings.rule_group_ids) { + # Remove empty 'rule_group_ids' value before submission of 'settings' + [void]$Policy.settings.PSObject.Properties.Remove('rule_group_ids') + } if ($Policy.settings) { - # Apply FirewallSetting @($Policy.settings | Edit-FalconFirewallSetting).foreach{ + # Apply FirewallSetting Set-Property $Policy settings $Policy.settings + @('platform_id','default_inbound','default_outbound','enforce','test_mode','local_logging').foreach{ + if ($Cid.settings.$_ -ne $Policy.settings.$_) { + # Add individual modified settings to output + Add-Result Modified $Policy $Pair.Key $_ $Cid.settings.$_ $Policy.settings.$_ + } + } + if (Compare-Object $Cid.settings.rule_group_ids $Policy.settings.rule_group_ids) { + # Add 'rule_group_ids' to output when modified + Add-Result Modified $Policy $Pair.Key rule_group_ids $Cid.settings.rule_group_ids ( + $Policy.settings.rule_group_ids) + } } } - } elseif ($Policy.id -and $Policy.prevention_settings -or $Policy.settings) { + } elseif ($Policy.id -and ($Policy.prevention_settings -or $Policy.settings)) { # Compare Policy settings $Setting = Compare-Setting $Policy $Cid $Pair.Key if ($Setting) { @@ -980,8 +1195,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Import-FalconConfig $Exclusion.PSObject.Properties.Remove('repeated') } if ($Existing) { - [string[]]$Modified = @($Exclusion.PSObject.Properties.Name).Where({ $_ -notmatch - '^((policy_)?id|\w+_timestamp)$' }).foreach{ + [string[]]$Modified = @($Exclusion.PSObject.Properties.Name).Where({$_ -notmatch + '^((policy_)?id|\w+_timestamp)$'}).foreach{ # Compare existing exclusion against import to find new or modified properties if ($_ -eq 'repeated') { foreach ($i in $Exclusion.repeated.PSObject.Properties.Name) { diff --git a/public/psf-devices.ps1 b/public/psf-devices.ps1 index 813c9e94..ac3c16cf 100644 --- a/public/psf-devices.ps1 +++ b/public/psf-devices.ps1 @@ -38,7 +38,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Find-FalconDuplicate ) begin { function Group-Selection ($Object,$GroupBy) { - ($Object | Group-Object $GroupBy).Where({ $_.Count -gt 1 -and $_.Name }).foreach{ + ($Object | Group-Object $GroupBy).Where({$_.Count -gt 1 -and $_.Name}).foreach{ $_.Group | Sort-Object last_seen | Select-Object -First ($_.Count - 1) } } @@ -98,19 +98,22 @@ Find hosts using a list of hostnames Perform hostname searches in groups of 100. Requires 'Hosts: Read'. +.PARAMETER InputObject +One or more hostnames to find .PARAMETER Path Path to a plain text file containing hostnames .PARAMETER Include Include additional properties .PARAMETER Partial Perform a non-exact search -.PARAMETER Array -An array containing hostnames .LINK https://github.com/crowdstrike/psfalcon/wiki/Find-FalconHostname #> [CmdletBinding(DefaultParameterSetName='Path',SupportsShouldProcess)] param( + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [Alias('Array')] + [string[]]$InputObject, [Parameter(ParameterSetName='Path',Mandatory,Position=1)] [ValidateScript({ if (Test-Path $_ -PathType Leaf) { @@ -121,45 +124,47 @@ https://github.com/crowdstrike/psfalcon/wiki/Find-FalconHostname })] [string]$Path, [Parameter(ParameterSetName='Path',Position=2)] - [Parameter(ParameterSetName='Array',Position=2)] + [Parameter(ParameterSetName='Pipeline',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(ParameterSetName='Path')] - [Parameter(ParameterSetName='Array')] - [switch]$Partial, - [Parameter(ParameterSetName='Array',Mandatory,ValueFromPipeline)] - [string[]]$Array + [Parameter(ParameterSetName='Pipeline')] + [switch]$Partial ) begin { - if ($Path) { - [string]$Path = $Script:Falcon.Api.Path($Path) - } else { - [System.Collections.Generic.List[string]]$List = @() - } + [System.Collections.Generic.List[string]]$List = @() + if ($Path) { [string]$Path = $Script:Falcon.Api.Path($Path) } [string[]]$Select = 'device_id','hostname' if ($Include) { $Select += $Include } } - process { if ($Array) { @($Array).foreach{ $List.Add($_) }}} + process { + if ($Path) { + $List.AddRange([string[]]((Get-Content -Path $Path).Normalize()).Where({ + ![string]::IsNullOrWhiteSpace($_)})) + } elseif ($InputObject) { + @($InputObject).Where({![string]::IsNullOrWhiteSpace($_)}).foreach{ $List.Add($_) } + } + } end { - [string[]]$HostList = if ($List) { $List } else { (Get-Content -Path $Path).Normalize() } - $HostList = $HostList | Select-Object -Unique | Where-Object { ![string]::IsNullOrEmpty($_) } - for ($i=0; $i -lt ($HostList | Measure-Object).Count; $i+=100) { - [string[]]$TempList = $HostList[$i..($i + 99)] - [string]$Filter = if ($Partial) { - (@($TempList).foreach{ "hostname:'$_'" }) -join ',' - } else { - (@($TempList).foreach{ "hostname:['$_']" }) -join ',' - } - [object[]]$HostList = Get-FalconHost -Filter $Filter -Detailed | Select-Object $Select - @($TempList).foreach{ - if (($Partial -and $HostList.hostname -notlike "$_*") -or (!$Partial -and - $HostList.hostname -notcontains $_)) { - $PSCmdlet.WriteWarning("[Find-FalconHostname] No match found for '$_'.") + if ($List) { + $List = @($List) | Select-Object -Unique + for ($i=0; $i -lt ($List | Measure-Object).Count; $i+=100) { + [string[]]$Group = @($List)[$i..($i+99)] + [string]$Filter = if ($Partial) { + (@($Group).foreach{ "hostname:'$_'" }) -join ',' + } else { + (@($Group).foreach{ "hostname:['$_']" }) -join ',' + } + $Req = Get-FalconHost -Filter $Filter -Detailed | Select-Object $Select + @($Group).foreach{ + if (($Partial -and $Req.hostname -notlike "$_*") -or (!$Partial -and $Req.hostname -notcontains $_)) { + $PSCmdlet.WriteWarning("[Find-FalconHostname] No match found for '$_'.") + } } + if ($Req) { $Req } } - if ($HostList) { $HostList } } } } \ No newline at end of file diff --git a/public/psf-fwmgr.ps1 b/public/psf-fwmgr.ps1 index 39adef9e..68eac168 100644 --- a/public/psf-fwmgr.ps1 +++ b/public/psf-fwmgr.ps1 @@ -197,7 +197,7 @@ https://github.com/crowdstrike/psfalcon/wiki/ConvertTo-FalconFirewallRule [string]$Value = if ($Name -eq 'image_name' -and $Rule.($Map.$Name) -notmatch '\.\w+$') { # Convert directory paths to glob syntax with a single asterisk [string]$Glob = $Rule.($Map.$Name) -replace '^\w:\\',$null - if ($Glob -match '\\$') { $Glob,'*' -join $null } else { $Glob,'*' -join '\' } + if ($Glob -match '\\$') { [string]::Concat($Glob,'*') } else { $Glob,'*' -join '\' } } else { $Rule.($Map.$Name) } diff --git a/public/psf-logscale.ps1 b/public/psf-logscale.ps1 index ba54c298..8218697b 100644 --- a/public/psf-logscale.ps1 +++ b/public/psf-logscale.ps1 @@ -1,15 +1,15 @@ function Register-FalconEventCollector { <# .SYNOPSIS -Define Falcon LogScale ingestion endpoint and token for logging +Define Falcon LogScale or Falcon NGSIEM ingestion endpoint and token for logging .DESCRIPTION -Once configured, the Falcon LogScale destination can be used by PSFalcon but the module will not send events to -Falcon LogScale until 'Enable' options are chosen. 'Remove-FalconEventCollector' can be used to remove a -configured destination and stop the transmission of events. +Once configured, the Falcon LogScale or Falcon NGSIEM destination can be used by PSFalcon but the module will not +send events to until 'Enable' options are chosen. 'Remove-FalconEventCollector' can be used to remove a configured +destination and stop the transmission of events. .PARAMETER Uri -Falcon LogScale cloud +Falcon LogScale cloud or Falcon NGSIEM HEC ingestion URI .PARAMETER Token -Falcon LogScale ingestion token +Falcon LogScale or Falcon NGSIEM ingestion token .PARAMETER Enable Define events to send to the collector .LINK @@ -21,7 +21,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Register-FalconEventCollector [Parameter(Mandatory,ValueFromPipelineByPropertyName,Position=1)] [System.Uri]$Uri, [Parameter(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}$')] + [ValidatePattern('^([a-fA-F0-9]{32}|[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12})$')] [string]$Token, [Parameter(ValueFromPipelineByPropertyName,Position=3)] [ValidateSet('responses','requests')] @@ -29,9 +29,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Register-FalconEventCollector ) process { if (!$Script:Falcon.Api) { throw "[ApiClient] has not been initiated. Try 'Request-FalconToken'." } - $Script:Falcon.Api.Collector = @{ - Uri = $PSBoundParameters.Uri.ToString() + 'api/v1/ingest/humio-structured/' - Token = $PSBoundParameters.Token + $Script:Falcon.Api.Collector = @{ Uri = $PSBoundParameters.Uri.ToString(); Token = $PSBoundParameters.Token } + if ($Token -match '^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$') { + $Script:Falcon.Api.Collector.Uri += 'api/v1/ingest/humio-structured/' } [string]$Message = "Added '$($Script:Falcon.Api.Collector.Uri)'" if ($PSBoundParameters.Enable) { @@ -44,7 +44,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Register-FalconEventCollector function Send-FalconEvent { <# .SYNOPSIS -Create Falcon LogScale events from PSFalcon command results +Create Falcon LogScale or Falcon NGSIEM events from PSFalcon command results .DESCRIPTION Uses the pre-defined 'Path' and 'Token' values from 'Register-FalconEventCollector' to create events from the output provided by a PSFalcon command. @@ -64,11 +64,31 @@ https://github.com/crowdstrike/psfalcon/wiki/Send-FalconEvent $ProgressPreference = 'SilentlyContinue' [System.Collections.Generic.List[object]]$List = @() } - process { if ($Object) { @($Object).foreach{ $List.Add($_) }}} + process { + if ($Script:Falcon.Api.Collector.Token -and $Script:Falcon.Api.Collector.Token -match '^[a-fA-F0-9]{32}$') { + # Force object into [PSCustomObject] type and send to Falcon NGSIEM + [PSCustomObject]$Object = if ($Object -is [string]) { @{ string = $Object } } else { $Object } + Set-Property $Object '@timestamp' ([DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()) + Set-Property $Object '@sourcetype' $Script:Falcon.Api.UserAgent + $Param = @{ + Uri = $Script:Falcon.Api.Collector.Uri + Method = 'POST' + Headers = @{ + Authorization = @('Bearer',$Script:Falcon.Api.Collector.Token) -join ' ' + ContentType = 'application/json' + } + Body = @{ event = $Object } | ConvertTo-Json -Depth 32 + } + try { [void](Invoke-WebRequest @Param -UseBasicParsing) } catch { Write-Error $_ } + } else { + if ($Object) { @($Object).foreach{ $List.Add($_) }} + } + } end { if (!$Script:Falcon.Api.Collector.Uri -or !$Script:Falcon.Api.Collector.Token) { throw "Falcon LogScale destination has not been configured. Try 'Register-FalconEventCollector'." } elseif ($List) { + # Send events to Falcon LogScale environment [object[]]$Events = @($List).foreach{ $Item = @{ timestamp = Get-Date -Format o; attributes = @{}} if ($_ -is [PSCustomObject]) { @@ -128,13 +148,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Unregister-FalconEventCollector } } $Register = @{ + # Add default Humio cloud addresses for autocompletion CommandName = 'Register-FalconEventCollector' ParameterName = 'Uri' ScriptBlock = { param($CommandName,$ParameterName,$WordToComplete,$CommandAst,$FakeBoundParameters) - $PublicClouds = @('https://cloud.community.humio.com/','https://cloud.humio.com/', + $PublicCloud = @('https://cloud.community.humio.com/','https://cloud.humio.com/', 'https://cloud.us.humio.com/') - $Match = $PublicClouds | Where-Object { $_ -like "$WordToComplete*" } + $Match = $PublicCloud | Where-Object { $_ -like "$WordToComplete*" } $Match | ForEach-Object { New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_, $_, diff --git a/public/psf-output.ps1 b/public/psf-output.ps1 index 8936c523..261cec98 100644 --- a/public/psf-output.ps1 +++ b/public/psf-output.ps1 @@ -266,7 +266,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Show-FalconMap } end { if ($List) { - [string[]]$IocInput = @($List | Select-Object -Unique) -join ',' + [string[]]$IocInput = @($List) -join ',' if (!$IocInput) { throw "No valid indicators found." } [string]$Target = "$($FalconUI)/intelligence/graph?indicators=$($IocInput -join ',')" if ($PSCmdlet.ShouldProcess($Target)) { Start-Process $Target } @@ -295,7 +295,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Show-FalconModule ModulePath = Split-Path $ManifestPath -Parent UserModulePath = $env:PSModulePath UserHome = $HOME - UserAgent = 'crowdstrike-psfalcon',$ModuleData.ModuleVersion -join '/' + UserAgent = $Script:Falcon.Api.UserAgent } } else { throw "Unable to locate '$ManifestPath'." diff --git a/public/psf-policies.ps1 b/public/psf-policies.ps1 index 3569cb8c..035564da 100644 --- a/public/psf-policies.ps1 +++ b/public/psf-policies.ps1 @@ -1,106 +1,3 @@ -function Compare-FalconPreventionPhase { -<# -.SYNOPSIS -Compare a Falcon Prevention Policy against recommended implementation phases -.DESCRIPTION -Requires 'Prevention Policies: Read'. -.PARAMETER Id -Policy identifier -.LINK -https://github.com/crowdstrike/psfalcon/wiki/Compare-FalconPreventionPhase -#> - [CmdletBinding(SupportsShouldProcess)] - [OutputType([PSCustomObject[]])] - param( - [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] - [ValidatePattern('^[a-fA-F0-9]{32}$')] - [string]$Id - ) - begin { - # Define allowed OSes and path to json settings - [string[]]$AllowedOS = 'Linux','Mac','Windows' - $List = [System.Collections.Generic.List[string]]@() - } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} - end { - if ($List -and $PSCmdlet.ShouldProcess('Compare-FalconPreventionPhase','Get-FalconPreventionPolicy')) { - # Collect detailed policy information for unique identifiers - $PolicyList = Get-FalconPreventionPolicy -Id ($List | Select-Object -Unique) -EA 0 | Select-Object id, - name,platform_name,prevention_settings | Sort-Object platform_name - @($List).Where({ $PolicyList.id -notcontains $_ }).foreach{ - # Generate error when 'id' values were not found - Write-Error "'$_' was not found." - } - if ($PolicyList) { - [string]$Ineligible = '[Compare-FalconPreventionPolicy] {0} is ineligible. [{1}]' - if ($PolicyList.platform_name) { - # Import json settings for allowed 'platform_name' values - $Compare = @{} - [string]$JsonPath = Join-Path (Show-FalconModule).ModulePath policy - $PolicyList.platform_name | Select-Object -Unique | Where-Object { $AllowedOS -contains $_ } | - ForEach-Object { - [string]$FilePath = (Join-Path $JsonPath "$($_.ToLower()).json") - if (Test-Path $FilePath) { - $JsonValue = try { Get-Content $FilePath | ConvertFrom-Json } catch {} - if ($JsonValue) { - $Compare[$_] = $JsonValue - } else { - Write-Error "Failed to import $_ comparison template." - } - } else { - Write-Error "Failed to locate $_ comparison template. [$FilePath]" - } - } - } - if (!$Compare.Values) { - throw "No comparison templates were successfully imported." - } else { - foreach ($Policy in $PolicyList) { - if ($AllowedOS -notcontains $Policy.platform_name) { - $PSCmdlet.WriteWarning(($Ineligible -f $Policy.id,$Policy.platform_name)) - } elseif (!$Policy.prevention_settings) { - $PSCmdlet.WriteWarning(($Ineligible -f $Policy.id,'Missing prevention_settings')) - } elseif ($Compare.($Policy.platform_name)) { - # Filter to settings for eligible policies - [PSCustomObject[]]$Ref = $Compare.($Policy.platform_name) - foreach ($Category in $Policy.prevention_settings) { - foreach ($Setting in $Category.settings) { - $Output = [PSCustomObject]@{ - policy_id = $Policy.id - policy_name = $Policy.name - platform_name = $Policy.platform_name - category = $Category.name - id = $Setting.id - name = $Setting.name - value = if ($Setting.type -eq 'toggle') { - $Setting.value.enabled - } elseif ($Setting.type -eq 'mlslider') { - $Setting.value.PSObject.Properties.Value -join ':' - } - } - foreach ($Phase in $Compare.($Policy.platform_name).phase) { - # Include id and value for each phase - ($Ref | Where-Object { $_.phase -eq $Phase }).prevention_settings | - Where-Object { $_.id -eq $Setting.id } | ForEach-Object { - $Value = if ($_.type -eq 'toggle') { - $_.value.enabled - } elseif ($_.type -eq 'mlslider') { - $_.value.PSObject.Properties.Value -join ':' - } - Set-Property $Output ('phase',$Phase -join '_') $Value - } - } - Set-Property $Output 'description' $Setting.description - $Output - } - } - } - } - } - } - } - } -} function Copy-FalconDeviceControlPolicy { <# .SYNOPSIS diff --git a/public/psf-real-time-response.ps1 b/public/psf-real-time-response.ps1 index 79972da9..9ed63136 100644 --- a/public/psf-real-time-response.ps1 +++ b/public/psf-real-time-response.ps1 @@ -53,7 +53,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQueue process { if ($HostId) { @($HostId).foreach{ $List.Add($_) }}} end { [string[]]$Filter = if ($List) { - $List = $List | Where-Object { ![string]::IsNullOrEmpty($_) } | Select-Object -Unique + $List = @($List) | Where-Object { ![string]::IsNullOrEmpty($_) } for ($i = 0; $i -lt $List.Count; $i += 17) { # Create individual filter statements for groups of host identifiers [string]$IdList = "($((@($List[$i..($i + 16)]).foreach{ "aid:'$_'" }) -join ','))" @@ -83,9 +83,9 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQueue } } if ($Include -and $HostList) { - @($HostList.Where({ $_.device_id -eq $BaseObj.aid })).foreach{ + @($HostList.Where({$_.device_id -eq $BaseObj.aid})).foreach{ # Append 'Include' properties to base output - @($_.PSObject.Properties.Where({ $_.Name -ne 'device_id' })).foreach{ $BaseObj[$_.Name] = $_.Value } + @($_.PSObject.Properties.Where({$_.Name -ne 'device_id'})).foreach{ $BaseObj[$_.Name] = $_.Value } } } @($Session.commands).foreach{ @@ -321,8 +321,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconDeploy $i = [PSCustomObject]@{ aid = $_.aid; deployment_step = $Step } if ($Include) { # Append 'Include' fields to output - @($HostList).Where({ $_.device_id -eq $i.aid }).foreach{ - @($_.PSObject.Properties).Where({ $Include -contains $_.Name }).foreach{ + @($HostList).Where({$_.device_id -eq $i.aid}).foreach{ + @($_.PSObject.Properties).Where({$Include -contains $_.Name}).foreach{ Set-Property $i $_.Name $_.Value } } @@ -353,7 +353,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconDeploy # Use Host identifiers to also retrieve 'platform_name' and 'Include' fields [string[]]$Select = 'device_id','platform_name' if ($Include) { $Select += ($Include | Where-Object { $_ -ne 'platform_name' })} - @($List | Select-Object -Unique | Get-FalconHost | Select-Object $Select).foreach{ $HostList.Add($_) } + @($List | Get-FalconHost | Select-Object $Select).foreach{ $HostList.Add($_) } } if ($HostList) { # Check for existing 'CloudFile' and upload 'LocalFile' if chosen @@ -384,7 +384,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconDeploy 'Mac' }).device_id Linux = ($HostList | Where-Object { $SessionIds -contains $_.device_id -and $_.platform_name -eq 'Linux' }).device_id - }).GetEnumerator().Where({ $_.Value })) { + }).GetEnumerator().Where({$_.Value})) { # Define target temporary folder [string]$TempDir = switch ($Pair.Key) { 'Windows' { "\Windows\Temp\$DeployName" } @@ -475,6 +475,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconDeploy Write-Host "[Invoke-FalconDeploy] Issuing '$Cmd' to $(($Param.OptionalHostId | Measure-Object).Count) $($Pair.Key) host(s)..." [string]$Step = if ($Cmd -eq 'runscript') { 'extract' } else { $Cmd } + # Add delay when queueing to ensure commands are processed in correct order + if ($QueueOffline -eq $true) { Start-Sleep -Seconds 1 } [string[]]$Optional = Write-RtrResult (Invoke-FalconAdminCommand @Param) $Step $Session.batch_id } } @@ -557,13 +559,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconRtr end { if ($List) { # Gather list of unique host identifiers and append 'GroupId' when present - [object[]]$HostList = @($List | Select-Object -Unique).foreach{ [PSCustomObject]@{ aid = $_ }} + [object[]]$HostList = @($List).foreach{ [PSCustomObject]@{ aid = $_ }} if ($GroupId) { @($HostList).foreach{ Set-Property $_ 'group_id' $GroupId }} if ($Include) { foreach ($i in (Get-FalconHost -Id $HostList.aid | Select-Object @($Include + 'device_id'))) { - foreach ($p in @($i.PSObject.Properties.Where({ $_.Name -ne 'device_id' }))) { + foreach ($p in @($i.PSObject.Properties.Where({$_.Name -ne 'device_id'}))) { # Append 'Include' fields to output - @($HostList).Where({ $_.aid -eq $i.device_id }).foreach{ Set-Property $_ $p.Name $p.Value } + @($HostList).Where({$_.aid -eq $i.device_id}).foreach{ Set-Property $_ $p.Name $p.Value } } } } @@ -586,11 +588,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconRtr $Init = @{ Id = $Output.aid; Timeout = 30; QueueOffline = $QueueOffline } $InitReq = Start-FalconSession @Init if ($InitReq -and ($InitReq.batch_id -or $InitReq.session_id)) { - $JobId = Start-RtrUpdate $InitReq $Timeout + $JobId = Start-RtrUpdate $InitReq 20 # Output verbose message with batch_id or session_id [string[]]$Message = if ($InitReq.batch_id) { - 'batch_id:',$InitReq.batch_id,"[$(@($InitReq.hosts).Where({ $_.complete -eq $true -or - $_.offline_queued -eq $true }).Count) host(s)]" + 'batch_id:',$InitReq.batch_id,"[$(@($InitReq.hosts).Where({$_.complete -eq $true -or + $_.offline_queued -eq $true}).Count) host(s)]" } else { 'session_id:',$InitReq.session_id } diff --git a/public/psf-sensors.ps1 b/public/psf-sensors.ps1 index 10504c6e..85fc6501 100644 --- a/public/psf-sensors.ps1 +++ b/public/psf-sensors.ps1 @@ -1,13 +1,147 @@ +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 FalconSensorTags to hosts +Use Real-time Response to add SensorGroupingTags to a host .DESCRIPTION -Provided FalconSensorTag values will be appended to any existing tags. +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' and 'Real time response (admin): Write'. +Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and +'Real time response (admin): Write'. .PARAMETER Tag -FalconSensorTag value ['FalconSensorTags/'] +SensorGroupingTag value ['SensorGroupingTags/'] .PARAMETER QueueOffline Add command request to the offline queue .PARAMETER Id @@ -33,92 +167,16 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconSensorTag [boolean]$QueueOffline, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','host_ids','aid')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) - begin { - [string]$ScriptPath = Join-Path (Show-FalconModule).ModulePath 'script' - [System.Collections.Generic.List[string]]$List = @() - } + begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - [string[]]$Id = @($List | Select-Object -Unique) - [string[]]$Tag = $Tag -replace 'SensorGroupingTags/',$null - [string]$UserAgent = (Show-FalconModule).UserAgent - try { - # Get device info to determine script and begin session - $HostList = Get-FalconHost -Id $Id | Select-Object cid,device_id,platform_name,device_policies,tags - foreach ($Platform in (($HostList.platform_name | Group-Object).Name | Where-Object { @('Linux','Mac', - 'Windows') -contains $_ })) { - # Start sessions for each 'platform' type - if ($Platform -eq 'Windows') { - foreach ($i in ($HostList | Where-Object { $_.platform_name -eq $Platform })) { - # Check 'tags' for existing values - [boolean]$TagMatch = $false - [string[]]$Existing = ($i.tags | Where-Object { $_ -match 'SensorGroupingTags/' }) -replace - 'SensorGroupingTags/',$null - @($Tag).foreach{ if ($TagMatch -eq $false -and $Existing -notcontains $_) { $TagMatch = $true } } - if ($TagMatch -eq $true) { - [string]$Script = Get-Content (Join-Path $ScriptPath 'add_sensortag.ps1') -Raw - [string]$TagString = (@($Existing + $Tag) | Select-Object -Unique) -join ',' - [string]$CmdLine = if ($i.device_policies.sensor_update.uninstall_protection -eq 'ENABLED') { - '-Tag',$TagString,'-Token',($i.device_id | Get-FalconUninstallToken -AuditMessage ( - 'Add-FalconSensorTag',"[$UserAgent]" -join ' ')).uninstall_token -join ' ' - } else { - '-Tag',$TagString -join ' ' - } - $Param = @{ - Command = 'runscript' - Argument = '-Raw=```{0}``` -CommandLine=```{1}```' -f $Script,$CmdLine - HostId = $i.device_id - QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } - } - Invoke-FalconRtr @Param | Select-Object aid,stdout,stderr,errors | ForEach-Object { - # Output device properties and 'tags' value after script - [PSCustomObject]@{ - cid = $i.cid - device_id = $_.aid - tags = if ($_.stdout) { - $Result = ($_.stdout).Trim() - if ($Result -match 'Maintenance Token>') { $TagString } else { $Result } - } elseif ($_.stderr) { - $_.stderr - } else { - $_.errors - } - } - } - } else { - # Output device properties and 'tags' value when no changes required - [PSCustomObject]@{ - cid = $i.cid - device_id = $i.device_id - tags = $Existing -join ',' - } - } - } - } else { - [string]$Filename = if ($Platform -eq 'Linux') { 'add_sensortag.sh' } else { 'add_sensortag.zsh' } - [string]$Script = Get-Content (Join-Path $ScriptPath $Filename) -Raw - $Param = @{ - Command = 'runscript' - Argument = '-Raw=```{0}``` -CommandLine=```{1}```' -f $Script,($Tag -join ',') - HostId = ($HostList | Where-Object { $_.platform_name -eq $Platform }).device_id - QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } - } - Invoke-FalconRtr @Param | Select-Object aid,stdout,stderr,errors | ForEach-Object { - # Output device properties and 'tags' value - [PSCustomObject]@{ - cid = ($HostList | Where-Object device_id -eq $_.aid).cid - device_id = $_.aid - tags = if ($_.stdout) { ($_.stdout).Trim() } elseif ($_.stderr) { $_.stderr } else { $_.errors } - } - } - } - } - } catch { - throw $_ + foreach ($i in @(Get-FalconHost -Id $List | Select-Object cid,device_id,platform_name,device_policies, + tags)) { + Invoke-TagScript $i 'Add' $QueueOffline $Tag } } } @@ -126,11 +184,11 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconSensorTag function Get-FalconSensorTag { <# .SYNOPSIS -Use Real-time Response to display FalconSensorTags assigned to hosts +Display SensorGroupingTags assigned to hosts .DESCRIPTION -Requires 'Hosts: Read' and 'Real time response (admin): Write'. -.PARAMETER QueueOffline -Add command request to the offline queue +Returns 'cid', 'device_id', and any SensorGroupingTags listed under 'tags' within a 'Get-FalconHost' result. + +Requires 'Hosts: Read'. .PARAMETER Id Host identifier .LINK @@ -138,58 +196,22 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] param( - [Parameter(Position=1)] - [boolean]$QueueOffline, - [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] + [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','host_ids','aid')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) - begin { - [string]$ScriptPath = Join-Path (Show-FalconModule).ModulePath 'script' - [System.Collections.Generic.List[string]]$List = @() - } + begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - [string[]]$Id = @($List | Select-Object -Unique) - try { - # Get device info to determine script and begin session - $HostList = Get-FalconHost -Id $Id | Select-Object cid,device_id,platform_name,tags - foreach ($Platform in (($HostList.platform_name | Group-Object).Name | Where-Object { @('Linux','Mac', - 'Windows') -contains $_ })) { - # Start sessions for each 'platform' type - if ($Platform -eq 'Windows') { - foreach ($i in ($HostList | Where-Object { $_.platform_name -eq $Platform })) { - # Use devices API to return tag values - [PSCustomObject]@{ - cid = $i.cid - device_id = $i.device_id - tags = ($i.tags | Where-Object { $_ -match 'SensorGroupingTags/' }) -replace - 'SensorGroupingTags/',$null -join ',' - } - } - } else { - [string]$Filename = if ($Platform -eq 'Linux') { 'get_sensortag.sh' } else { 'get_sensortag.zsh' } - [string]$Script = Get-Content (Join-Path $ScriptPath $Filename) -Raw - $Param = @{ - Command = 'runscript' - Argument = '-Raw=```{0}```' -f $Script - HostId = ($HostList | Where-Object { $_.platform_name -eq $Platform }).device_id - QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } - } - Invoke-FalconRtr @Param | Select-Object aid,stdout,stderr,errors | ForEach-Object { - # Output device properties and 'tags' value - [PSCustomObject]@{ - cid = ($HostList | Where-Object device_id -eq $_.aid).cid - device_id = $_.aid - tags = if ($_.stdout) { ($_.stdout).Trim() } elseif ($_.stderr) { $_.stderr } else { $_.errors } - } - } - } + @(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 ',' } - } catch { - throw $_ } } } @@ -197,13 +219,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSensorTag function Remove-FalconSensorTag { <# .SYNOPSIS -Use Real-time Response to remove FalconSensorTags from hosts +Use Real-time Response to remove SensorGroupingTags from a host .DESCRIPTION -Provided FalconSensorTag values will be removed from existing tags and others will be left unmodified. +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' and 'Real time response (admin): Write'. +Requires 'Hosts: Read', 'Sensor update policies: Write', 'Real time response: Read', and +'Real time response (admin): Write'. .PARAMETER Tag -FalconSensorTag value ['FalconSensorTags/'] +SensorGroupingTag value ['SensorGroupingTags/'] .PARAMETER Id Host identifier .PARAMETER QueueOffline @@ -212,8 +236,9 @@ Add command request to the offline queue https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSensorTag #> [CmdletBinding(SupportsShouldProcess)] + [OutputType([PSCustomObject])] param( - [Parameter(Mandatory,Position=1)] + [Parameter(Position=1)] [ValidateScript({ @($_).foreach{ if ((Test-RegexValue $_) -eq 'tag') { @@ -229,95 +254,68 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSensorTag [boolean]$QueueOffline, [Parameter(Mandatory,ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','host_ids','aid')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id ) - begin { - [string]$ScriptPath = Join-Path (Show-FalconModule).ModulePath 'script' - [System.Collections.Generic.List[string]]$List = @() - } + begin { [System.Collections.Generic.List[string]]$List = @() } process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - [string[]]$Id = @($List | Select-Object -Unique) - [string[]]$Tag = $Tag -replace 'SensorGroupingTags/',$null - [string]$UserAgent = (Show-FalconModule).UserAgent - try { - # Get device info to determine script and begin session - $HostList = Get-FalconHost -Id $Id | Select-Object cid,device_id,platform_name,device_policies,tags - foreach ($Platform in (($HostList.platform_name | Group-Object).Name | Where-Object { @('Linux','Mac', - 'Windows') -contains $_ })) { - # Start sessions for each 'platform' type - if ($Platform -eq 'Windows') { - foreach ($i in ($HostList | Where-Object { $_.platform_name -eq $Platform })) { - [boolean]$TagMatch = $false - [string[]]$Existing = ($i.tags | Where-Object { $_ -match 'SensorGroupingTags/' }) -replace - 'SensorGroupingTags/',$null - @($Tag).foreach{ if ($TagMatch -eq $false -and $Existing -contains $_) { $TagMatch = $true }} - if ($TagMatch -eq $true) { - [string]$Script = Get-Content (Join-Path $ScriptPath 'remove_sensortag.ps1') -Raw - [string]$TagString = (@($Existing + $Tag) | Select-Object -Unique) -join ',' - [string]$CmdLine = if ($i.device_policies.sensor_update.uninstall_protection -eq 'ENABLED') { - '-Tag',$TagString,'-Token',($i.device_id | Get-FalconUninstallToken -AuditMessage ( - 'Remove-FalconSensorTag',"[$UserAgent]" -join ' ')).uninstall_token -join ' ' - } else { - '-Tag',$TagString -join ' ' - } - $Param = @{ - Command = 'runscript' - Argument = '-Raw=```{0}``` -CommandLine=```{1}```' -f $Script,$CmdLine - HostId = $i.device_id - QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } - } - Invoke-FalconRtr @Param | Select-Object aid,stdout,stderr,errors | ForEach-Object { - # Output device properties and 'tags' value after script - [PSCustomObject]@{ - cid = $i.cid - device_id = $_.aid - tags = if ($_.stdout) { - $Result = ($_.stdout).Trim() - if ($Result -eq 'Maintenance Token>') { $TagString } else { $Result } - } elseif ($_.stderr) { - $_.stderr - } else { - $_.errors - } - } - } - } else { - # Output device properties and 'tags' value when no changes required - [PSCustomObject]@{ - cid = $i.cid - device_id = $i.device_id - tags = $Existing -join ',' - } - } - } - } else { - [string]$Filename = if ($Platform -eq 'Linux') { - 'remove_sensortag.sh' - } else { - 'remove_sensortag.zsh' - } - [string]$Script = Get-Content (Join-Path $ScriptPath $Filename) -Raw - $Param = @{ - Command = 'runscript' - Argument = '-Raw=```{0}``` -CommandLine=```{1}```' -f $Script,($Tag -join ',') - HostId = ($HostList | Where-Object { $_.platform_name -eq $Platform }).device_id - QueueOffline = if ($QueueOffline) { $QueueOffline } else { $false } - } - Invoke-FalconRtr @Param | Select-Object aid,stdout,stderr,errors | ForEach-Object { - # Output device properties and 'tags' value - [PSCustomObject]@{ - cid = ($HostList | Where-Object device_id -eq $_.aid).cid - device_id = $_.aid - tags = if ($_.stdout) { ($_.stdout).Trim() } elseif ($_.stderr) { $_.stderr } else { $_.errors } - } - } - } + 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/'] +.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. ['$_']" } - } catch { - throw $_ + } + })] + [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 } } } diff --git a/public/quarantine.ps1 b/public/quarantine.ps1 index fcf9a7de..9e7efc74 100644 --- a/public/quarantine.ps1 +++ b/public/quarantine.ps1 @@ -30,7 +30,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQuarantine [Parameter(ParameterSetName='/quarantine/entities/quarantined-files/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}_[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/quarantine/queries/quarantined-files/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -59,10 +59,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQuarantine $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Invoke-FalconQuarantineAction { @@ -103,17 +107,21 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconQuarantineAction [Parameter(ParameterSetName='/quarantine/entities/quarantined-files/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=3)] [ValidatePattern('^[a-fA-F0-9]{32}_[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName; Max = 500 } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Test-FalconQuarantineAction { diff --git a/public/real-time-response.ps1 b/public/real-time-response.ps1 index 1a221791..ae514917 100644 --- a/public/real-time-response.ps1 +++ b/public/real-time-response.ps1 @@ -25,7 +25,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconAdminCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('cloud_request_id','task_id')] [string]$CloudRequestId ) @@ -61,7 +61,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('cloud_request_id','task_id')] [string]$CloudRequestId ) @@ -91,7 +91,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconGetFile 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('session_id')] [string]$SessionId, [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:get',Position=1)] @@ -99,7 +99,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconGetFile [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_get_cmd_req_id')] [string]$BatchGetCmdReqId ) @@ -152,7 +152,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Confirm-FalconResponderCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('cloud_request_id','task_id')] [string]$CloudRequestId ) @@ -277,10 +277,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconLibraryScript $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconPutFile { @@ -313,7 +317,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconPutFile [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')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/real-time-response/queries/put-files/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -341,7 +345,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconPutFile } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $Param['Max'] = 200 + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -376,7 +381,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScript [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')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/real-time-response/queries/scripts/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -404,7 +409,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScript } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -452,8 +457,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSession 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')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/real-time-response/queries/sessions/v1:get',Position=1)] [Parameter(ParameterSetName='/real-time-response-audit/combined/sessions/v1:get',Position=1)] @@ -489,10 +494,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSession $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Invoke-FalconAdminCommand { @@ -557,12 +566,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconAdminCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_id')] [string]$BatchId, [Parameter(ParameterSetName='/real-time-response/entities/admin-command/v1:post')] @@ -589,12 +598,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconAdminCommand Wait = $PSBoundParameters.Wait } if ($Timeout) { $GetParam['Timeout'] = $PSBoundParameters.Timeout } - if ($List) { $GetParam['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $GetParam['OptionalHostId'] = @($List) } Invoke-FalconBatchGet @GetParam } else { # Verify 'Endpoint' using BatchId/SessionId [string]$Endpoint = if ($PSBoundParameters.BatchId) { - if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['OptionalHostId'] = @($List) } '/real-time-response/combined/batch-admin-command/v1:post' } elseif ($PSBoundParameters.SessionId) { '/real-time-response/entities/admin-command/v1:post' @@ -602,7 +611,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconAdminCommand if ($Endpoint) { if ($PSBoundParameters.HostTimeout) { # Add 's' to denote seconds for 'host_timeout_duration' - $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null + $PSBoundParameters.HostTimeout = [string]::Concat($PSBoundParameters.HostTimeout,'s') } $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) { # Join 'Command' and 'Argument' into 'command_string' @@ -677,7 +686,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconBatchGet [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_id')] [string]$BatchId, [Parameter(ParameterSetName='/real-time-response/combined/batch-get-command/v1:post')] @@ -689,10 +698,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconBatchGet } process { if ($OptionalHostId) { @($OptionalHostId).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['OptionalHostId'] = @($List) } if ($PSBoundParameters.HostTimeout) { # Add 's' to denote seconds for 'host_timeout_duration' - $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null + $PSBoundParameters.HostTimeout = [string]::Concat($PSBoundParameters.HostTimeout,'s') } foreach ($Request in (Invoke-Falcon @Param -UserInput $PSBoundParameters)) { if ($Request.batch_get_cmd_req_id -and $Request.combined.resources) { @@ -705,12 +714,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconBatchGet $_ } } - @($Request.hosts).Where({ $_.errors }).foreach{ + @($Request.hosts).Where({$_.errors}).foreach{ # Write warning for hosts in batch that produced errors $PSCmdlet.WriteWarning(('[Invoke-FalconBatchGet]',($_.errors.code, $_.errors.message -join ': '),('[aid: {0}]' -f $_.aid) -join ' ')) } - @($Request.hosts).Where({ $_.stderr }).foreach{ + @($Request.hosts).Where({$_.stderr}).foreach{ # Write warning for hosts in batch that produced 'stderr' $PSCmdlet.WriteWarning(('[Invoke-FalconBatchGet]',$_.stderr, ('[aid: {0}' -f $_.aid) -join ' ')) @@ -778,12 +787,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_id')] [string]$BatchId, [Parameter(ParameterSetName='/real-time-response/entities/command/v1:post')] @@ -798,7 +807,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconCommand end { # Verify 'Endpoint' using BatchId/SessionId $Endpoint = if ($PSBoundParameters.BatchId) { - if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['OptionalHostId'] = @($List) } '/real-time-response/combined/batch-command/v1:post' } else { '/real-time-response/entities/command/v1:post' @@ -806,7 +815,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconCommand if ($Endpoint) { if ($PSBoundParameters.HostTimeout) { # Add 's' to denote seconds for 'host_timeout_duration' - $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null + $PSBoundParameters.HostTimeout = [string]::Concat($PSBoundParameters.HostTimeout,'s') } $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) { # Join 'Command' and 'Argument' into 'command_string' @@ -898,12 +907,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconResponderCommand [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_id')] [string]$BatchId, [Parameter(ParameterSetName='/real-time-response/entities/active-responder-command/v1:post')] @@ -924,12 +933,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconResponderCommand Wait = $PSBoundParameters.Wait } if ($Timeout) { $GetParam['Timeout'] = $PSBoundParameters.Timeout } - if ($List) { $GetParam['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $GetParam['OptionalHostId'] = @($List) } Invoke-FalconBatchGet @GetParam } else { # Verify 'Endpoint' using BatchId/SessionId $Endpoint = if ($PSBoundParameters.BatchId) { - if ($List) { $PSBoundParameters['OptionalHostId'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['OptionalHostId'] = @($List) } '/real-time-response/combined/batch-active-responder-command/v1:post' } elseif ($PSBoundParameters.SessionId) { '/real-time-response/entities/active-responder-command/v1:post' @@ -937,7 +946,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconResponderCommand if ($Endpoint) { if ($PSBoundParameters.HostTimeout) { # Add 's' to denote seconds for 'host_timeout_duration' - $PSBoundParameters.HostTimeout = $PSBoundParameters.HostTimeout,'s' -join $null + $PSBoundParameters.HostTimeout = [string]::Concat($PSBoundParameters.HostTimeout,'s') } $PSBoundParameters['command_string'] = if ($PSBoundParameters.Argument) { # Join 'Command' and 'Argument' into 'command_string' @@ -998,7 +1007,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconGetFile [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('session_id')] [string]$SessionId, [Parameter(ParameterSetName='/real-time-response/entities/extracted-file-contents/v1:get')] @@ -1049,12 +1058,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconCommand 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('cloud_request_id','task_id')] [string]$CloudRequestId ) @@ -1082,13 +1091,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconGetFile 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[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]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$')] - [Alias('Ids')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -1111,7 +1120,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconPutFile [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')] + [Alias('ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -1133,7 +1142,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconScript [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')] + [Alias('ids')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -1155,7 +1164,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSession 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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('session_id')] [string]$Id ) @@ -1304,7 +1313,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Start-FalconSession [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('existing_batch_id')] [string]$ExistingBatchId, [Parameter(ParameterSetName='/real-time-response/combined/batch-init-session/v1:post',Position=3)] @@ -1333,25 +1342,25 @@ https://github.com/crowdstrike/psfalcon/wiki/Start-FalconSession # 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] + $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.HostTimeout = [string]::Concat($PSBoundParameters.HostTimeout,'s') } - $PSBoundParameters['host_ids'] = @($List | Select-Object -Unique) + $PSBoundParameters['host_ids'] = @($List) '/real-time-response/combined/batch-init-session/v1:post' } @(Invoke-Falcon @Param -Endpoint $Endpoint -UserInput $PSBoundParameters).foreach{ if ($_.batch_id -and $_.resources) { [string]$BatchId = $_.batch_id - @($_.resources.PSObject.Properties.Value).Where({ $_.errors }).foreach{ + @($_.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{ + @($_.resources.PSObject.Properties.Value).Where({$_.session_id}).foreach{ # Append 'batch_id' for hosts with a 'session_id' Set-Property $_ batch_id $BatchId } @@ -1412,7 +1421,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Update-FalconSession [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('batch_id')] [string]$BatchId ) @@ -1426,12 +1435,12 @@ https://github.com/crowdstrike/psfalcon/wiki/Update-FalconSession [string]$Endpoint = if ($PSBoundParameters.HostId) { '/real-time-response/entities/refresh-session/v1:post' } elseif ($PSBoundParameters.BatchId) { - if ($List) { $PSBoundParameters['HostToRemove'] = @($List | Select-Object -Unique) } + if ($List) { $PSBoundParameters['HostToRemove'] = @($List) } '/real-time-response/combined/batch-refresh-session/v1:post' } @(Invoke-Falcon @Param -Endpoint $Endpoint -UserInput $PSBoundParameters).foreach{ if ($Endpoint -eq '/real-time-response/combined/batch-refresh-session/v1:post') { - @($_.PSObject.Properties.Value).Where({ $_.errors }).foreach{ + @($_.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)]") diff --git a/public/recon.ps1 b/public/recon.ps1 index 92671e64..ac74186a 100644 --- a/public/recon.ps1 +++ b/public/recon.ps1 @@ -47,7 +47,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconAction [boolean]$TriggerMatchless, [Parameter(ParameterSetName='/recon/entities/actions/v1:patch',Mandatory,ValueFromPipelineByPropertyName, Position=6)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id ) begin { @@ -63,7 +63,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconAction } end { if ($List) { - $PSBoundParameters['Recipient'] = @($List | Select-Object -Unique) + $PSBoundParameters['Recipient'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -74,8 +74,8 @@ function Edit-FalconReconNotification { Modify a Falcon Intelligence Recon notification .DESCRIPTION Requires 'Monitoring rules (Falcon Intelligence Recon): Write'. -.PARAMETER Array -An array of notifications to modify in a single request +.PARAMETER InputObject +One or more notifications to modify in a single request .PARAMETER Id Notification identifier .PARAMETER Status @@ -91,30 +91,19 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconNotification #> [CmdletBinding(DefaultParameterSetName='/recon/entities/notifications/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconReconNotification' - Endpoint = '/recon/entities/notifications/v1:patch' - Required = @('id','assigned_to_uuid','status') - Pattern = @('id','assigned_to_uuid') - Format = @{ assigned_to_uuid = 'AssignedToUuid' } - } - Confirm-Parameter @Param - } + Confirm-Parameter $_ 'Edit-FalconReconNotification' '/recon/entities/notifications/v1:patch' })] - [Alias('resources')] - [object[]]$Array, + [Alias('Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/recon/entities/notifications/v1:patch',Mandatory,Position=1)] - [ValidatePattern('^\w{76}$')] [string]$Id, [Parameter(ParameterSetName='/recon/entities/notifications/v1:patch',Mandatory,Position=2)] [ValidateSet('new','in-progress','closed-false-positive','closed-true-positive',IgnoreCase=$false)] [string]$Status, [Parameter(ParameterSetName='/recon/entities/notifications/v1:patch',Mandatory,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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('assigned_to_uuid')] [string]$AssignedToUuid, [Parameter(ParameterSetName='/recon/entities/notifications/v1:patch',Position=4)] @@ -124,21 +113,16 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconNotification [string]$IdpSendStatus ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/recon/entities/notifications/v1:patch' - Format = @{ Body = @{ root = @('assigned_to_uuid','id','status','raw_array','idp_send_status','message') }} - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/recon/entities/notifications/v1:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('id','assigned_to_uuid','status','message','idp_send_status').foreach{ - if ($i.$_) { $_ } - } - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.root + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -146,6 +130,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconNotification } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('raw_array') } } for ($i = 0; $i -lt $List.Count; $i += 100) { $PSBoundParameters['raw_array'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -159,8 +145,8 @@ function Edit-FalconReconRule { Modify a Falcon Intelligence Recon monitoring rule .DESCRIPTION Requires 'Monitoring rules (Falcon Intelligence Recon): Write'. -.PARAMETER Array -An array of monitoring rules to modify in a single request +.PARAMETER InputObject +One or more monitoring rules to modify in a single request .PARAMETER Id Monitoring rule identifier .PARAMETER Name @@ -173,31 +159,21 @@ Monitoring rule priority Permission level [public: 'All Intel users', private: 'Recon Admins'] .PARAMETER BreachMonitoring Monitor for breach data +.PARAMETER BreachMonitorOnly +Monitor only for breach data. Must be accompanied by BreachMonitoring: True. .PARAMETER SubstringMatching -Monitor for substring matches +Monitor for substring matches. Only available for the 'Typosquatting' topic. .LINK https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconRule #> [CmdletBinding(DefaultParameterSetName='/recon/entities/rules/v1:patch',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'Edit-FalconReconRule' - Endpoint = '/recon/entities/rules/v1:patch' - Required = @('id','name','filter','priority','permissions') - Content = @('permissions','priority') - Pattern = @('id') - } - Confirm-Parameter @Param - } - })] - [Alias('resources')] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'Edit-FalconReconRule' '/recon/entities/rules/v1:patch' })] + [Alias('Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/recon/entities/rules/v1:patch',Mandatory,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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id, [Parameter(ParameterSetName='/recon/entities/rules/v1:patch',Mandatory,Position=2)] [string]$Name, @@ -215,29 +191,23 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconRule [Alias('breach_monitoring_enabled')] [boolean]$BreachMonitoring, [Parameter(ParameterSetName='/recon/entities/rules/v1:patch',Position=7)] + [Alias('breach_monitor_only')] + [boolean]$BreachMonitorOnly, + [Parameter(ParameterSetName='/recon/entities/rules/v1:patch',Position=8)] [Alias('substring_matching_enabled')] [boolean]$SubstringMatching ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/recon/entities/rules/v1:patch' - Format = @{ - Body = @{ - root = @('permissions','priority','name','id','filter','raw_array','breach_monitoring_enabled', - 'substring_matching_enabled') - } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/recon/entities/rules/v1:patch' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('permissions','priority','name','filter','breach_monitoring_enabled', - 'substring_match_enabled','id').foreach{ if ($null -ne $i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.root + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -245,6 +215,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconReconRule } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('raw_array') } } for ($i = 0; $i -lt $List.Count; $i += 100) { $PSBoundParameters['raw_array'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -283,8 +255,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconAction param( [Parameter(ParameterSetName='/recon/entities/actions/v1:get',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')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/recon/queries/actions/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -309,10 +281,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconAction $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconReconExport { @@ -340,7 +316,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconExport process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -388,8 +364,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconNotification ValueFromPipelineByPropertyName,ValueFromPipeline)] [Parameter(ParameterSetName='/recon/entities/notifications-detailed-translated/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [ValidatePattern('^\w{76}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/recon/queries/notifications/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -423,10 +398,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconNotification $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconReconRecord { @@ -461,7 +440,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconRecord param( [Parameter(ParameterSetName='/recon/entities/notifications-exposed-data-records/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [ValidatePattern('^\w{76}$')] [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/recon/queries/notifications-exposed-data-records/v1:get',Position=1)] @@ -487,10 +465,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconRecord $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconReconRule { @@ -507,6 +489,8 @@ Falcon Query Language expression to limit results Perform a generic substring search across available fields .PARAMETER Sort Property and direction to sort results +.PARAMETER SecondarySort +Secondary property and direction to sort results .PARAMETER Limit Maximum number of results per request .PARAMETER Offset @@ -524,8 +508,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconRule param( [Parameter(ParameterSetName='/recon/entities/rules/v1:get',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')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/recon/queries/rules/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -538,6 +522,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconRule 'last_updated_timestamp|desc',IgnoreCase=$false)] [string]$Sort, [Parameter(ParameterSetName='/recon/queries/rules/v1:get',Position=4)] + [ValidateSet('created_timestamp|asc','created_timestamp|desc','last_updated_timestamp|asc', + 'last_updated_timestamp|desc',IgnoreCase=$false)] + [string]$SecondarySort, + [Parameter(ParameterSetName='/recon/queries/rules/v1:get',Position=5)] [ValidateRange(1,500)] [int32]$Limit, [Parameter(ParameterSetName='/recon/queries/rules/v1:get')] @@ -553,10 +541,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconReconRule $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconReconRulePreview { @@ -672,7 +664,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconAction param( [Parameter(ParameterSetName='/recon/entities/actions/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('rule_id')] [string]$RuleId, [Parameter(ParameterSetName='/recon/entities/actions/v1:post',Mandatory,ValueFromPipelineByPropertyName, @@ -690,16 +682,13 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconAction })] [Alias('Recipients','uid')] [string[]]$Recipient, - [Parameter(ParameterSetName='/recon/entities/actions/v1:post',ValueFromPipelineByPropertyName, - Position=5)] + [Parameter(ParameterSetName='/recon/entities/actions/v1:post',ValueFromPipelineByPropertyName,Position=5)] [ValidateSet('standard','enhanced',IgnoreCase=$false)] [Alias('content_format')] [string]$ContentFormat, - [Parameter(ParameterSetName='/recon/entities/actions/v1:post',ValueFromPipelineByPropertyName, - Position=6)] + [Parameter(ParameterSetName='/recon/entities/actions/v1:post',ValueFromPipelineByPropertyName,Position=6)] [Alias('trigger_matchless')] [boolean]$TriggerMatchless - ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } @@ -708,7 +697,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconAction process { if ($Recipient) { @($Recipient).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Recipient'] = @($List | Select-Object -Unique) + $PSBoundParameters['Recipient'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -719,8 +708,8 @@ function New-FalconReconRule { Create Falcon Intelligence Recon monitoring rules .DESCRIPTION Requires 'Monitoring rules (Falcon Intelligence Recon): Write'. -.PARAMETER Array -An array of monitoring rules to create in a single request +.PARAMETER InputObject +One or more monitoring rules to create in a single request .PARAMETER Name Monitoring rule name .PARAMETER Topic @@ -733,28 +722,21 @@ Monitoring rule priority Permission level [public: 'All Intel users', private: 'Recon Admins'] .PARAMETER BreachMonitoring Monitor for breach data +.PARAMETER BreachMonitorOnly +Monitor only for breach data. Must be accompanied by BreachMonitoring: True. .PARAMETER SubstringMatching -Monitor for substring matches +Monitor for substring matches. Only available for the 'Typosquatting' topic. +.PARAMETER OriginatingTemplateId +Identifier of originating rule template, if based on one .LINK https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconRule #> [CmdletBinding(DefaultParameterSetName='/recon/entities/rules/v1:post',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='array',Mandatory,ValueFromPipeline)] - [ValidateScript({ - foreach ($Object in $_) { - $Param = @{ - Object = $Object - Command = 'New-FalconReconRule' - Endpoint = '/recon/entities/rules/v1:post' - Required = @('name','topic','filter','priority','permissions') - Content = @('permissions','priority','topic') - Format = @{} - } - Confirm-Parameter @Param - } - })] - [object[]]$Array, + [Parameter(ParameterSetName='Pipeline',Mandatory,ValueFromPipeline)] + [ValidateScript({ Confirm-Parameter $_ 'New-FalconReconRule' '/recon/entities/rules/v1:post' })] + [Alias('Array')] + [object[]]$InputObject, [Parameter(ParameterSetName='/recon/entities/rules/v1:post',Mandatory,Position=1)] [string]$Name, [Parameter(ParameterSetName='/recon/entities/rules/v1:post',Mandatory,Position=2)] @@ -775,29 +757,26 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconRule [Alias('breach_monitoring_enabled')] [boolean]$BreachMonitoring, [Parameter(ParameterSetName='/recon/entities/rules/v1:post',Position=7)] + [Alias('breach_monitor_only')] + [boolean]$BreachMonitorOnly, + [Parameter(ParameterSetName='/recon/entities/rules/v1:post',Position=8)] [Alias('substring_matching_enabled')] - [boolean]$SubstringMatching + [boolean]$SubstringMatching, + [Parameter(ParameterSetName='/recon/entities/rules/v1:post',Position=9)] + [Alias('originating_template_id')] + [string]$OriginatingTemplateId ) begin { - $Param = @{ - Command = $MyInvocation.MyCommand.Name - Endpoint = '/recon/entities/rules/v1:post' - Format = @{ - Body = @{ - root = @('filter','permissions','topic','name','breach_monitoring_enabled','substring_matching_enabled', - 'priority','raw_array') - } - } - } + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/recon/entities/rules/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint [System.Collections.Generic.List[object]]$List = @() } process { - if ($Array) { - foreach ($i in $Array) { - # Select allowed fields, when populated - [string[]]$Select = @('permissions','priority','name','filter','topic', - 'breach_monitoring_enabled','substring_match_enabled').foreach{ if ($null -ne $i.$_) { $_ }} - $List.Add(($i | Select-Object $Select)) + if ($InputObject) { + @($InputObject).foreach{ + # Filter to defined properties + $i = [PSCustomObject]$_ | Select-Object $Param.Format.Body.root + $List.Add($i) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -805,6 +784,8 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconReconRule } end { if ($List) { + [void]$PSBoundParameters.Remove('InputObject') + $Param.Format = @{ Body = @{ root = @('raw_array') } } for ($i = 0; $i -lt $List.Count; $i += 100) { $PSBoundParameters['raw_array'] = @($List[$i..($i + 99)]) Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -870,7 +851,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconAction param( [Parameter(ParameterSetName='/recon/entities/actions/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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} @@ -901,7 +882,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconExport process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -921,8 +902,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconNotification param( [Parameter(ParameterSetName='/recon/entities/notifications/v1:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] - [ValidatePattern('^\w{76}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id ) begin { @@ -932,7 +912,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconNotification process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -957,8 +937,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconRule [boolean]$DeleteNotification, [Parameter(ParameterSetName='/recon/entities/rules/v1:delete',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('Ids')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] + [Alias('ids')] [string[]]$Id ) begin { @@ -968,7 +948,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconReconRule process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/reports.ps1 b/public/reports.ps1 index 7a708ee1..8e7cfd7b 100644 --- a/public/reports.ps1 +++ b/public/reports.ps1 @@ -17,7 +17,7 @@ Maximum number of results per request .PARAMETER Offset Position to begin retrieving results .PARAMETER Execution -Retrieve information about scheduled report execution +Retrieve information about scheduled report execution(s) .PARAMETER Detailed Retrieve detailed information .PARAMETER All @@ -34,7 +34,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScheduledReport [Parameter(ParameterSetName='/reports/entities/report-executions/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/reports/queries/scheduled-reports/v1:get',Position=1)] [Parameter(ParameterSetName='/reports/queries/report-executions/v1:get',Position=1)] @@ -87,7 +87,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconScheduledReport } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -149,7 +149,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconScheduledReport [Parameter(ParameterSetName='/reports/entities/report-executions-download/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string]$Id, [Parameter(ParameterSetName='/reports/entities/report-executions-download/v1:get')] [switch]$Force diff --git a/public/samples.ps1 b/public/samples.ps1 index 2ec3462a..fe54625f 100644 --- a/public/samples.ps1 +++ b/public/samples.ps1 @@ -14,7 +14,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSample [Parameter(ParameterSetName='/samples/queries/samples/GET/v1:post',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('sha256s','sha256','Ids')] + [Alias('sha256s','sha256','ids')] [string[]]$Id ) begin { @@ -24,7 +24,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconSample process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -56,7 +56,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconSample [Parameter(ParameterSetName='/samples/entities/samples/v3:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=3)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string]$Id, [Parameter(ParameterSetName='/samples/entities/samples/v3:get')] [switch]$Force @@ -99,7 +99,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconSample [Parameter(ParameterSetName='/samples/entities/samples/v3:delete',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids','sha256')] + [Alias('ids','sha256')] [string]$Id ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} diff --git a/public/scanner.ps1 b/public/scanner.ps1 index bd2193c0..f9157967 100644 --- a/public/scanner.ps1 +++ b/public/scanner.ps1 @@ -28,7 +28,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQuickScan [Parameter(ParameterSetName='/scanner/entities/scans/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/scanner/queries/scans/v1:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -51,10 +51,14 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconQuickScan $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconQuickScanQuota { @@ -101,7 +105,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconQuickScan [Parameter(ParameterSetName='/scanner/entities/scans/v1:post',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('samples','Ids','sha256')] + [Alias('samples','ids','sha256')] [string[]]$Id ) begin { @@ -111,7 +115,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconQuickScan process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/sensors.ps1 b/public/sensors.ps1 index c3653285..dc5f795b 100644 --- a/public/sensors.ps1 +++ b/public/sensors.ps1 @@ -11,7 +11,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCcid #> [CmdletBinding(DefaultParameterSetName='/sensors/queries/installers/ccid/v1:get',SupportsShouldProcess)] param() - process { Invoke-Falcon -Endpoint $PSCmdlet.ParameterSetName } + process { Invoke-Falcon -Command $MyInvocation.MyCommand.Name -Endpoint $PSCmdlet.ParameterSetName } } function Get-FalconInstaller { <# @@ -38,43 +38,47 @@ Display total result count instead of results .LINK https://github.com/crowdstrike/psfalcon/wiki/Get-FalconInstaller #> - [CmdletBinding(DefaultParameterSetName='/sensors/queries/installers/v1:get',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/sensors/queries/installers/v2:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/sensors/entities/installers/v1:get',Mandatory, + [Parameter(ParameterSetName='/sensors/entities/installers/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get',Position=1)] - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get',Position=1)] + [Parameter(ParameterSetName='/sensors/queries/installers/v2:get',Position=1)] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get',Position=1)] [ValidateScript({ Test-FqlStatement $_ })] [string]$Filter, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get',Position=2)] - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get',Position=2)] + [Parameter(ParameterSetName='/sensors/queries/installers/v2:get',Position=2)] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get',Position=2)] [string]$Sort, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get',Position=3)] - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get',Position=3)] + [Parameter(ParameterSetName='/sensors/queries/installers/v2:get',Position=3)] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get',Position=3)] [ValidateRange(1,500)] [int32]$Limit, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get')] - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get')] + [Parameter(ParameterSetName='/sensors/queries/installers/v2:get')] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get')] [int32]$Offset, - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get',Mandatory)] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get',Mandatory)] [switch]$Detailed, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get')] - [Parameter(ParameterSetName='/sensors/combined/installers/v1:get')] + [Parameter(ParameterSetName='/sensors/queries/installers/v2:get')] + [Parameter(ParameterSetName='/sensors/combined/installers/v2:get')] [switch]$All, - [Parameter(ParameterSetName='/sensors/queries/installers/v1:get')] + [Parameter(ParameterSetName='/sensors/queries/installers/v2: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($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconStream { @@ -116,18 +120,18 @@ Overwrite an existing file when present .LINK https://github.com/crowdstrike/psfalcon/wiki/Receive-FalconInstaller #> - [CmdletBinding(DefaultParameterSetName='/sensors/entities/download-installer/v1:get',SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName='/sensors/entities/download-installer/v2:get',SupportsShouldProcess)] param( - [Parameter(ParameterSetName='/sensors/entities/download-installer/v1:get',Mandatory, + [Parameter(ParameterSetName='/sensors/entities/download-installer/v2:get',Mandatory, ValueFromPipelineByPropertyName,Position=1)] [Alias('name')] [string]$Path, - [Parameter(ParameterSetName='/sensors/entities/download-installer/v1:get',Mandatory, + [Parameter(ParameterSetName='/sensors/entities/download-installer/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=2)] [ValidatePattern('^[A-Fa-f0-9]{64}$')] [Alias('sha256')] [string]$Id, - [Parameter(ParameterSetName='/sensors/entities/download-installer/v1:get')] + [Parameter(ParameterSetName='/sensors/entities/download-installer/v2:get')] [switch]$Force ) begin { diff --git a/public/settings.ps1 b/public/settings.ps1 index 14479e24..ab56bf59 100644 --- a/public/settings.ps1 +++ b/public/settings.ps1 @@ -1,7 +1,7 @@ -function Edit-FalconHorizonPolicy { +function Edit-FalconCloudPolicy { <# .SYNOPSIS -Modify a Falcon Horizon policy +Modify a Falcon Cloud Security policy .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER Severity @@ -17,9 +17,10 @@ Account identifier .PARAMETER Id Policy identifier .LINK -https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonPolicy +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconCloudPolicy #> [CmdletBinding(DefaultParameterSetName='/settings/entities/policy/v1:patch',SupportsShouldProcess)] + [Alias('Edit-FalconHorizonPolicy')] param( [Parameter(ParameterSetName='/settings/entities/policy/v1:patch',Mandatory,ValueFromPipelineByPropertyName, Position=1)] @@ -44,10 +45,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonPolicy begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Edit-FalconHorizonSchedule { +function Edit-FalconCloudSchedule { <# .SYNOPSIS -Modify Falcon Horizon scan schedules +Modify Falcon Cloud Security scan schedules .DESCRIPTION Requires 'CSPM registration: Write'. .PARAMETER ScanSchedule @@ -57,9 +58,10 @@ Cloud platform .PARAMETER NextScanTimestamp Next scan timestamp (RFC3339) .LINK -https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonSchedule +https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconCloudSchedule #> [CmdletBinding(DefaultParameterSetName='/settings/scan-schedule/v1:post',SupportsShouldProcess)] + [Alias('Edit-FalconHorizonSchedule')] param( [Parameter(ParameterSetName='/settings/scan-schedule/v1:post',Mandatory,ValueFromPipelineByPropertyName, Position=1)] @@ -79,10 +81,10 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconHorizonSchedule begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} process { Invoke-Falcon @Param -UserInput $PSBoundParameters } } -function Get-FalconHorizonPolicy { +function Get-FalconCloudPolicy { <# .SYNOPSIS -Retrieve detailed information about Falcon Horizon policies +Retrieve detailed information about Falcon Cloud Security policies .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER Id @@ -94,14 +96,15 @@ Cloud service type .PARAMETER CloudPlatform Cloud platform .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonPolicy +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudPolicy #> [CmdletBinding(DefaultParameterSetName='/settings/entities/policy/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonPolicy')] param( [Parameter(ParameterSetName='/settings/entities/policy-details/v2:get',ValueFromPipelineByPropertyName, ValueFromPipeline,Mandatory)] [ValidatePattern('^\d+$')] - [Alias('Ids','policy_id')] + [Alias('ids','policy_id')] [int32[]]$Id, [Parameter(ParameterSetName='/settings/entities/policy/v1:get',Position=1)] [ValidatePattern('^\d+$')] @@ -126,24 +129,29 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonPolicy $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[int32]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } -function Get-FalconHorizonSchedule { +function Get-FalconCloudSchedule { <# .SYNOPSIS -Retrieve detailed information about Falcon Horizon schedules +Retrieve detailed information about Falcon Cloud Security schedules .DESCRIPTION Requires 'CSPM registration: Read'. .PARAMETER CloudPlatform Cloud platform .LINK -https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonSchedule +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconCloudSchedule #> [CmdletBinding(DefaultParameterSetName='/settings/scan-schedule/v1:get',SupportsShouldProcess)] + [Alias('Get-FalconHorizonSchedule')] param( [Parameter(ParameterSetName='/settings/scan-schedule/v1:get',Mandatory,ValueFromPipelineByPropertyName, ValueFromPipeline,Position=1)] @@ -158,7 +166,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconHorizonSchedule process { if ($CloudPlatform) { @($CloudPlatform).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['CloudPlatform'] = @($List | Select-Object -Unique) + $PSBoundParameters['CloudPlatform'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/snapshots.ps1 b/public/snapshots.ps1 new file mode 100644 index 00000000..7824f641 Binary files /dev/null and b/public/snapshots.ps1 differ diff --git a/public/spotlight.ps1 b/public/spotlight.ps1 index 91bd4119..5f19f92a 100644 --- a/public/spotlight.ps1 +++ b/public/spotlight.ps1 @@ -3,7 +3,7 @@ function Get-FalconRemediation { .SYNOPSIS Retrieve detail about remediations specified in a Falcon Spotlight vulnerability .DESCRIPTION -Requires 'Spotlight vulnerabilities: Read'. +Requires 'Vulnerabilities: Read'. .PARAMETER Id Remediation identifier .LINK @@ -13,7 +13,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRemediation param( [Parameter(ParameterSetName='/spotlight/entities/remediations/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] - [Alias('Ids')] + [Alias('ids')] [object[]]$Id ) begin { @@ -38,7 +38,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRemediation } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -48,7 +48,7 @@ function Get-FalconVulnerability { .SYNOPSIS Search for Falcon Spotlight vulnerabilities .DESCRIPTION -Requires 'Spotlight vulnerabilities: Read'. +Requires 'Vulnerabilities: Read'. .PARAMETER Id Vulnerability identifier .PARAMETER Filter @@ -75,7 +75,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconVulnerability [Parameter(ParameterSetName='/spotlight/entities/vulnerabilities/v2:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] [ValidatePattern('^[a-fA-F0-9]{32}_[a-fA-F0-9]{32}$')] - [Alias('Ids')] + [Alias('ids')] [string[]]$Id, [Parameter(ParameterSetName='/spotlight/queries/vulnerabilities/v1:get',Mandatory,Position=1)] [Parameter(ParameterSetName='/spotlight/combined/vulnerabilities/v1:get',Mandatory,Position=1)] @@ -91,7 +91,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconVulnerability [string]$Sort, [Parameter(ParameterSetName='/spotlight/queries/vulnerabilities/v1:get',Position=4)] [Parameter(ParameterSetName='/spotlight/combined/vulnerabilities/v1:get',Position=4)] - [ValidateRange(1,400)] + [ValidateRange(1,5000)] [int32]$Limit, [Parameter(ParameterSetName='/spotlight/queries/vulnerabilities/v1:get')] [Parameter(ParameterSetName='/spotlight/combined/vulnerabilities/v1:get')] @@ -107,11 +107,16 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconVulnerability begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() + if ($Param.Endpoint -match 'queries' -and $PSBoundParameters.Limit -gt 400) { $PSBoundParameters.Limit = 400 } + } + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } function Get-FalconVulnerabilityLogic { @@ -119,7 +124,7 @@ function Get-FalconVulnerabilityLogic { .SYNOPSIS Search for Falcon Spotlight vulnerability evaluation logic .DESCRIPTION -Requires 'Spotlight vulnerabilities: Read'. +Requires 'Vulnerabilities: Read'. .PARAMETER Id Vulnerability logic identifier .PARAMETER Filter @@ -143,7 +148,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconVulnerabilityLogic param( [Parameter(ParameterSetName='/spotlight/entities/evaluation-logic/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline)] - [Alias('Ids','apps')] + [Alias('ids','apps')] [object[]]$Id, [Parameter(ParameterSetName='/spotlight/queries/evaluation-logic/v1:get',Mandatory,Position=1)] [Parameter(ParameterSetName='/spotlight/combined/evaluation-logic/v1:get',Mandatory,Position=1)] @@ -190,7 +195,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconVulnerabilityLogic } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } diff --git a/public/threatgraph.ps1 b/public/threatgraph.ps1 new file mode 100644 index 00000000..c3826f7b Binary files /dev/null and b/public/threatgraph.ps1 differ diff --git a/public/ti.ps1 b/public/ti.ps1 index b4c347e5..d34c2d6c 100644 Binary files a/public/ti.ps1 and b/public/ti.ps1 differ diff --git a/public/user-management.ps1 b/public/user-management.ps1 index 427c9f1f..7cafee66 100644 --- a/public/user-management.ps1 +++ b/public/user-management.ps1 @@ -18,14 +18,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconRole param( [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('uuid','user_uuid')] [string]$UserId, [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',Mandatory, ValueFromPipelineByPropertyName,Position=2)] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',Mandatory,Position=3)] - [Alias('role_ids','Ids')] + [Alias('role_ids','ids')] [string[]]$Id ) begin { @@ -35,7 +36,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Add-FalconRole process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['role_ids'] = @($List | Select-Object -Unique) + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + $PSBoundParameters['role_ids'] = @($List) $PSBoundParameters['uuid'] = $PSBoundParameters.UserId $PSBoundParameters['action'] = 'grant' [void]$PSBoundParameters.Remove('Id') @@ -69,7 +71,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Edit-FalconUser [string]$LastName, [Parameter(ParameterSetName='/user-management/entities/users/v1:patch',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$Id ) @@ -98,6 +100,8 @@ Property and direction to sort results 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 @@ -112,13 +116,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRole [Alias('ids','roles','role_id')] [string[]]$Id, [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get',Mandatory)] - [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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$UserId, [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get',Position=1)] [Parameter(ParameterSetName='/user-management/entities/roles/v1:get',Position=2)] [Parameter(ParameterSetName='/user-management/queries/roles/v1:get')] - [ValidatePattern('^[a-fA-F0-9]{32}$')] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get',Position=2)] [Alias('direct_only')] @@ -132,6 +136,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRole [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get',Position=5)] [ValidateRange(1,500)] [int]$Limit, + [Parameter(ParameterSetName='/user-management/queries/roles/v1:get')] + [switch]$Detailed, [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get')] [string]$Offset, [Parameter(ParameterSetName='/user-management/combined/user-roles/v1:get')] @@ -146,19 +152,21 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconRole process { if ($Id) { @($Id).foreach{ - if ($_ -match '^[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}$') { + if ($_ -match '^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$') { Get-FalconRole -UserId $_ } else { $List.Add($_) } } } else { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } Invoke-Falcon @Param -UserInput $PSBoundParameters } } end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + $PSBoundParameters['Id'] = @($List) Invoke-Falcon @Param -UserInput $PSBoundParameters } } @@ -196,7 +204,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUser param( [Parameter(ParameterSetName='/user-management/entities/users/GET/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids','uuid')] [string[]]$Id, [Parameter(ParameterSetName='/user-management/queries/users/v1:get',Position=1)] @@ -238,7 +246,6 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUser end { if ($Username) { # Re-submit 'Username' values as filtered searches - $Username = @($Username | Select-Object -Unique) for ($i = 0; $i -lt ($Username | Measure-Object).Count; $i += 100) { [string]$Filter = ($Username[$i..($i + 99)] | ForEach-Object { "uid:*'$_'" }) -join ',' if ($Filter) { @@ -249,7 +256,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconUser } } } else { - if ($IdList) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } + if ($IdList) { $PSBoundParameters['Id'] = @($List) } if ($Include) { $Request = Invoke-Falcon @Param -UserInput $PSBoundParameters if ($Request -and !$Request.uuid) { $Request = @($Request).foreach{ ,[PSCustomObject]@{ uuid = $_ }}} @@ -283,7 +290,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconUserAction [Alias('action_name')] [string]$Name, [Parameter(ParameterSetName='/user-management/entities/user-actions/v1:post',Mandatory,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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('ids')] [string[]]$Id ) @@ -298,7 +305,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconUserAction process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['Id'] = @($List | Select-Object -Unique) + $PSBoundParameters['Id'] = @($List) $PSBoundParameters['Action'] = @{ action_name = $PSBoundParameters.Name } [void]$PSBoundParameters.Remove('Name') Invoke-Falcon @Param -UserInput $PSBoundParameters @@ -349,6 +356,7 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconUser [string]$Password, [Parameter(ParameterSetName='/user-management/entities/users/v1:post',ValueFromPipelineByPropertyName, Position=5)] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/user-management/entities/users/v1:post',ValueFromPipelineByPropertyName, Position=6)] @@ -356,7 +364,10 @@ https://github.com/crowdstrike/psfalcon/wiki/New-FalconUser [boolean]$ValidateOnly ) begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} - process { Invoke-Falcon @Param -UserInput $PSBoundParameters } + process { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } function Remove-FalconRole { <# @@ -378,14 +389,15 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconRole param( [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('uuid','user_uuid')] [string]$UserId, [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',Mandatory, ValueFromPipelineByPropertyName,Position=2)] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] [string]$Cid, [Parameter(ParameterSetName='/user-management/entities/user-role-actions/v1:post',Mandatory,Position=3)] - [Alias('role_ids','Ids')] + [Alias('role_ids','ids')] [string[]]$Id ) begin { @@ -395,7 +407,8 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconRole process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} end { if ($List) { - $PSBoundParameters['role_ids'] = @($List | Select-Object -Unique) + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + $PSBoundParameters['role_ids'] = @($List) $PSBoundParameters['uuid'] = $PSBoundParameters.UserId $PSBoundParameters['action'] = 'revoke' [void]$PSBoundParameters.Remove('Id') @@ -419,7 +432,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Remove-FalconUser param( [Parameter(ParameterSetName='/user-management/entities/users/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}$')] + [ValidatePattern('^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$')] [Alias('user_uuid','uuid')] [string]$Id ) diff --git a/public/workflows.ps1 b/public/workflows.ps1 new file mode 100644 index 00000000..d2b3aa48 --- /dev/null +++ b/public/workflows.ps1 @@ -0,0 +1,355 @@ +function Export-FalconWorkflow { +<# +.SYNOPSIS +Export a Falcon Fusion workflow YAML +.DESCRIPTION +Requires 'Workflow: Read'. +.PARAMETER Sanitize +Remove potentially identifiable information before export +.PARAMETER Path +Destination path. If not provided, a file will be created in the local directory using the workflow identifier. +.PARAMETER Id +Workflow identifier +.PARAMETER Force +Overwrite an existing file when present +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Export-FalconWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/workflows/entities/definitions/export/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/definitions/export/v1:get',Position=1)] + [boolean]$Sanitize, + [Parameter(ParameterSetName='/workflows/entities/definitions/export/v1:get',Position=2)] + [ValidatePattern('\.(yaml|yml)$')] + [string]$Path, + [Parameter(ParameterSetName='/workflows/entities/definitions/export/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('execution_id')] + [string]$Id, + [Parameter(ParameterSetName='/workflows/entities/definitions/export/v1:get')] + [switch]$Force + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Headers = @{ Accept = 'application/yaml' } + } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + $Param.Format['Outfile'] = 'path' + } + process { + if (!$PSBoundParameters.Path) { + $PSBoundParameters['Path'] = Join-Path (Get-Location).Path ($PSBoundParameters.Id,'yaml' -join '.') + } + $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 + } else { + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } + } +} +function Get-FalconWorkflow { +<# +.SYNOPSIS +Search for Falcon Fusion workflows +.DESCRIPTION +Requires 'Workflow: Read'. +.PARAMETER Id +Workflow execution 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 Execution +Retrieve information about workflow executions +.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-FalconWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/workflows/combined/definitions/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/execution-results/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('ids','execution_id')] + [string[]]$Id, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get',Position=1)] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get',Position=2)] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get',Position=3)] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get',Position=3)] + [ValidateRange(1,500)] + [int32]$Limit, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get')] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get')] + [string]$Offset, + [Parameter(ParameterSetName='/workflows/entities/execution-results/v1:get',Mandatory)] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get',Mandatory)] + [switch]$Execution, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get')] + [Parameter(ParameterSetName='/workflows/combined/executions/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/workflows/combined/definitions/v1:get')] + [Parameter(ParameterSetName='/workflows/combined/executions/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($_) } } else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } + end { + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters -Max 500 + } + } +} +function Get-FalconWorkflowAction { +<# +.SYNOPSIS +Search for Falcon Fusion workflow actions +.DESCRIPTION +Requires 'Workflow: 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 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-FalconWorkflowAction +#> + [CmdletBinding(DefaultParameterSetName='/workflows/combined/activities/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter, + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get',Position=2)] + [string]$Sort, + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get',Position=3)] + [int32]$Limit, + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get')] + [string]$Offset, + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get')] + [switch]$All, + [Parameter(ParameterSetName='/workflows/combined/activities/v1:get')] + [switch]$Total + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Get-FalconWorkflowInput { +<# +.SYNOPSIS +Retrieve information about Falcon Fusion workflow human inputs +.DESCRIPTION +Requires 'Workflow: Read'. +.PARAMETER Id +Human input identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconWorkflowInput +#> + [CmdletBinding(DefaultParameterSetName='/workflows/entities/human-inputs/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/human-inputs/v1:get',Mandatory, + ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('ids')] + [string[]]$Id + ) + 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) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} +function Get-FalconWorkflowTrigger { +<# +.SYNOPSIS +Search for Falcon Fusion workflow triggers +.DESCRIPTION +Requires 'Workflow: Read'. +.PARAMETER Filter +Falcon Query Language expression to limit results +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Get-FalconWorkflowTrigger +#> + [CmdletBinding(DefaultParameterSetName='/workflows/combined/triggers/v1:get',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/combined/triggers/v1:get',Position=1)] + [ValidateScript({ Test-FqlStatement $_ })] + [string]$Filter + ) + begin { $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName }} + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Import-FalconWorkflow { +<# +.SYNOPSIS +Import a Falcon Fusion workflow YAML +.DESCRIPTION +Requires 'Workflow: Write'. +.PARAMETER Name +Workflow name +.PARAMETER ValidateOnly +Validate workflow without creating it +.PARAMETER Path +Path to Falcon Fusion workflow YAML +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Import-FalconWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/workflows/entities/definitions/import/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/definitions/import/v1:post',Position=1)] + [string]$Name, + [Parameter(ParameterSetName='/workflows/entities/definitions/import/v1:post',Position=2)] + [Alias('validate_only')] + [boolean]$ValidateOnly, + [Parameter(ParameterSetName='/workflows/entities/definitions/import/v1:post',Mandatory, + ValueFromPipelineByPropertyName,Position=3)] + [ValidatePattern('\.(yaml|yml)$')] + [ValidateScript({ + if (Test-Path $_ -PathType Leaf) { + $true + } else { + throw "Cannot find path '$_' because it does not exist or is a directory." + } + })] + [Alias('data_file','FullName')] + [string]$Path + ) + begin { + $Param = @{ + Command = $MyInvocation.MyCommand.Name + Endpoint = $PSCmdlet.ParameterSetName + Headers = @{ ContentType = 'multipart/form-data' } + } + } + process { Invoke-Falcon @Param -UserInput $PSBoundParameters } +} +function Invoke-FalconWorkflow { +<# +.SYNOPSIS +Execute an on-demand Falcon Fusion workflow +.DESCRIPTION +Requires 'Workflow: Write'. +.PARAMETER Cid +Target CID. Child CIDs are supported in Flight Control environments. +.PARAMETER Key +Optional UUID used to help de-duplicate executions +.PARAMETER Depth +Execution depth limit to help prevent execution loops from multiple workflow triggers +.PARAMETER SourceEventUrl +Optional source URL for auditing +.PARAMETER Json +Json string to define workflow trigger key/value pairs +.PARAMETER Name +Workflow name +.PARAMETER Id +Workflow identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Invoke-FalconWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/workflows/entities/execute/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',Position=1)] + [Parameter(ParameterSetName='Name',Position=1)] + [ValidatePattern('^[a-fA-F0-9]{32}(-\w{2})?$')] + [Alias('execution_cid')] + [string[]]$Cid, + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',Position=2)] + [Parameter(ParameterSetName='Name',Position=2)] + [string]$Key, + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',Position=3)] + [Parameter(ParameterSetName='Name',Position=3)] + [ValidateRange(1,4)] + [int32]$Depth, + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',Position=4)] + [Parameter(ParameterSetName='Name',Position=4)] + [Alias('source_event_url')] + [string]$SourceEventUrl, + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',Mandatory)] + [Parameter(ParameterSetName='Name',Mandatory)] + [string]$Json, + [Parameter(ParameterSetName='Name',ValueFromPipelineByPropertyName,Mandatory)] + [string]$Name, + [Parameter(ParameterSetName='/workflows/entities/execute/v1:post',ValueFromPipelineByPropertyName, + ValueFromPipeline,Mandatory)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('definition_id')] + [string[]]$Id + ) + begin { + $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = '/workflows/entities/execute/v1:post' } + $Param['Format'] = Get-EndpointFormat $Param.Endpoint + } + process { + if ($PSBoundParameters.Cid) { $PSBoundParameters.Cid = Confirm-CidValue $PSBoundParameters.Cid } + Invoke-Falcon @Param -UserInput $PSBoundParameters -JsonBody $PSBoundParameters.Json + } +} +function Redo-FalconWorkflow { +<# +.SYNOPSIS +Resume or retry a failed Falcon Fusion workflow execution +.DESCRIPTION +Requires 'Workflow: Write'. +.PARAMETER Id +Workflow identifier +.LINK +https://github.com/crowdstrike/psfalcon/wiki/Redo-FalconWorkflow +#> + [CmdletBinding(DefaultParameterSetName='/workflows/entities/execution-actions/v1:post',SupportsShouldProcess)] + param( + [Parameter(ParameterSetName='/workflows/entities/execution-actions/v1:post',ValueFromPipelineByPropertyName, + ValueFromPipeline,Mandatory)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [Alias('ids')] + [string[]]$Id + ) + 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) { + $PSBoundParameters['action_name'] = 'resume' + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } + } +} \ No newline at end of file diff --git a/public/zero-trust-assessment.ps1 b/public/zero-trust-assessment.ps1 index 27846c6b..8699f4e3 100644 --- a/public/zero-trust-assessment.ps1 +++ b/public/zero-trust-assessment.ps1 @@ -28,7 +28,7 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconZta [Parameter(ParameterSetName='/zero-trust-assessment/entities/assessments/v1:get',Mandatory, ValueFromPipelineByPropertyName,ValueFromPipeline,Position=1)] [ValidatePattern('^[a-fA-F0-9]{32}$')] - [Alias('Ids','device_id','host_ids','aid')] + [Alias('ids','device_id','host_ids','aid')] [string[]]$Id, [Parameter(ParameterSetName='/zero-trust-assessment/queries/assessments/v1:get',Mandatory,Position=1)] [ValidateScript({ Test-FqlStatement $_ })] @@ -52,9 +52,13 @@ https://github.com/crowdstrike/psfalcon/wiki/Get-FalconZta $Param = @{ Command = $MyInvocation.MyCommand.Name; Endpoint = $PSCmdlet.ParameterSetName } [System.Collections.Generic.List[string]]$List = @() } - process { if ($Id) { @($Id).foreach{ $List.Add($_) }}} + process { + if ($Id) { @($Id).foreach{ $List.Add($_) }} else { Invoke-Falcon @Param -UserInput $PSBoundParameters } + } end { - if ($List) { $PSBoundParameters['Id'] = @($List | Select-Object -Unique) } - Invoke-Falcon @Param -UserInput $PSBoundParameters + if ($List) { + $PSBoundParameters['Id'] = @($List) + Invoke-Falcon @Param -UserInput $PSBoundParameters + } } } \ No newline at end of file diff --git a/samples/host_groups/add-a-list-of-hostnames-to-a-host-group.ps1 b/samples/devices/add-a-list-of-hostnames-to-a-host-group.ps1 similarity index 100% rename from samples/host_groups/add-a-list-of-hostnames-to-a-host-group.ps1 rename to samples/devices/add-a-list-of-hostnames-to-a-host-group.ps1 diff --git a/samples/host_groups/create-a-host-group-and-add-a-list-of-devices-by-hostname.ps1 b/samples/devices/create-a-host-group-and-add-a-list-of-devices-by-hostname.ps1 similarity index 100% rename from samples/host_groups/create-a-host-group-and-add-a-list-of-devices-by-hostname.ps1 rename to samples/devices/create-a-host-group-and-add-a-list-of-devices-by-hostname.ps1 diff --git a/samples/hosts/create-sensor-policy-daily-report-csv.ps1 b/samples/devices/create-sensor-policy-daily-report-csv.ps1 similarity index 100% rename from samples/hosts/create-sensor-policy-daily-report-csv.ps1 rename to samples/devices/create-sensor-policy-daily-report-csv.ps1 diff --git a/samples/hosts/find-duplicate-hosts-and-hide-them.ps1 b/samples/devices/find-duplicate-hosts-and-hide-them.ps1 similarity index 100% rename from samples/hosts/find-duplicate-hosts-and-hide-them.ps1 rename to samples/devices/find-duplicate-hosts-and-hide-them.ps1 diff --git a/samples/hosts/hide-hosts-based-on-last_seen-time.ps1 b/samples/devices/hide-hosts-based-on-last_seen-time.ps1 similarity index 100% rename from samples/hosts/hide-hosts-based-on-last_seen-time.ps1 rename to samples/devices/hide-hosts-based-on-last_seen-time.ps1 diff --git a/samples/hosts/network-contain-a-device-by-hostname.ps1 b/samples/devices/network-contain-a-device-by-hostname.ps1 similarity index 100% rename from samples/hosts/network-contain-a-device-by-hostname.ps1 rename to samples/devices/network-contain-a-device-by-hostname.ps1 diff --git a/samples/hosts/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 b/samples/devices/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 similarity index 58% rename from samples/hosts/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 rename to samples/devices/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 index c56a5b7b..e50884e5 100644 --- a/samples/hosts/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 +++ b/samples/devices/network-contain-a-list-of-hostnames-from-a-csv-file.ps1 @@ -2,29 +2,37 @@ using module @{ModuleName='PSFalcon';ModuleVersion ='2.2'} <# .SYNOPSIS -Import a list of devices from CSV and contain them +Import a list of hostnames from CSV and network contain matching devices .PARAMETER Path -Path to the CSV file containing a list of devices +Path to the CSV file containing a list of hostnames .NOTES This example requires a CSV with a column labeled 'hostname'. It will create a new CSV with that includes -'hostname', 'device_id' and 'contain_requested' status. +'hostname', 'device_id' and 'contain_requested' status in the current directory. #> param( [Parameter(Mandatory)] [ValidatePattern('\.csv$')] [string]$Path ) +# Create output file CSV name and import values from CSV [string]$OutputFile = Join-Path (Get-Location).Path "contained_$(Get-Date -Format FileDateTime).csv" $Import = Import-Csv -Path $Path if (!$Import.hostname) { throw "No 'hostname' column found in '$Path'." } -# Use Find-FalconDuplicate to find duplicate hosts and contain them -$Import.hostname | Find-FalconHostname -OutVariable HostList | - Invoke-FalconHostAction -Name contain -OutVariable ContainList +# Search for hosts and capture the most recently seen result that matches the provided hostname +[System.Collections.Generic.List[object]]$HostList = @() +@($Import.hostname).Where({![string]::IsNullOrEmpty($_)}).foreach{ + @(Get-FalconHost -Filter "hostname:['$_']" -Limit 1 -Sort last_seen.desc -Detailed | Select-Object device_id, + hostname).foreach{ + $HostList.Add($_) + } +} if (!$HostList.hostname) { # Error if no matches were found throw "No hosts found." } else { + # Contain devices + $HostList.device_id | Invoke-FalconHostAction -Name contain -OutVariable ContainList @($HostList).foreach{ # Add 'contain_requested' property and export to CSV $Status = if ($ContainList.id -contains $_.device_id) { $true } else { $false } diff --git a/samples/hosts/output-devices-with-their-most-recent-login.ps1 b/samples/devices/output-devices-with-their-most-recent-login.ps1 similarity index 100% rename from samples/hosts/output-devices-with-their-most-recent-login.ps1 rename to samples/devices/output-devices-with-their-most-recent-login.ps1 diff --git a/samples/hosts/output-selected-host-info-and-replace-ids-with-names.ps1 b/samples/devices/output-selected-host-info-and-replace-ids-with-names.ps1 similarity index 93% rename from samples/hosts/output-selected-host-info-and-replace-ids-with-names.ps1 rename to samples/devices/output-selected-host-info-and-replace-ids-with-names.ps1 index f91df23f..b6fe89ac 100644 --- a/samples/hosts/output-selected-host-info-and-replace-ids-with-names.ps1 +++ b/samples/devices/output-selected-host-info-and-replace-ids-with-names.ps1 @@ -3,16 +3,25 @@ using module @{ModuleName='PSFalcon';ModuleVersion ='2.2'} <# .SYNOPSIS Output host information, but replace identifiers with their relevant 'name' value +.PARAMETER Hostname +Export a specific device by hostname .NOTES Fields in the output can be defined by updating the '$Field' variable. Output is returned to the console, but can be piped to a file. #> +param( + [string]$Hostname +) # Fields to include with the export to CSV (host group and policy data is automatically added) [string[]]$Field = 'device_id','hostname','last_seen','first_seen','local_ip','external_ip','agent_version' $Field += 'device_policies','groups' # Retrieve all host information and filter to selected fields -$HostInfo = Get-FalconHost -Detailed -All | Select-Object $Field +$HostInfo = if ($Hostname) { + Get-FalconHost -Filter "hostname:'$Hostname'" -Detailed | Select-Object $Field +} else { + Get-FalconHost -Detailed -All | Select-Object $Field +} if ($HostInfo) { # Create hashtable to store object detail for hosts $Related = @{ diff --git a/samples/host_groups/verify-that-a-list-of-host-groups-exist-within-child-cids.ps1 b/samples/devices/verify-that-a-list-of-host-groups-exist-within-child-cids.ps1 similarity index 100% rename from samples/host_groups/verify-that-a-list-of-host-groups-exist-within-child-cids.ps1 rename to samples/devices/verify-that-a-list-of-host-groups-exist-within-child-cids.ps1 diff --git a/samples/discover/retrieve_hosts_and_their_applications.ps1 b/samples/discover/retrieve_hosts_and_their_applications.ps1 new file mode 100644 index 00000000..5130165c --- /dev/null +++ b/samples/discover/retrieve_hosts_and_their_applications.ps1 @@ -0,0 +1,78 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion='2.2'} +<# +.SYNOPSIS +Retrieve all hosts with Falcon installed, append their installed applications, then output to Json +.DESCRIPTION +Requires "Hosts: Read" and "Falcon Discover: Read" +.PARAMETER ClientId +OAuth2 client identifier +.PARAMETER ClientSecret +OAuth2 client secret +.PARAMETER Hostname +CrowdStrike API hostname +#> +[CmdletBinding()] +param( + [Parameter(Mandatory,ValueFromPipelineByPropertyName,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$ClientId, + [Parameter(Mandatory,ValueFromPipelineByPropertyName,Position=2)] + [ValidatePattern('^\w{40}$')] + [string]$ClientSecret, + [Parameter(ValueFromPipelineByPropertyName,Position=3)] + [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', + 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + [string]$Hostname +) +begin { + function Add-AppList ([object[]]$HostObj,[object[]]$AppObj) { + foreach ($Member in $HostObj) { + # Append installed applications to final host output + $Member.PSObject.Properties.Add((New-Object PSNoteProperty('applications',(@($AppObj).Where({ + $_.host.aid -eq $Member.device_id }))))) + Write-Host "Matched $(($Member.applications.id | Measure-Object).Count) applications to host $( + $Member.device_id)." + $Member + } + } + # Request authorization token + $Token = @{} + @('ClientId','ClientSecret','Hostname').foreach{ + if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ } + } + Request-FalconToken @Token + [string]$Json = "hosts_and_applications_$(Get-Date -Format FileDateTime).json" +} +process { + # Retrieve all hosts and their details + Write-Host "Start $(Get-Date -Format o)" + $HostList = Get-FalconHost -Detailed -All + $HostTotal = ($HostList.device_id | Measure-Object).Count + Write-Host "Retrieved $HostTotal host results." + $Output = for ($i=0; $i -lt $HostTotal; $i+=100) { + # Check total count of applications using group of 100 ids + [object[]]$Group = @($HostList)[$i..($i+99)] + [string]$Filter = "host.aid:[$((@($Group).foreach{ "'$($_.device_id)'" }) -join ',')]" + [int32]$AppTotal = Get-FalconAsset -Filter $Filter -Application -Total + if ($AppTotal -lt 10000) { + # Request all 100 hosts if total application results are less than 10,000 + Write-Host "[$i of $HostTotal] Requesting $AppTotal apps for hosts $($Group[0].device_id) to $( + $Group[-1].device_id)..." + Add-AppList $Group (Get-FalconAsset -Filter $Filter -Application -Detailed -All) + } else { + for ($i2=0; $i2 -lt ($Group.device_id | Measure-Object).Count; $i2+=20) { + # Break group of 100 into groups of 20 to stay under 10,000 results + [object[]]$SubGroup = @($Group)[$i2..($i2+19)] + [string]$SubFilter = "host.aid:[$((@($SubGroup).foreach{ "'$($_.device_id)'" }) -join ',')]" + [int32]$SubTotal = Get-FalconAsset -Filter $SubFilter -Application -Total + Write-Host "[$($i + $i2) of $HostTotal] Requesting $SubTotal apps for hosts $( + $SubGroup[0].device_id) to $($SubGroup[-1].device_id)..." + Add-AppList $SubGroup (Get-FalconAsset -Filter $SubFilter -Application -Detailed -All) + } + } + } + $Output | ConvertTo-Json -Depth 32 > $Json + Write-Host "End $(Get-Date -Format o)" +} +end { if (Test-Path $Json) { Get-ChildItem $Json | Select-Object FullName,Length,LastWriteTime }} \ No newline at end of file diff --git a/samples/firewall_management/firewall_rule_summaries.ps1 b/samples/fwmgr/firewall_rule_summaries.ps1 similarity index 100% rename from samples/firewall_management/firewall_rule_summaries.ps1 rename to samples/fwmgr/firewall_rule_summaries.ps1 diff --git a/samples/threat_intelligence/export-domain-and-ip-indicators-updated-within-the-last-week-to-csv.ps1 b/samples/intel/export-domain-and-ip-indicators-updated-within-the-last-week-to-csv.ps1 similarity index 100% rename from samples/threat_intelligence/export-domain-and-ip-indicators-updated-within-the-last-week-to-csv.ps1 rename to samples/intel/export-domain-and-ip-indicators-updated-within-the-last-week-to-csv.ps1 diff --git a/samples/ioarules/create_group_of_custom_ioa_rules_from_list_of_ipv4_addresses.ps1 b/samples/ioarules/create_group_of_custom_ioa_rules_from_list_of_ipv4_addresses.ps1 new file mode 100644 index 00000000..7930c51d --- /dev/null +++ b/samples/ioarules/create_group_of_custom_ioa_rules_from_list_of_ipv4_addresses.ps1 @@ -0,0 +1,217 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion='2.2'} +<# +.SYNOPSIS +Create a custom IOA rule group with 'network_connection' rules using a list of IPv4 addresses within a text file +.DESCRIPTION +IPv4 addresses will be converted into RegEx and condensed into a single rule when 2 or more octets match + +Requires 'Custom IOA rules: Write'. +.PARAMETER ClientId +OAuth2 client identifier +.PARAMETER ClientSecret +OAuth2 client secret +.PARAMETER MemberCid +Member CID, used when authenticating within a multi-CID environment ('Falcon Flight Control') +.PARAMETER Cloud +CrowdStrike cloud [default: 'us-1'] +.PARAMETER Path +Path to text file containing IPv4 addresses +.PARAMETER Platform +Operating system platform +.PARAMETER GroupName +Rule group name +.PARAMETER Severity +Rule severity +.PARAMETER DispositionId +Disposition identifier [10: Monitor, 20: Detect, 30: Block] +#> +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('eu-1','us-gov-1','us-1','us-2')] + [string]$Cloud, + [Parameter(Mandatory,Position=5)] + [ValidatePattern('\.txt$')] + [ValidateScript({ + if (Test-Path -Path $_ -PathType Leaf) { + $true + } else { + throw "Cannot find path '$_' because it does not exist or is a directory." + } + })] + [string]$Path, + [Parameter(Mandatory,Position=6)] + [ValidateSet('windows','mac','linux',IgnoreCase=$false)] + [string]$Platform, + [Parameter(Mandatory,Position=7)] + [string]$GroupName, + [Parameter(Mandatory,Position=8)] + [ValidateSet('critical','high','medium','low','informational',IgnoreCase=$false)] + [string]$Severity, + [Parameter(Mandatory,Position=9)] + [ValidateSet(10,20,30)] + [int32]$DispositionId +) +begin { + function Add-EscapeCharacter ([string[]]$String) { + # Escape periods in a string for RegEx + $String -replace '\.','\.' + } + function Join-ByPrefix { + param( + [hashtable]$Hashtable, + [PSCustomObject]$Object, + [string]$Key, + [string]$SubKey, + [string]$Value + ) + # Add IPv4 with matching octets to hashtable using matched octets as a prefix + if (!$Hashtable.$Key.$SubKey) { $Hashtable.$Key[$SubKey] = [System.Collections.Generic.List[string]]@() } + $Hashtable.$Key.$SubKey.Add(($Value -replace "$SubKey\.",$null)) + } + function Submit-IoaRule { + param( + [string]$String, + [int32]$DispositionId, + [string]$Severity, + [string]$GroupId + ) + # Create a Custom IOA rule from the provided IPv4 address/range + $Action = switch ($DispositionId) { + 10 { 'Monitor' } + 20 { 'Detect' } + 30 { 'Block' } + } + $Param = @{ + Name = ($Action,$String -join ' ') + Description = (Show-FalconModule).UserAgent + PatternSeverity = $Severity + RuleTypeId = 9 + RuleGroupId = $GroupId + DispositionId = $DispositionId + FieldValue = @( + [PSCustomObject]@{ + name = 'RemoteIPAddress' + label = 'Remote IP Address' + type = 'excludable' + values = @(@{ label = 'include'; value = (Add-EscapeCharacter $String) }) + }, + [PSCustomObject]@{ + name = 'RemotePort' + label = 'Remote TCP/UDP Port' + type = 'excludable' + values = @(@{ label = 'include'; value = '.*' }) + }, + [PSCustomObject]@{ + name = 'ConnectionType' + label = 'Connection Type' + type = 'set' + values = @() + } + ) + } + $Req = New-FalconIoaRule @Param + if ($Req) { + Write-Host "Created '$($Req.name)'." + $Req + } + } + $Token = @{} + @('ClientId','ClientSecret','Cloud','MemberCid').foreach{ + if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ } + } +} +process { + # Import IP addresses from text file + $Import = try { Get-Content $Path } catch { throw $_ } + [PSCustomObject[]]$OctetList = @($Import).foreach{ + if ($_ -match '((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])') { + # Split valid IPv4 addresses into objects containing individual octets + $i = ($_).Split('.',4) + [PSCustomObject]@{octet1=$i[0];octet2=$i[1];octet3=$i[2];octet4=$i[3]} + } else { + Write-Error "'$_' is not a valid IPv4 address." + } + } + if (!$OctetList) { throw "No valid IPv4 addresses found."} + # Create hashtable to contain RegEx pattern content and group addresses when they share the first 2 or 3 octets + $IoaList = @{ Match3 = @{}; Match2 = @{}; Match1 = [System.Collections.Generic.List[string]]@() } + [PSCustomObject[]]$Match3 = @($OctetList | Group-Object -Property octet1,octet2,octet3).Where({ + $_.Count -gt 1}).Group + [PSCustomObject[]]$Match2 = @($OctetList | Group-Object -Property octet1,octet2).Where({$_.Count -gt 1}).Group + foreach ($i in $OctetList) { + $IPv4 = $i.PSObject.Properties.Value -join '.' + if (@($Match3).Where({$_.octet1 -eq $i.octet1 -and $_.octet2 -eq $i.octet2 -and $_.octet3 -eq $i.octet3})) { + # Capture IPv4 addresses that share the first 3 octets + Join-ByPrefix $IoaList $i Match3 ($i.octet1,$i.octet2,$i.octet3 -join '.') $IPv4 + } elseif (@($Match2).Where({$_.octet1 -eq $i.octet1 -and $_.octet2 -eq $i.octet2})) { + # Capture IPv4 addresses that share the first 2 octets + Join-ByPrefix $IoaList $i Match2 ($i.octet1,$i.octet2 -join '.') $IPv4 + } else { + # Capture unique IPv4 addresses + $IoaList.Match1.Add($IPv4) + } + } + try { + # Authenticate with CID + Request-FalconToken @Token + if ((Test-FalconToken).Token -eq $true) { + # Create IOA rule group + $Group = try { New-FalconIoaGroup -Name $GroupName -Platform $Platform } catch { throw $_ } + if ($Group.id) { + $Group.rules = [System.Collections.Generic.List[object]]@() + foreach ($Key in ('Match3','Match2')) { + if ($IoaList.$Key.Keys) { + # Create rules for IPv4 addresses with 3 and 2 shared octets + @($IoaList.$Key.Keys | Sort-Object).foreach{ + $Req = Submit-IoaRule ($_, + "($($IoaList.$Key.$_ -join '|'))" -join '.') $DispositionId $Severity $Group.id + if ($Req) { + # Enable rule and add to list for later modification + $Req.enabled = $true + $Group.rules.Add($Req) + } + } + } + } + if ($IoaList.Match1) { + # Create rules for unique IPv4 addresses + @($IoaList.Match1 | Sort-Object).foreach{ + $Req = Submit-IoaRule $_ $DispositionId $Severity $Group.id + if ($Req) { + # Enable rule and add to list for later modification + $Req.enabled = $true + $Group.rules.Add($Req) + } + } + } + } + + if ($Group.rules) { + # Enable IOA rules and rule group + if ($Group.enabled -eq $false) { $Group.enabled = $true } + @($Group | Edit-FalconIoaRule).foreach{ + @($_.rules).Where({$_.enabled -eq $true}).foreach{ Write-Host "Enabled IOA rule '$($_.name)'." } + } + $Enable = $Group | Edit-FalconIoaGroup + if ($Enable -and $Enable.enabled -eq $true) { + Write-Host "Enabled $($Enable.platform) IOA group '$($Enable.name)'." + } + } + } + } catch { + Write-Error $_ + } finally { + # Remove authentication token + if ((Test-FalconToken).Token -eq $true) { [void](Revoke-FalconToken) } + } +} \ No newline at end of file diff --git a/samples/ioarules/get-all-ioa-exclusions-multi-output.ps1 b/samples/ioarules/get-all-ioa-exclusions-multi-output.ps1 new file mode 100644 index 00000000..8cb93aa3 --- /dev/null +++ b/samples/ioarules/get-all-ioa-exclusions-multi-output.ps1 @@ -0,0 +1,139 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion ='2.2'} + +<# +.SYNOPSIS +Retrieve and report exclusions configured in CrowdStrike Falcon. +.DESCRIPTION +This script retrieves the ML exclusions, IOA exclusions, and Sensor Visibility exclusions configured in CrowdStrike Falcon and outputs the results. +.PARAMETER ClientId +OAuth2 client identifier. +.PARAMETER ClientSecret +OAuth2 client secret. +.PARAMETER Cloud +CrowdStrike cloud [default: 'us-1']. +.PARAMETER Hostname +CrowdStrike API hostname. +.PARAMETER OutputFormat +Specifies the format of the output. Allowed values are 'CSV', 'Text', and 'JSON'. +.NOTES +Ensure you have the necessary permissions to access this information and the PSFalcon module installed. +#> + +param( + [Parameter(Mandatory=$true)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$ClientId, + + [Parameter(Mandatory=$true)] + [ValidatePattern('^\w{40}$')] + [string]$ClientSecret, + + [Parameter(Mandatory=$true)] + [ValidateSet('CSV', 'Text', 'JSON')] + [string]$OutputFormat, + + [Parameter(ValueFromPipelineByPropertyName, Position=3)] + [ValidateSet('eu-1','us-gov-1','us-1','us-2')] + [string]$Cloud = 'us-1', + + [Parameter(ValueFromPipelineByPropertyName, Position=4)] + [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', + 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + [string]$Hostname +) + +# Define the fields to be included in the output for each exclusion type +[string[]]$MlFields = 'id', 'value', 'regexp_value', 'value_hash', 'excluded_from', 'groups', 'applied_globally', 'last_modified', 'modified_by', 'created_on', 'created_by' +[string[]]$IoaFields = 'id', 'name', 'description', 'pattern_id', 'pattern_name', 'ifn_regex', 'cl_regex', 'detection_json', 'groups', 'applied_globally', 'last_modified', 'modified_by', 'created_on', 'created_by' +[string[]]$SvFields = 'id', 'value', 'regexp_value', 'value_hash', 'groups', 'applied_globally', 'last_modified', 'modified_by', 'created_on', 'created_by' + +# Request the Falcon token using the provided ClientId and ClientSecret +$Token = @{ + ClientId = $ClientId + ClientSecret = $ClientSecret +} + +if ($PSBoundParameters.ContainsKey('Cloud')) { + $Token.Cloud = $Cloud +} + +if ($PSBoundParameters.ContainsKey('Hostname')) { + $Token.Hostname = $Hostname +} + +Write-Output "Requesting Falcon token..." +Request-FalconToken @Token + +# Validate the token +if ((Test-FalconToken).token -ne $true) { + Write-Error "Failed to retrieve a valid Falcon token. Exiting script." + exit +} + +# Retrieve ML exclusions +Write-Output "Retrieving ML exclusions..." +$RawMlExclusions = Get-FalconMlExclusion -Detailed +Write-Output "Raw ML Exclusions:" +$RawMlExclusions | Format-List + +$MlExclusions = $RawMlExclusions | Select-Object $MlFields +if ($MlExclusions -and $MlExclusions.Count -gt 0) { + Write-Output "ML Exclusions:" + $MlExclusions | Format-Table -AutoSize +} else { + Write-Output "No ML exclusions found or failed to retrieve exclusions." +} + +# Retrieve IOA exclusions +Write-Output "Retrieving IOA exclusions..." +$RawIoaExclusions = Get-FalconIoaExclusion -Detailed +Write-Output "Raw IOA Exclusions:" +$RawIoaExclusions | Format-List + +$IoaExclusions = $RawIoaExclusions | Select-Object $IoaFields +if ($IoaExclusions -and $IoaExclusions.Count -gt 0) { + Write-Output "IOA Exclusions:" + $IoaExclusions | Format-Table -AutoSize +} else { + Write-Output "No IOA exclusions found or failed to retrieve exclusions." +} + +# Retrieve Sensor Visibility exclusions +Write-Output "Retrieving Sensor Visibility exclusions..." +$RawSvExclusions = Get-FalconSvExclusion -Detailed +Write-Output "Raw Sensor Visibility Exclusions:" +$RawSvExclusions | Format-List + +$SvExclusions = $RawSvExclusions | Select-Object $SvFields +if ($SvExclusions -and $SvExclusions.Count -gt 0) { + Write-Output "Sensor Visibility Exclusions:" + $SvExclusions | Format-Table -AutoSize +} else { + Write-Output "No Sensor Visibility exclusions found or failed to retrieve exclusions." +} + +# Export the results based on the specified output format +switch ($OutputFormat) { + 'CSV' { + Write-Output "Exporting exclusions to CSV files..." + $MlExclusions | Export-Csv -Path "MlExclusions.csv" -NoTypeInformation + $IoaExclusions | Export-Csv -Path "IoaExclusions.csv" -NoTypeInformation + $SvExclusions | Export-Csv -Path "SvExclusions.csv" -NoTypeInformation + Write-Output "Exclusions have been exported to CSV files." + } + 'Text' { + Write-Output "Exporting exclusions to text files..." + $MlExclusions | Out-File -FilePath "MlExclusions.txt" + $IoaExclusions | Out-File -FilePath "IoaExclusions.txt" + $SvExclusions | Out-File -FilePath "SvExclusions.txt" + Write-Output "Exclusions have been exported to text files." + } + 'JSON' { + Write-Output "Exporting exclusions to JSON files..." + $MlExclusions | ConvertTo-Json | Out-File -FilePath "MlExclusions.json" + $IoaExclusions | ConvertTo-Json | Out-File -FilePath "IoaExclusions.json" + $SvExclusions | ConvertTo-Json | Out-File -FilePath "SvExclusions.json" + Write-Output "Exclusions have been exported to JSON files." + } +} diff --git a/samples/ods/export-scans-by-hostname.ps1 b/samples/ods/export-scans-by-hostname.ps1 new file mode 100644 index 00000000..f61020b1 --- /dev/null +++ b/samples/ods/export-scans-by-hostname.ps1 @@ -0,0 +1,71 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion='2.2'} +<# +.SYNOPSIS +Create a CSV in the local directory containing on-demand scan results matching a hostname search result +.DESCRIPTION +Requires 'Hosts: Read' and 'On-demand scans (ODS): Read'. +.PARAMETER ClientId +API client identifier +.PARAMETER ClientSecret +API client secret +.PARAMETER Hostname +Hostname value, used with authorization token request [default: https://api.crowdstrike.com] +.PARAMETER MemberCid +Optional child CID, if requesting an authorization token for a single child CID +.PARAMETER ScanTarget +Hostname of device to output on-demand scan results +.EXAMPLE +.\export-scans-by-hostname.ps1 -ClientId abc -ClientSecret def -ScanTarget my_hostname +#> +[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)] + [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', + 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + [string]$Hostname, + [Parameter(Position=4)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$MemberCid, + [Parameter(Mandatory,Position=5)] + [string]$ScanTarget +) +begin { + # Build hashtable for authorization token request + $Token = @{} + @('ClientId','ClientSecret','Hostname','MemberCid').foreach{ + if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ } + } +} +process { + try { + # Request an authorization token from the Falcon APIs + Request-FalconToken @Token + if ((Test-FalconToken).Token -eq $true) { + # Find 'device_id' matching $ScanTarget and assemble CSV name + [string]$HostId = Get-FalconHost -Filter "hostname:'$ScanTarget'" -Sort last_seen.desc -Limit 1 + if (!$HostId) { throw "No device found matching '$ScanTarget'." } + [string]$OutputFile = Join-Path (Get-Location).Path ('scan_results_for_{0}_{1}.csv' -f $HostId,( + Get-Date -Format FileDateTime)) + # Retrieve scan results and export to CSV + Get-FalconScan -Detailed -All | Where-Object { $_.hosts -contains $HostId } | Select-Object @{l='scan_id'; + e={$_.id}},@{l='device_id';e={$_.hosts -join ','}},status,initiated_from,@{l='file_paths';e={ + $_.file_paths -join ','}},@{l='scanned';e={$_.filecount.scanned}},@{l='malicious';e={ + $_.filecount.malicious}},@{l='quarantined';e={$_.filecount.quarantined}},@{l='skipped';e={ + $_.filecount.skipped}},@{l='traversed';e={$_.filecount.traversed}},scan_started_on,scan_completed_on | + Export-Csv $OutputFile -NoTypeInformation -Append + } + } catch { + throw $_ + } finally { + # Silently revoke active authorization token + if ((Test-FalconToken).Token -eq $true) { [void](Revoke-FalconToken) } + } +} +end { if (Test-Path $OutputFile) { Get-ChildItem $OutputFile | Select-Object FullName,Length,LastWriteTime }} \ No newline at end of file diff --git a/samples/policies/add-a-list-of-combined_id-exceptions-to-a-device-control-policy.ps1 b/samples/policy-device-control/add-a-list-of-combined_id-exceptions-to-a-device-control-policy.ps1 similarity index 100% rename from samples/policies/add-a-list-of-combined_id-exceptions-to-a-device-control-policy.ps1 rename to samples/policy-device-control/add-a-list-of-combined_id-exceptions-to-a-device-control-policy.ps1 diff --git a/samples/policy-device-control/add_device_control_exceptions_from_activity_json_export.ps1 b/samples/policy-device-control/add_device_control_exceptions_from_activity_json_export.ps1 new file mode 100644 index 00000000..d0210a44 --- /dev/null +++ b/samples/policy-device-control/add_device_control_exceptions_from_activity_json_export.ps1 @@ -0,0 +1,162 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion ='2.2'} +<# +.SYNOPSIS +Add a list of exceptions to an existing Device Control policy using a Json export from the 'Device Control +Activity' page within the Falcon console. +.DESCRIPTION +Your Json file must contain 'platform_name', 'policy_action', 'usb_device_classes' and either 'usb_device_id' or +'usb_device_vendor_id', 'usb_device_product_id', and 'usb_device_sn' to function. If the required fields are not +present, the script will generate an error and will not continue. + +Once complete, the script will create an 'exception_invalid' and 'exception_valid' CSV files with lists of the +exceptions that were processed (with an 'added' column stating whether or not they were created) and exceptions +that were ignored. + +Requires 'Device control policies: Read' and 'Device control policies: Write' permission. +.PARAMETER ClientId +OAuth2 client identifier +.PARAMETER ClientSecret +OAuth2 client secret +.PARAMETER Cloud +CrowdStrike cloud [default: 'us-1'] +.PARAMETER Path +Path to Json export +.PARAMETER Class +Class type, for filtering Json to specific exceptions +.PARAMETER Action +Action type, used when creating exceptions +.PARAMETER PolicyId +Device Control policy to add exceptions +.EXAMPLE +.\add_device_control_exceptions_from_activity_export_json.ps1 -ClientId -ClientSecret + -Cloud us-1 -Path .\my.json -Class MASS_STORAGE -Action FULL_ACCESS -PolicyId +#> +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)] + [ValidateSet('eu-1','us-gov-1','us-1','us-2')] + [string]$Cloud, + [Parameter(Mandatory,Position=4)] + [ValidateScript({ Test-Path $_ -PathType Leaf })] + [string]$Path, + [Parameter(Mandatory,Position=5)] + [ValidateSet('ANY','AUDIO_VIDEO','IMAGING','MASS_STORAGE','MOBILE','PRINTER','WIRELESS',IgnoreCase=$false)] + [string]$Class, + [Parameter(Mandatory,Position=6)] + [ValidateSet('BLOCK_ALL','BLOCK_EXECUTE','BLOCK_WRITE_EXECUTE','FULL_ACCESS',IgnoreCase=$false)] + [string]$Action, + [Parameter(Mandatory,Position=7)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$PolicyId +) +begin { + if (($Class -eq 'ANY' -and $Action -eq 'FULL_ACCESS') -or ($Class -match + 'AUDIO_VIDEO|IMAGING|MOBILE|PRINTER|WIRELESS' -and $Action -notmatch 'BLOCK_ALL|FULL_ACCESS')) { + # Error if user attempts unsupported action for chosen class + throw "'$Action' is not an accepted action value for class '$Class'." + } else { + # Define names of output files and request authorization token + [string]$InvalidPath = Join-Path (Get-Location).Path 'exception_invalid.csv' + [string]$ValidPath = Join-Path (Get-Location).Path 'exception_valid.csv' + $Token = @{ ClientId = $ClientId; ClientSecret = $ClientSecret } + if ($Cloud) { $Token['Cloud'] = $Cloud } + Request-FalconToken @Token + } +} +process { + if ((Test-FalconToken).Token -eq $true) { + try { + # Import Json and select required fields + $Import = Get-Content -Path $Path | ConvertFrom-Json | Where-Object { $_.usb_device_classes -contains + $Class } | Select-Object usb_device_id,usb_device_vendor_id,usb_device_product_id,usb_device_sn, + usb_device_vendor_name,usb_device_product_name + if ($Import) { + # Create hashtable to contain valid and invalid entries + $Output = @{ + Invalid = [System.Collections.Generic.List[PSCustomObject]]@() + Valid = [System.Collections.Generic.List[PSCustomObject]]@() + } + foreach ($i in $Import) { + if (![string]::IsNullOrEmpty($i.usb_device_id)) { + if ($i.usb_device_id -notmatch '^(\w+_){2}\w+' -or $i.usb_device_id -match + '[^\x00-\x7F]|^(\w+_){2}.+_') { + # Capture invalid usb_device_id values + if ($Output.Invalid.usb_device_id -notcontains $i.usb_device_id) { $Output.Invalid.Add($i) } + } elseif ($Output.Valid.combined_id -notcontains ($i.usb_device_id).Trim()) { + # Capture unique entries with usb_device_id values and convert them to exception format + $Output.Valid.Add([PSCustomObject]@{ + action = $Action + combined_id = ($i.usb_device_id).Trim() + vendor_name = ($i.usb_device_vendor_name).Trim() + product_name = ($i.usb_device_product_name).Trim() + }) + } + } else { + [boolean[]]$Missing = @('usb_device_vendor_id','usb_device_product_id','usb_device_sn').foreach{ + # Verify required fields + [string]::IsNullOrEmpty($i.$_) + } + if ($Missing -eq $true) { + # Capture entries that don't have required fields + if ($Output.Invalid.usb_device_id -notcontains $i.usb_device_id) { $Output.Invalid.Add($i) } + } else { + $Existing = $Output.Valid | Where-Object { $_.vendor_id -eq ($i.usb_device_vendor_id).Trim() -and + $_.product_id -eq ($i.usb_device_product_id).Trim() -and $_.serial_number -eq + ($i.usb_device_sn).Trim() } + if (!$Existing) { + # Capture unique usb_device_vendor_id/usb_device_product_id/usb_device_sn entries and convert them + # to exception format + $Output.Valid.Add([PSCustomObject]@{ + action = $Action + vendor_id = ($i.usb_device_vendor_id).Trim() + product_id = ($i.usb_device_product_id).Trim() + serial_number = ($i.usb_device_sn).Trim() + vendor_name = ($i.usb_device_vendor_name).Trim() + product_name = ($i.usb_device_product_name).Trim() + }) + } + } + } + } + if ($Output.Valid) { + $Setting = [PSCustomObject]@{ classes = @(@{ id = $Class; exceptions = $Output.Valid })} + $Edit = Edit-FalconDeviceControlPolicy -Id $PolicyId -Setting $Setting + if ($Edit) { + foreach ($i in $Edit.settings.classes.Where({ $_.id -eq $Class }).exceptions) { + if ($i.combined_id) { + # Mark each combined_id as added + @(@($Output.Valid).Where({ $_.combined_id -eq $i.combined_id })).foreach{ + $_.PSObject.Properties.Add((New-Object PSNoteProperty('added',$true))) + } + } elseif ($i.vendor_id -and $i.product_id -and $i.serial_number) { + # Mark each vendor_id/product_id/serial_number as added + @(@($Output.Valid).Where({ $_.vendor_id -eq $i.vendor_id -and $_.product_id -eq $i.product_id -and + $_.serial_number -eq $i.serial_number})).foreach{ + $_.PSObject.Properties.Add((New-Object PSNoteProperty('added',$true))) + } + } + } + @($Output.Valid).Where({ !$_.added }).foreach{ + # Mark unmatched results with 'false' + $_.PSObject.Properties.Add((New-Object PSNoteProperty('added',$false))) + } + } + # Export results to CSV and display created files + $Output.Valid | Export-Csv $ValidPath -NoTypeInformation + } + if ($Output.Invalid) { $Output.Invalid | Export-Csv $InvalidPath -NoTypeInformation } + @($ValidPath,$InvalidPath).foreach{ + if (Test-Path $_) { Get-ChildItem $_ | Select-Object FullName,Length,LastWriteTime } + } + } + } catch { + throw $_ + } + } +} \ No newline at end of file diff --git a/samples/policy-device-control/create-csv-of-device-control-policy-exceptions.ps1 b/samples/policy-device-control/create-csv-of-device-control-policy-exceptions.ps1 new file mode 100644 index 00000000..03af14e6 --- /dev/null +++ b/samples/policy-device-control/create-csv-of-device-control-policy-exceptions.ps1 @@ -0,0 +1,116 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion ='2.2'} +<# +.SYNOPSIS +Create a CSV containing exceptions assigned to USB Device Control policies in a CID +.PARAMETER ClientId +API client identifier +.PARAMETER ClientSecret +API client secret +.PARAMETER Cloud +Cloud value, used with authorization token request [default: us-1] +.PARAMETER Hostname +Hostname value, used with authorization token request [default: https://api.crowdstrike.com] +.PARAMETER MemberCid +A list of one or more child CIDs to run the script against [default: all active child CIDs] +.PARAMETER PolicyId +A list of one of more Device Control policy identifiers to target in a single CID [default: all available] +#> +[CmdletBinding()] +param( + [Parameter(ParameterSetName='Cloud',Mandatory,Position=1)] + [Parameter(ParameterSetName='Hostname',Mandatory,Position=1)] + [Parameter(ParameterSetName='Cloud_MemberCid',Mandatory,Position=1)] + [Parameter(ParameterSetName='Hostname_MemberCid',Mandatory,Position=1)] + [Parameter(ParameterSetName='Cloud_PolicyId',Mandatory,Position=1)] + [Parameter(ParameterSetName='Hostname_PolicyId',Mandatory,Position=1)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string]$ClientId, + [Parameter(ParameterSetName='Cloud',Mandatory,Position=2)] + [Parameter(ParameterSetName='Hostname',Mandatory,Position=2)] + [Parameter(ParameterSetName='Cloud_MemberCid',Mandatory,Position=2)] + [Parameter(ParameterSetName='Hostname_MemberCid',Mandatory,Position=2)] + [Parameter(ParameterSetName='Cloud_PolicyId',Mandatory,Position=2)] + [Parameter(ParameterSetName='Hostname_PolicyId',Mandatory,Position=2)] + [ValidatePattern('^\w{40}$')] + [string]$ClientSecret, + [Parameter(ParameterSetName='Cloud',Position=3)] + [Parameter(ParameterSetName='Cloud_MemberCid',Position=3)] + [Parameter(ParameterSetName='Cloud_PolicyId',Position=3)] + [ValidateSet('us-1','us-2','us-gov-1','eu-1',IgnoreCase=$false)] + [string]$Cloud, + [Parameter(ParameterSetName='Hostname',Position=3)] + [Parameter(ParameterSetName='Hostname_MemberCid',Position=3)] + [Parameter(ParameterSetName='Hostname_PolicyId',Position=3)] + [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', + 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + [string]$Hostname, + [Parameter(ParameterSetName='Cloud_MemberCid',Mandatory)] + [Parameter(ParameterSetName='Hostname_MemberCid',Mandatory)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string[]]$MemberCid, + [Parameter(ParameterSetName='Cloud_PolicyId',Mandatory)] + [Parameter(ParameterSetName='Hostname_PolicyId',Mandatory)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string[]]$PolicyId +) +begin { + function Write-PolicyException ([string]$String,[string[]]$PolicyId) { + $PolicyList = if ($PolicyId) { + # Target specific policy identifiers, if given + Get-FalconDeviceControlPolicy -Id $PolicyId + } else { + if ($String) { Write-Host "Retrieving USB Device Control policies for CID '$String'..." } + Get-FalconDeviceControlPolicy -Detailed -All + } + if ($PolicyList) { + [string]$Filename = 'device_control_exceptions.csv' + if ($String) { $Filename = $String,$Filename -join '_' } + foreach ($i in $PolicyList) { + # Output each exception for each class under each policy + $i.settings.classes.exceptions | Select-Object @{l='policy_id';e={$i.id}},@{l='policy_name';e={$i.name}}, + @{l='policy_platform';e={$i.platform_name}},@{l='exception_id';e={$_.id}},class,vendor_id_decimal, + vendor_name,product_id,product_id_decimal,product_name,serial_number,combined_id,action,match_method, + description | Export-Csv -Path (Join-Path (Get-Location).Path $Filename) -NoTypeInformation -Append + } + $Filename + } + } + # Set baseline token request parameters + $Token = @{} + @('ClientId','ClientSecret','Cloud','Hostname').foreach{ + if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ } + } + Request-FalconToken @Token + [string[]]$MemberCid = if (!$MemberCid -and !$PolicyId) { + # Attempt to retrieve MemberCids + @(Get-FalconMemberCid -Detailed -All -EA 0).Where({ $_.status -eq 'active' }).child_cid + } +} +process { + [string[]]$OutputList = if ($MemberCid) { + if ((Test-FalconToken).Token -eq $true) { [void](Revoke-FalconToken) } + foreach ($Cid in $MemberCid) { + try { + # Authenticate with Member CID and output exceptions + Request-FalconToken @Token -MemberCid $Cid + if ((Test-FalconToken).Token -eq $true) { Write-PolicyException $Cid } + } catch { + Write-Error $_ + } finally { + if ((Test-FalconToken).Token -eq $true) { + # Remove authentication token and sleep to avoid rate limiting + [void](Revoke-FalconToken) + Start-Sleep -Seconds 5 + } + } + } + } elseif ((Test-FalconToken).Token -eq $true) { + if ($PolicyId) { Write-PolicyException -PolicyId $PolicyId } else { Write-PolicyException } + } +} +end { + if ($OutputList) { + @($OutputList).foreach{ if (Test-Path $_) { Get-ChildItem $_ | Select-Object FullName,Length,LastWriteTime }} + } +} \ No newline at end of file diff --git a/samples/policies/create-csvs-containing-device-control-policy-details-and-exceptions.ps1 b/samples/policy-device-control/create-csvs-containing-device-control-policy-details-and-exceptions.ps1 similarity index 100% rename from samples/policies/create-csvs-containing-device-control-policy-details-and-exceptions.ps1 rename to samples/policy-device-control/create-csvs-containing-device-control-policy-details-and-exceptions.ps1 diff --git a/samples/policies/create-a-list-of-minimum-sensor-versions-by-linux-kernel.ps1 b/samples/policy-sensor-update/create-a-list-of-minimum-sensor-versions-by-linux-kernel.ps1 similarity index 100% rename from samples/policies/create-a-list-of-minimum-sensor-versions-by-linux-kernel.ps1 rename to samples/policy-sensor-update/create-a-list-of-minimum-sensor-versions-by-linux-kernel.ps1 diff --git a/samples/policies/modify-the-build-of-a-sensor-update-policy-by-name.ps1 b/samples/policy-sensor-update/modify-the-build-of-a-sensor-update-policy-by-name.ps1 similarity index 100% rename from samples/policies/modify-the-build-of-a-sensor-update-policy-by-name.ps1 rename to samples/policy-sensor-update/modify-the-build-of-a-sensor-update-policy-by-name.ps1 diff --git a/samples/policies/modify-all-sensor-visibility-exclusions-to-include-an-additional-host-group.ps1 b/samples/policy-sv-exclusions/modify-all-sensor-visibility-exclusions-to-include-an-additional-host-group.ps1 similarity index 100% rename from samples/policies/modify-all-sensor-visibility-exclusions-to-include-an-additional-host-group.ps1 rename to samples/policy-sv-exclusions/modify-all-sensor-visibility-exclusions-to-include-an-additional-host-group.ps1 diff --git a/samples/policies/assign-a-list-of-host-group-names-to-a-specific-policy-within-a-list-of-child-cids.ps1 b/samples/policy/assign-a-list-of-host-group-names-to-a-specific-policy-within-a-list-of-child-cids.ps1 similarity index 100% rename from samples/policies/assign-a-list-of-host-group-names-to-a-specific-policy-within-a-list-of-child-cids.ps1 rename to samples/policy/assign-a-list-of-host-group-names-to-a-specific-policy-within-a-list-of-child-cids.ps1 diff --git a/samples/policy/list_prevention_policies_and_assigned_host_groups.ps1 b/samples/policy/list_prevention_policies_and_assigned_host_groups.ps1 new file mode 100644 index 00000000..37bef475 --- /dev/null +++ b/samples/policy/list_prevention_policies_and_assigned_host_groups.ps1 @@ -0,0 +1,90 @@ +#Requires -Version 5.1 +using module @{ModuleName='PSFalcon';ModuleVersion='2.2'} +<# +.SYNOPSIS +Create a CSV containing a list of Prevention policies, their assigned Host Groups, and total member counts for +all CIDs within a Flight Control environment +.DESCRIPTION +A CSV will be created in the local directory containing the script results +.PARAMETER ClientId +API client identifier +.PARAMETER ClientSecret +API client secret +.PARAMETER Hostname +Hostname value, used with authorization token request [default: https://api.crowdstrike.com] +.PARAMETER MemberCid +A list of one or more child CIDs to run the script against [default: all active child CIDs] +.EXAMPLE +.\list_prevention_policies_and_assigned_host_groups.ps1 -ClientId abc -ClientSecret def -Cloud us-1 +#> +[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)] + [ValidateSet('https://api.crowdstrike.com','https://api.us-2.crowdstrike.com', + 'https://api.laggar.gcw.crowdstrike.com','https://api.eu-1.crowdstrike.com',IgnoreCase=$false)] + [string]$Hostname, + [Parameter(Position=4)] + [ValidatePattern('^[a-fA-F0-9]{32}$')] + [string[]]$MemberCid +) +begin { + # Build hashtable for authorization token request + $Token = @{} + @('ClientId','ClientSecret','Hostname').foreach{ + if ($PSBoundParameters.$_) { $Token[$_] = $PSBoundParameters.$_ } + } + if (!$MemberCid) { + Request-FalconToken @Token + if ((Test-FalconToken).Token -eq $true) { + # Gather available active child CIDs and silently revoke initial authorization token + [object[]]$MemberCid = Get-FalconMemberCid -Detailed -All | Where-Object { $_.status -eq 'active' } | + Select-Object name,child_cid + [void](Revoke-FalconToken) + } + } + [string]$OutputFile = Join-Path (Get-Location).Path "policies_and_host_groups_$( + Get-Date -Format FileDateTime).csv" +} +process { + if (!$MemberCid) { throw "Child CIDs undefined. Unable to continue." } + foreach ($Cid in $MemberCid) { + try { + # Request an authorization token from the Falcon APIs for each member CID + Request-FalconToken @Token -MemberCid $Cid.child_cid + if ((Test-FalconToken).Token -eq $true) { + Write-Host "Authorized with '$($Cid.name)'. Collecting policies..." + try { + Get-FalconPreventionPolicy -Detailed -All | Select-Object @{l='cid';e={$Cid.child_cid}},@{l='cid_name'; + e={$Cid.name}}@{l='type';e={'prevention_policy'}},id,platform_name,name,enabled, + @{l='assigned_groups';e={$_.groups.id -join ','}},@{l='total_members';e={ + Get-FalconPreventionPolicyMember -Id $_.id -Total}} | Export-Csv $OutputFile -NoTypeInformation -Append + } catch { + Write-Error "Failed to collect prevention policies from '$($Cid.name)'." + } + try { + Get-FalconHostGroup -Detailed -All | Select-Object @{l='cid';e={$Cid.child_cid}},@{l='cid_name'; + e={$Cid.name}},@{l='type';e={'host_group',$_.group_type -join ':'}},id,@{l='platform_name';e={''}}, + name,@{l='enabled';e={''}},@{l='assigned_groups';e={''}},@{l='total_members';e={ + Get-FalconHostGroupMember -Id $_.id -Total}} | Export-Csv $OutputFile -NoTypeInformation -Append + } catch { + Write-Error "Failed to collect host groups from '$($Cid.name)'." + } + } + } catch { + Write-Error $_ + } finally { + if ((Test-FalconToken).Token -eq $true) { + # Silently revoke active authorization token and pause to prevent rate limiting + [void](Revoke-FalconToken) + Start-Sleep -Seconds 5 + } + } + } +} +end { if (Test-Path $OutputFile) { Get-ChildItem $OutputFile | Select-Object FullName,Length,LastWriteTime }} \ No newline at end of file diff --git a/samples/policies/output-a-list-of-assigned-host-groups-for-designated-policy-ids-within-child-cids.ps1 b/samples/policy/output-a-list-of-assigned-host-groups-for-designated-policy-ids-within-child-cids.ps1 similarity index 100% rename from samples/policies/output-a-list-of-assigned-host-groups-for-designated-policy-ids-within-child-cids.ps1 rename to samples/policy/output-a-list-of-assigned-host-groups-for-designated-policy-ids-within-child-cids.ps1 diff --git a/samples/real-time_response/download-the-latest-cswindiag-archive-from-a-list-of-hosts.ps1 b/samples/real-time-response/download-the-latest-cswindiag-archive-from-a-list-of-hosts.ps1 similarity index 100% rename from samples/real-time_response/download-the-latest-cswindiag-archive-from-a-list-of-hosts.ps1 rename to samples/real-time-response/download-the-latest-cswindiag-archive-from-a-list-of-hosts.ps1 diff --git a/samples/real-time_response/execute-cswindiag-and-download-results-from-a-list-of-hosts.ps1 b/samples/real-time-response/execute-cswindiag-and-download-results-from-a-list-of-hosts.ps1 similarity index 100% rename from samples/real-time_response/execute-cswindiag-and-download-results-from-a-list-of-hosts.ps1 rename to samples/real-time-response/execute-cswindiag-and-download-results-from-a-list-of-hosts.ps1 diff --git a/samples/real-time_response/execute-xmemdump-and-notify-when-complete.ps1 b/samples/real-time-response/execute-xmemdump-and-notify-when-complete.ps1 similarity index 100% rename from samples/real-time_response/execute-xmemdump-and-notify-when-complete.ps1 rename to samples/real-time-response/execute-xmemdump-and-notify-when-complete.ps1 diff --git a/samples/real-time_response/run-a-command-against-a-group-of-devices.ps1 b/samples/real-time-response/run-a-command-against-a-group-of-devices.ps1 similarity index 100% rename from samples/real-time_response/run-a-command-against-a-group-of-devices.ps1 rename to samples/real-time-response/run-a-command-against-a-group-of-devices.ps1 diff --git a/samples/real-time_response/upload-and-execute-a-local-script-as-a-secondary-process.ps1 b/samples/real-time-response/upload-and-execute-a-local-script-as-a-secondary-process.ps1 similarity index 100% rename from samples/real-time_response/upload-and-execute-a-local-script-as-a-secondary-process.ps1 rename to samples/real-time-response/upload-and-execute-a-local-script-as-a-secondary-process.ps1 diff --git a/samples/real-time_response/upload-and-execute-a-local-script.ps1 b/samples/real-time-response/upload-and-execute-a-local-script.ps1 similarity index 100% rename from samples/real-time_response/upload-and-execute-a-local-script.ps1 rename to samples/real-time-response/upload-and-execute-a-local-script.ps1 diff --git a/samples/scheduled_reports/download-your-most-recent-scheduled-report-results.ps1 b/samples/reports/download-your-most-recent-scheduled-report-results.ps1 similarity index 100% rename from samples/scheduled_reports/download-your-most-recent-scheduled-report-results.ps1 rename to samples/reports/download-your-most-recent-scheduled-report-results.ps1 diff --git a/samples/sensor_installers/download-the-installer-package-assigned-to-a-sensor-update-policy.ps1 b/samples/sensors/download-the-installer-package-assigned-to-a-sensor-update-policy.ps1 similarity index 100% rename from samples/sensor_installers/download-the-installer-package-assigned-to-a-sensor-update-policy.ps1 rename to samples/sensors/download-the-installer-package-assigned-to-a-sensor-update-policy.ps1 diff --git a/samples/sensor_installers/download-the-installer-package-assigned-to-your-default-sensor-update-policy.ps1 b/samples/sensors/download-the-installer-package-assigned-to-your-default-sensor-update-policy.ps1 similarity index 100% rename from samples/sensor_installers/download-the-installer-package-assigned-to-your-default-sensor-update-policy.ps1 rename to samples/sensors/download-the-installer-package-assigned-to-your-default-sensor-update-policy.ps1 diff --git a/samples/vulnerabilities/create-a-report-with-additional-host-fields.ps1 b/samples/spotlight/create-a-report-with-additional-host-fields.ps1 similarity index 100% rename from samples/vulnerabilities/create-a-report-with-additional-host-fields.ps1 rename to samples/spotlight/create-a-report-with-additional-host-fields.ps1 diff --git a/script/add_sensortag.ps1 b/script/add_sensortag.ps1 index 08b87825..06670122 100644 --- a/script/add_sensortag.ps1 +++ b/script/add_sensortag.ps1 @@ -1,4 +1,4 @@ -param([string]$Token,[string]$Tag) +param([Parameter(Mandatory,Position=1)][string]$Tag,[Parameter(Position=2)][string]$Token) $ExePath=Join-Path $env:ProgramFiles "CrowdStrike\CsSensorSettings.exe" if (Test-Path $ExePath) { if ($Token) { diff --git a/script/clear_sensortag.ps1 b/script/clear_sensortag.ps1 new file mode 100644 index 00000000..1240aa09 --- /dev/null +++ b/script/clear_sensortag.ps1 @@ -0,0 +1,11 @@ +param([Parameter(Position=1)][string]$Token) +$ExePath = Join-Path $env:ProgramFiles "CrowdStrike\CsSensorSettings.exe" +if (Test-Path $ExePath) { + if ($Token) { + echo "$Token" | & "$ExePath" clear --grouping-tags + } else { + & "$ExePath" clear --grouping-tags + } +} else { + throw "Not found: $ExePath" +} \ No newline at end of file diff --git a/script/get_sensortag.sh b/script/get_sensortag.sh deleted file mode 100644 index 74d23db6..00000000 --- a/script/get_sensortag.sh +++ /dev/null @@ -1 +0,0 @@ -/opt/CrowdStrike/falconctl -g --tags | sed "s/^Sensor grouping tags are not set.//; s/^tags=//; s/.$//" \ No newline at end of file diff --git a/script/get_sensortag.zsh b/script/get_sensortag.zsh deleted file mode 100644 index 0a8a7b95..00000000 --- a/script/get_sensortag.zsh +++ /dev/null @@ -1 +0,0 @@ -/Applications/Falcon.app/Contents/Resources/falconctl grouping-tags get | sed "s/^No grouping tags set//; s/^Grouping tags: //" \ No newline at end of file diff --git a/script/remove_sensortag.ps1 b/script/remove_sensortag.ps1 index 2487b66b..1d7cf98c 100644 --- a/script/remove_sensortag.ps1 +++ b/script/remove_sensortag.ps1 @@ -1,12 +1,10 @@ -param([string]$Tag,[string]$Token) +param([Parameter(Mandatory,Position=1)][string]$Tag,[Parameter(Position=2)][string]$Token) $ExePath = Join-Path $env:ProgramFiles "CrowdStrike\CsSensorSettings.exe" if (Test-Path $ExePath) { - if ($Token -and $Tag) { + if ($Token) { echo "$Token" | & "$ExePath" set --grouping-tags "$Tag" - } elseif ($Token) { - echo "$Token" | & "$ExePath" clear --grouping-tags } else { - & "$ExePath" clear --grouping-tags + & "$ExePath" set --grouping-tags "$Tag" } } else { throw "Not found: $ExePath"