Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ ENHANCEMENT ] Add error message when Receive-FalconInstaller fails due to timeout #310

Open
slolife opened this issue May 10, 2023 · 11 comments
Assignees
Labels
enhancement New feature or request

Comments

@slolife
Copy link

slolife commented May 10, 2023

Describe the bug
Receive-FalconInstaller does not create file or save download to file. No errors returned.

To Reproduce
Run script below. All query requests run fine and return data.

#Requires -Version 5.1
using module @{ ModuleName = 'PSFalcon'; ModuleVersion = '2.2' }

# Ensure that we have a valid CrowdStrike API token
Invoke-Expression -Command .\GetToken.ps1 | Out-Null

$Installers = Get-FalconInstaller -Filter "platform:'windows'+os:'Windows'" -Detailed

if ($Installers) {
    # Select latest installer
    $Latest = $Installers | Sort-Object -Property release_date -Descending | Select -first 1 #Where-Object { $_.version -match "^\d\.\d{1,2}\.$BuildVersion" }
	Write-Output $Latest

	if ($Latest) {
		$InstallerId = $Latest.sha256
		$Filename = $Latest.name
		$FileVersion = $Latest.version
    }
} else {
     throw "Error retrieving installer list"
}

$OutputDir = "$pwd\Output"
New-Item -Path "$OutputDir" -Force -ItemType Directory | Out-Null

$VersionedFileName = $Filename.replace('.exe', '-' + "$FileVersion" + '.exe')
$OutputPath = "$OutputDir\$VersionedFileName"

Write-Output "Downloading installer"
Receive-FalconInstaller -Id $InstallerId -Force -Path "$OutputPath"

Expected behavior
When Receive-FalconInstaller call completes, it either throws exception or file is on disk

Environment:

  • OS: Windows 10[e.g. Windows Server 2016, Windows 10]
  • PowerShell: 5.1.19041.2673
  • PSFalcon: v2.2.5 {d893eb9f-f6bb-4a40-9caf-aaff0e42acd1}

Additional context


Windows PowerShell transcript start
Start time: 20230510134942
Configuration Name: 
Machine: (Microsoft Windows NT 10.0.19045.0)
Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Process ID: 28700
PSVersion: 5.1.19041.2673
PSEdition: Desktop
PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.19041.2673
BuildVersion: 10.0.19041.2673
CLRVersion: 4.0.30319.42000
WSManStackVersion: 3.0
PSRemotingProtocolVersion: 2.3
SerializationVersion: 1.1.0.1
**********************
Transcript started, output file is PowerShell_transcript.qH4m9R3F.20230510134942.txt
PS C:\dev\crowdstrike-psfalcon> .\DownloadLatestSensors.ps1
VERBOSE: 13:49:48 [ApiClient.Invoke] POST https://api.us-2.crowdstrike.com/oauth2/token
VERBOSE: 13:49:48 [ApiClient.Invoke] ContentType=application/x-www-form-urlencoded, Accept=application/json
VERBOSE: 13:49:48 [ApiClient.Invoke] 201: Created
VERBOSE: 13:49:48 [ApiClient.Invoke] Connection=keep-alive, X-Cs-Region=us-2, X-Cs-Traceid=337ae88d-a1ff-4fd2-975c-2f9274a6a016, X-Ratelimit-Limit=300, X-Ratelimit-Remaining=299, Strict-Transport-Security=max-age=31536000; includeSubDomains, Date=Wed, 10 May 2023 20:49:47 GMT, Server=nginx
VERBOSE: 13:49:48 [Request-FalconToken] Authorized until: 05/10/2023 14:19:47
VERBOSE: 13:49:48 [Get-FalconInstaller] /sensors/combined/installers/v1:get
VERBOSE: 13:49:48 [ApiClient.Invoke] GET https://api.us-2.crowdstrike.com/sensors/combined/installers/v1?filter=platform:'windows'%2Bos:'Windows'
VERBOSE: 13:49:48 [ApiClient.Invoke] Accept=application/json
VERBOSE: 13:49:49 [ApiClient.Invoke] 200: OK
VERBOSE: 13:49:49 [ApiClient.Invoke] Connection=keep-alive, Strict-Transport-Security=max-age=15724800; includeSubDomains, max-age=31536000; includeSubDomains, X-Cs-Region=us-2, X-Cs-Traceid=298467e6-c120-43e5-bba2-5fbb6f150587, X-Ratelimit-Limit=6000, X-Ratelimit-Remaining=5999, Date=Wed, 10 May 2023 20:49:47 GMT, Server=nginx
VERBOSE: 13:49:49 [Write-Result] query_time=0.097343066, powered_by=binserv, trace_id=298467e6-c120-43e5-bba2-5fbb6f150587


