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

Update powershell install/uninstaller #136

Merged
merged 26 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
uses: actions/cache@v3
with:
path: ~/.vagrant.d/boxes
key: ${{ runner.os }}-vagrant-${{ hashFiles('./molecule/win_falcon_install/molecule.yml') }}
key: ${{ runner.os }}-vagrant-${{ hashFiles('./molecule/pwsh_install_policy/molecule.yml') }}
restore-keys: |
${{ runner.os }}-vagrant-

Expand Down
4 changes: 2 additions & 2 deletions molecule/pwsh_install_policy/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
- name: Converge
hosts: all
tasks:
- name: Run Powershell Script
- name: Run Install Script
ansible.builtin.script: |
../../powershell/install/falcon_windows_install.ps1 `
-FalconClientId "{{ lookup('env', 'FALCON_CLIENT_ID') }}" `
-FalconClientSecret "{{ lookup('env', 'FALCON_CLIENT_SECRET') }}" `
-ProvToken "{{ lookup('env', 'FALCON_PROV_TOKEN') }}"
-ProvToken "{{ lookup('env', 'FALCON_PROV_TOKEN') }}"
2 changes: 1 addition & 1 deletion molecule/pwsh_install_policy/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ scenario:
- prepare
- converge
- side_effect
- verify
- verify
2 changes: 1 addition & 1 deletion molecule/pwsh_install_policy/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@

- name: Verify Falcon Sensor is installed and running
ansible.builtin.assert:
that: "'RUNNING' in win_status.stdout"
that: "'RUNNING' in win_status.stdout"
3 changes: 3 additions & 0 deletions powershell/PSScriptAnalyzerSettings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
ExcludeRules = @("PSUseShouldProcessForStateChangingFunctions")
}
4 changes: 2 additions & 2 deletions powershell/install/falcon_windows_install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ begin {
$Content += , "[$($Falcon.ResponseHeaders.Get('X-Cs-TraceId'))]"
}

"$(@($Content + $Source) -join ' '): $Message" >> $LogPath
"$(@($Content + $Source) -join ' '): $Message" | Out-File -FilePath $LogPath -Append -Encoding utf8

if ([string]::IsNullOrEmpty($Source)) {
if ($FalconClientId.Length -gt 0) {
Expand Down Expand Up @@ -235,7 +235,7 @@ process {
throw $Message
}

if (not (Test-Path -Path $UninstallerPath)) {
if (-not (Test-Path -Path $UninstallerPath)) {
$Message = "${UninstallerName} not found."
Write-FalconLog 'CheckUninstaller' $Message
throw $Message
Expand Down
106 changes: 57 additions & 49 deletions powershell/install/falcon_windows_uninstall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Delete sensor uninstaller package when complete [default: $true]
.PARAMETER DeleteScript
Delete script when complete [default: $true]
.PARAMETER RemoveHost
Remove host from CrowdStrike Falcon [default: $false]
Remove host from CrowdStrike Falcon
.PARAMETER FalconCloud
CrowdStrike Falcon OAuth2 API Hostname [default: autodiscover]
.PARAMETER FalconClientId
Expand Down Expand Up @@ -68,7 +68,7 @@ param(
[bool] $DeleteScript = $true,

[Parameter(Position = 7)]
[bool] $RemoveHost = $false,
[switch] $RemoveHost,

[Parameter(Position = 8)]
[ValidateSet('autodiscover', 'us-1', 'us-2', 'eu-1', 'us-gov-1')]
Expand Down Expand Up @@ -102,7 +102,7 @@ begin {
$Content += , "[$($Falcon.ResponseHeaders.Get('X-Cs-TraceId'))]"
}

"$(@($Content + $Source) -join ' '): $Message" >> $LogPath
"$(@($Content + $Source) -join ' '): $Message" | Out-File -FilePath $LogPath -Append -Encoding utf8

if ([string]::IsNullOrEmpty($Source)) {
if ($FalconClientId.Length -gt 0) {
Expand Down Expand Up @@ -133,7 +133,7 @@ begin {
$content = ConvertFrom-Json -InputObject $response.Content

if ([string]::IsNullOrEmpty($content.access_token)) {
$Message = "Unable to authenticate to the CrowdStrike Falcon API. Please check your credentials and try again."
$Message = 'Unable to authenticate to the CrowdStrike Falcon API. Please check your credentials and try again.'
throw $Message
}

Expand All @@ -156,7 +156,7 @@ begin {
$region = $response.Headers.GetValues('X-Cs-Region')[0]
}
else {
$Message = "Received a redirect but no X-Cs-Region header was provided. Unable to autodiscover the FalconCloud. Please set FalconCloud to the correct region."
$Message = 'Received a redirect but no X-Cs-Region header was provided. Unable to autodiscover the FalconCloud. Please set FalconCloud to the correct region.'
Write-FalconLog -Source 'Invoke-FalconAuth' -Message $Message
throw $Message
}
Expand Down Expand Up @@ -205,7 +205,7 @@ begin {
}
}
if (!$aid) {
$Message = "AID not found in registry. This could be due to the agent not being installed or being partially installed."
$Message = 'AID not found in registry. This could be due to the agent not being installed or being partially installed.'
}
else {
$Message = "Found AID: $aid"
Expand All @@ -215,17 +215,6 @@ begin {
return $aid
}

if ($UninstallTool -match "installcache") {
$UninstallerName = 'WindowsSensor*.exe'
$UninstallerCachePath = "C:\ProgramData\Package Cache"
$UninstallerPath = Get-ChildItem -Include $UninstallerName -Path $UninstallerCachePath -Recurse | ForEach-Object { $_.FullName }
}

if ($UninstallTool -match "standalone") {
$UninstallerName = 'CsUninstallTool.exe'
$UninstallerPath = Join-Path -Path $PSScriptRoot -ChildPath $UninstallerName
}

$WinSystem = [Environment]::GetFolderPath('System')
$WinTemp = $WinSystem -replace 'system32', 'Temp'
if (!$LogPath) {
Expand All @@ -241,7 +230,7 @@ begin {
}

function Format-FalconResponseError($errors) {
$Message = ""
$Message = ''
foreach ($error in $errors) {
$Message += "`r`n`t $($error.message)"
}
Expand All @@ -252,20 +241,21 @@ begin {
# an action of $hide will hide the host, anything else will unhide the host
# should only be called to hide/unhide a host that is already in the console
function Invoke-HostVisibility ([string] $action) {
if ($action -eq "hide") {
$action = "hide_host"
} else {
$action = "unhide_host"
if ($action -eq 'hide') {
$action = 'hide_host'
}
else {
$action = 'unhide_host'
}

if (!$aid) {
$Message = "AID not found on machine. Unable to ${action} host without AID, this may be due to the sensor not being installed or being partially installed."
Write-FalconLog "HostVisibilityError" $Message
Write-FalconLog 'HostVisibilityError' $Message
throw $Message
}

$Body = @{
"ids" = @($aid)
'ids' = @($aid)
}

$bodyJson = $Body | ConvertTo-Json
Expand All @@ -279,7 +269,7 @@ begin {
if ($content.errors) {
$Message = "Error when calling ${action} on host: "
$Message += Format-FalconResponseError -errors $content.errors
Write-FalconLog "HostVisibilityError" $Message
Write-FalconLog 'HostVisibilityError' $Message
throw $Message
}
else {
Expand All @@ -292,21 +282,21 @@ begin {

if (!$response) {
$Message = "Unhandled error occurred while performing action '${action}' on host from the CrowdStrike Falcon API. Error: $($_.Exception.Message)"
Write-FalconLog "HostVisibilityError" $Message
Write-FalconLog 'HostVisibilityError' $Message
throw $Message
}

if ($response.StatusCode -eq 409) {
$Message = "Received a $($response.StatusCode) response from ${url} Error: $($response.StatusDescription)"
Write-FalconLog "HostVisibilityError" $Message
Write-FalconLog $null "Host already removed from CrowdStrike Falcon"
Write-FalconLog 'HostVisibilityError' $Message
Write-FalconLog $null 'Host already removed from CrowdStrike Falcon'
}
elseif ($response.StatusCode -eq 403) {
$scope = @{
"host" = @("Write")
'host' = @('Write')
}
$Message = Format-403Error -url $url -scope $scope
Write-FalconLog "HostVisibilityError" $Message
Write-FalconLog 'HostVisibilityError' $Message
throw $Message
}
else {
Expand All @@ -329,10 +319,28 @@ process {
$Message = "'CSFalconService' service not found, already uninstalled"
Write-FalconLog 'CheckService' $Message
Write-FalconLog $null $Message
break;
break
}

$UninstallerPath = $null
switch ($UninstallTool) {
'installcache' {
$UninstallerName = 'WindowsSensor*.exe'
$UninstallerPathDir = 'C:\ProgramData\Package Cache'

if (Test-Path -Path $UninstallerPathDir) {
$UninstallerPath = Get-ChildItem -Include $UninstallerName -Path $UninstallerPathDir -Recurse | ForEach-Object { $_.FullName } | Sort-Object -Descending | Select-Object -First 1
} else {
$UninstallerPath = $null
}
}
Default {
$UninstallerName = 'CsUninstallTool.exe'
$UninstallerPath = Join-Path -Path $PSScriptRoot -ChildPath $UninstallerName
}
}

if (-not (Test-Path -Path $UninstallerPath)) {
if (!$UninstallerPath -or (-not (Test-Path -Path $UninstallerPath))) {
$Message = "${UninstallerName} not found. Unable to uninstall without the cached uninstaller or the standalone uninstaller."
Write-FalconLog 'CheckUninstaller' $Message
Write-FalconLog $null $Message
Expand All @@ -359,19 +367,19 @@ process {


$Body = @{}
$Body["client_id"] = $FalconClientId
$Body["client_secret"] = $FalconClientSecret
$Body['client_id'] = $FalconClientId
$Body['client_secret'] = $FalconClientSecret

if ($MemberCid) {
$Body["&member_cid"] = $MemberCid
$Body['&member_cid'] = $MemberCid
}

$BaseUrl, $Headers = Invoke-FalconAuth -BaseUrl $BaseUrl -Body $Body -FalconCloud $FalconCloud
$Headers['Content-Type'] = 'application/json'
}

if ($RemoveHost) {
Invoke-HostVisibility -action "hide"
Invoke-HostVisibility -action 'hide'
}

if ($MaintenanceToken) {
Expand All @@ -390,16 +398,16 @@ process {
$bodyJson = $Body | ConvertTo-Json

try {
$url = "policy/combined/reveal-uninstall-token/v1"
$url = 'policy/combined/reveal-uninstall-token/v1'

$Headers['Content-Type'] = 'application/json'
$response = Invoke-WebRequest -Uri "$($baseUrl)/$($url)" -UseBasicParsing -Method 'POST' -Headers $Headers -Body $bodyJson -MaximumRedirection 0
$content = ConvertFrom-Json -InputObject $response.Content

if ($content.errors) {
$Message = "Failed to retrieve maintenance token: "
$Message = 'Failed to retrieve maintenance token: '
$Message += Format-FalconResponseError -errors $content.errors
Write-FalconLog "GetTokenError" $Message
Write-FalconLog 'GetTokenError' $Message
throw $Message
}
else {
Expand All @@ -412,23 +420,23 @@ process {

if (!$response) {
$Message = "Unhandled error occurred while retrieving maintenance token from the CrowdStrike Falcon API. Error: $($_.Exception.Message)"
Write-FalconLog "GetTokenError" $Message
Write-FalconLog 'GetTokenError' $Message
throw $Message
}

if ($response.StatusCode -eq 403) {
$scope = @{
'Sensor update policies' = @("Write")
'Sensor update policies' = @('Write')
}

$Message = Format-403Error -url $url -scope $scope

Write-FalconLog "GetTokenError" $Message
Write-FalconLog 'GetTokenError' $Message
throw $Message
}
else {
$Message = "Received a $($response.StatusCode) response from $($baseUrl)$($url) Error: $($response.StatusDescription)"
Write-FalconLog "GetTokenError" $Message
Write-FalconLog 'GetTokenError' $Message
throw $Message
}
}
Expand All @@ -449,32 +457,32 @@ process {
else {
$Message = "Uninstaller returned exit code $($UninstallerProcess.ExitCode)"
}
Write-FalconLog "UninstallError" $Message
Write-FalconLog 'UninstallError' $Message
Write-FalconLog $null $Message

if ($RemoveHost) {
Write-FalconLog $null "Uninstall failed, attempting to restore host visibility..."
Invoke-HostVisibility -action "show"
Write-FalconLog $null 'Uninstall failed, attempting to restore host visibility...'
Invoke-HostVisibility -action 'show'
}
throw $Message
}

$AgentService = Get-Service -Name CSAgent -ErrorAction SilentlyContinue
if ($AgentService -and $AgentService.Status -eq 'Running') {
$Message = 'Service uninstall failed...'
Write-FalconLog "ServiceError" $Message
Write-FalconLog 'ServiceError' $Message
throw $Message
}

if (Test-Path -Path HKLM:\System\Crowdstrike) {
$Message = 'Registry key removal failed...'
Write-FalconLog "RegistryError" $Message
Write-FalconLog 'RegistryError' $Message
throw $Message
}

if (Test-Path -Path"${env:SYSTEMROOT}\System32\drivers\CrowdStrike") {
$Message = 'Driver removal failed...'
Write-FalconLog "DriverError" $Message
Write-FalconLog 'DriverError' $Message
throw $Message
}

Expand Down