name         : WindowsSensor.MaverickGyr.exe
description  : Falcon Sensor for Windows
platform     : windows
os           : Windows
os_version   :
sha256       : a5059da06d318e1766a2ce95d45d1ac1897443f62e2f2326a1d17c7347d1e7a1
release_date : 2023-05-02T22:07:45.558Z
version      : 6.54.16808
file_size    : 159103520
file_type    : exe

Downloading installer
VERBOSE: 13:49:49 [Receive-FalconInstaller] /sensors/entities/download-installer/v1:get
VERBOSE: 13:49:49 [ApiClient.Invoke] GET https://api.us-2.crowdstrike.com/sensors/entities/download-installer/v1?id=a5059da06d318e1766a2ce95d45d1ac1897443f62e2f2326a1d17c7347d1e7a1
VERBOSE: 13:49:49 [ApiClient.Invoke] Accept=application/octet-stream
@slolife slolife added the bug Something isn't working label May 10, 2023
@bk-cs
Copy link
Collaborator

bk-cs commented May 11, 2023

I suspect it's how you're building the output path that's causing a problem, but when I tried running your script it worked fine.

I tested Receive-FalconInstaller a couple of different ways to verify that the command itself works. It downloads properly when using the pipeline with an installer result:

PS C:\falcon> Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'" | Receive-FalconInstaller
VERBOSE: 12:08:23 [Get-FalconInstaller] /sensors/combined/installers/v1:get
VERBOSE: 12:08:23 [ApiClient.Invoke] GET
https://api.crowdstrike.com/sensors/combined/installers/v1?limit=1&filter=platform:'windows'
VERBOSE: 12:08:23 [ApiClient.Invoke] Accept=application/json
VERBOSE: 12:08:23 [ApiClient.Invoke] 200: OK
VERBOSE: 12:08:23 [ApiClient.Invoke] Connection=keep-alive, Strict-Transport-Security=max-age=15724800;
includeSubDomains, max-age=31536000; includeSubDomains, X-Cs-Region=us-1,
X-Cs-Traceid=42bf7ba5-c907-49e9-8a08-2f28bb8af28c, X-Ratelimit-Limit=6000, X-Ratelimit-Remaining=5991, Date=Thu, 11 May
 2023 19:08:24 GMT, Server=nginx
VERBOSE: 12:08:23 [Write-Result] query_time=0.099462462, powered_by=binserv,
trace_id=42bf7ba5-c907-49e9-8a08-2f28bb8af28c
VERBOSE: 12:08:23 [Receive-FalconInstaller] /sensors/entities/download-installer/v1:get
VERBOSE: 12:08:23 [ApiClient.Invoke] GET
https://api.crowdstrike.com/sensors/entities/download-installer/v1?id=47052db19bef20879fc470e2b76e336420d5c23bc6e1ce2b9
57cc546b024e185
VERBOSE: 12:08:23 [ApiClient.Invoke] Accept=application/octet-stream
VERBOSE: 12:08:31 [ApiClient.Invoke] Output directed to 'C:\falcon\WindowsSensor.exe'.

FullName                                 Length LastWriteTime
--------                                 ------ -------------
C:\falcon\WindowsSensor.exe 159103096 5/11/2023 12:08:31 PM

And when using values saved in a variable:

PS C:\falcon> $Installer = Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'"
VERBOSE: 12:09:30 [Get-FalconInstaller] /sensors/combined/installers/v1:get
VERBOSE: 12:09:30 [ApiClient.Invoke] GET
https://api.crowdstrike.com/sensors/combined/installers/v1?limit=1&filter=platform:'windows'
VERBOSE: 12:09:30 [ApiClient.Invoke] Accept=application/json
VERBOSE: 12:09:30 [ApiClient.Invoke] 200: OK
VERBOSE: 12:09:30 [ApiClient.Invoke] Connection=keep-alive, Strict-Transport-Security=max-age=15724800;
includeSubDomains, max-age=31536000; includeSubDomains, X-Cs-Region=us-1,
X-Cs-Traceid=87554e8f-d97f-4818-b03d-cafc859b9a59, X-Ratelimit-Limit=6000, X-Ratelimit-Remaining=5992, Date=Thu, 11 May
 2023 19:09:31 GMT, Server=nginx
VERBOSE: 12:09:30 [Write-Result] query_time=0.027503389, powered_by=binserv,
trace_id=87554e8f-d97f-4818-b03d-cafc859b9a59
PS C:\falcon> Receive-FalconInstaller -Id $Installer.sha256 -Force -Path C:\falcon\WindowsSensor.exe
VERBOSE: 12:10:04 [Receive-FalconInstaller] /sensors/entities/download-installer/v1:get
VERBOSE: 12:10:04 [ApiClient.Invoke] GET
https://api.crowdstrike.com/sensors/entities/download-installer/v1?id=47052db19bef20879fc470e2b76e336420d5c23bc6e1ce2b9
57cc546b024e185
VERBOSE: 12:10:04 [ApiClient.Invoke] Accept=application/octet-stream
VERBOSE: 12:10:13 [ApiClient.Invoke] Output directed to 'C:\falcon\WindowsSensor.exe'.

FullName                       Length LastWriteTime
--------                       ------ -------------
C:\falcon\WindowsSensor.exe 159103096 5/11/2023 12:10:13 PM

Could you try updating your path creation method? Here's how I would do it:

$OutputDir = Join-Path (Get-Location).Path Output
$Installer = Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'+os:'Windows'" -Sort release_date.desc
if (!$Installer) { throw "No installer result." }
if ((Test-Path $OutputDir) -eq $false) { [void](New-Item -Path $OutputDir -ItemType Directory) }
$Filename = (($Installer.name -replace '\.exe$'),$Installer.version -join '-'),'exe' -join '.'
Receive-FalconInstaller -Id $Installer.sha256 -Path (Join-Path $OutputDir $Filename) -Force

@bk-cs bk-cs added question Further information is requested and removed bug Something isn't working labels May 11, 2023
@bk-cs bk-cs changed the title [ BUG ] Receive-FalconInstaller does not save to disk [ QUESTION ] Receive-FalconInstaller not saving to disk when used in script May 11, 2023
@slolife
Copy link
Author

slolife commented May 11, 2023

I tried the code you posted:

#Requires -Version 5.1
using module @{ ModuleName = 'PSFalcon'; ModuleVersion = '2.2' }

$OutputDir = Join-Path (Get-Location).Path Output
$Installer = Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'+os:'Windows'" -Sort release_date.desc
if (!$Installer) { throw "No installer result." }
if ((Test-Path $OutputDir) -eq $false) { [void](New-Item -Path $OutputDir -ItemType Directory) }
$Filename = (($Installer.name -replace '\.exe$'),$Installer.version -join '-'),'exe' -join '.'
Receive-FalconInstaller -Id $Installer.sha256 -Path (Join-Path $OutputDir $Filename) -Force

And that did not write the file.

I also tried what you posted:
Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'" | Receive-FalconInstaller

Either case, I am not getting the following message at the end:
[ApiClient.Invoke] Output directed to 'C:\falcon\WindowsSensor.exe'

Any other thoughts as to what might be different about my setup/machine?

@bk-cs
Copy link
Collaborator

bk-cs commented May 12, 2023

Could you try removing and reinstalling the module?

Uninstall-Module -Name PSFalcon -AllVersions
Install-Module -Name PSFalcon -Scope CurrentUser

@slolife
Copy link
Author

slolife commented May 12, 2023

Strange. I run

Uninstall-Module -Name PSFalcon -AllVersions
Install-Module -Name PSFalcon -Scope CurrentUser

And then run
Get-FalconInstaller -Detailed -Limit 1 -Filter "platform:'windows'" | Receive-FalconInstaller
And it works (correctly downloads and saves the file to disk).

Run the Get/Receive line again and it doesn't save the file.

Uninstall/Re-install again and it still doesn't work. I have to uninstall, reboot, then install and get 1 run that works.

@slolife
Copy link
Author

slolife commented May 13, 2023

It is seems that this might be a timeout issue during download on 1 machine. I ran it on two other machines with faster connections and both worked repeatedly.

I changed call to download macOS and Ubuntu images on the problem machine and those worked repeatedly, so definitely seems like a timeout issue.

Any ideas on lack of error message for a timeout?

@bk-cs
Copy link
Collaborator

bk-cs commented May 15, 2023

Thanks for following up! I'll do some research and determine if I can add an error message when the download fails due to timeout.

@bk-cs bk-cs added enhancement New feature or request and removed question Further information is requested labels May 15, 2023
@bk-cs bk-cs changed the title [ QUESTION ] Receive-FalconInstaller not saving to disk when used in script [ ENHANCEMENT ] Add error message when Receive-FalconInstaller fails due to timeout May 15, 2023
@bk-cs
Copy link
Collaborator

bk-cs commented Nov 22, 2023

I experimented with this to see if it was possible, but I've yet to figure out a way to output an error given how PSFalcon is downloading the file. Keeping this open in case I figure it out...

@MatthewCKelly
Copy link
Contributor

Greeting, I was also having this issue..

I worked out a work around by adding a timeout value to the class.ps1 as below.

So I am now able to download all my missing windows clients.

  ApiClient() {
    $this.Handler = [System.Net.Http.HttpClientHandler]::New()
    $this.Client = [System.Net.Http.HttpClient]::New($this.Handler)
    # added a large timeout...
    $this.Client.Timeout = New-Object System.TimeSpan(0, 10, 90);

    $this.Collector = $null
  }

I had tried to add it to the download section .. as follows..

      $Request = if ($Param.Outfile) {
        # Download file
        @($Param.Headers.Keys).foreach{ $this.Client.DefaultRequestHeaders.Add($_,$Param.Headers.$_) }
        #  Added timeout
        $this.Client.Timeout = New-Object System.TimeSpan(0, 10, 90);
        $this.Verbose('ApiClient.Invoke','Receiving ByteArray content...')
        $this.Client.GetByteArrayAsync($Param.Path)
      }

As the $this.Client object it is reused, if you use multiple calls you get the following reponse..

Exception setting "Timeout": "This instance has already started one or more requests. Properties can only be modified before sending the first request."
At line:1 char:1
+ $this.Client.Timeout = New-Object System.TimeSpan(0, 10, 90);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ExceptionWhenSetting

@CBecker-EDR
Copy link

Thank you @MatthewCKelly . I will try this out. Right now, all of my downloads are working without adding this timeout, but I am sure I will reproduce again sometime soon with a slow connection.

@bk-cs
Copy link
Collaborator

bk-cs commented Dec 20, 2023

I wasn't able to get that timeout option working without the "re-use" errors that @MatthewCKelly reported. I'm still experimenting...

@bk-cs bk-cs closed this as completed Dec 20, 2023
@bk-cs bk-cs reopened this Dec 20, 2023
@MatthewCKelly
Copy link
Contributor

I wasn't able to get that timeout option working without the "re-use" errors that @MatthewCKelly reported. I'm still experimenting...

I have a script that does the following..

  1. Gathers all the current installers.
  2. Then all the SensorUpdate policies,
  3. Enumerates all the Policies for membership and then add to an array all the policies that have more than than 10 members and have a sensor assigned and windows
  4. create a folder for each version that doesnt exist
  5. downloads each file that doesnt exist.
  6. gets the hash of each
  7. then emails the security team once complete any updates.
    as I am doing multiple calls, the class is loaded only the once therefore as the timeout is set you cannot re-set it.. Hence I moved it to earlier in the class..

bk-cs added a commit that referenced this issue Dec 20, 2023
Issue #310: Added default client timeout of 1 minute to help generate error messages when file downloads do not complete.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants