Question

Worklet? Crowdstrike Uninstall to Move Asset to another Crowdstrike Console

  • 10 April 2024
  • 1 reply
  • 24 views

Badge

We’ve just set up 2 extra Crowdstrike consoles to allow segregation of assets and users. However, I’m struggling to find a way to move these assets in bulk, as I need to uninstall the sensor on each asset, and then reinstall with a different Customer ID.

 

Does anyone think this would be possible via a couple of worklets? Otherwise I’m looking at a huge manual job… Thanks!


1 reply

Userlevel 5
Badge +1

@james.whiting.gsl  I’d log into their support portal and grab a copy of CsUninstallTool.exe

It has been awhile since I’ve used this, so if you run into a snag let me know!

 

# Evaluation

$cs = get-service csagent -ErrorAction SilentlyContinue
IF($cs)
{
Exit 1
}
else
{
Exit 0
}

# Remediation

$log = 'C:\windows\temp\crowdstrike-removal.log'
Start-Process CsUninstallTool.exe -argumentlist "/quiet /log $log"
Start-Sleep -Seconds 120
$cs = get-service csagent -ErrorAction SilentlyContinue
IF($cs)
{
write-output "Something went wrong with uninstall."
IF(!(Test-Path C:\windows\temp\CsUninstallTool.exe)){ Copy-Item .\CsUninstallTool.exe C:\windows\temp\CsUninstallTool.exe }
IF(Test-Path $log){
Get-Content $log
}else{
Write-output "Unable to locate $log"
}
# Installed Software
$scriptblock = {
$Paths = @("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall","SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
ForEach($Path in $Paths) {

Write-Verbose "Checking Path: $Path"

# Create an instance of the Registry Object and open the HKLM base key
#Try { $reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer,'Registry64') } Catch { Write-Error $_ ; Continue }
Try { $reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer,'Registry64') } Catch { Continue }
# Drill down into the Uninstall key using the OpenSubKey Method

Try {

$regkey=$reg.OpenSubKey($Path)

# Retrieve an array of string that contain all the subkey names
$subkeys=$regkey.GetSubKeyNames()

# Open each Subkey and use GetValue Method to return the required values for each
ForEach ($key in $subkeys){
Write-Verbose "Key: $Key"
$thisKey=$Path+"\\"+$key
Try {

$thisSubKey=$reg.OpenSubKey($thisKey)

# Prevent Objects with empty DisplayName
$DisplayName = $thisSubKey.getValue("DisplayName")

If ($DisplayName -AND $DisplayName -notmatch '^Update for|rollup|^Security Update|^Service Pack|^HotFix') {

$Date = $thisSubKey.GetValue('InstallDate')
#If ($Date) { Try { $Date = [datetime]::ParseExact($Date, 'yyyyMMdd', $Null) } Catch { Write-Warning "$($Computer): $_ <$($Date)>"; $Date = $Null } }
If ($Date) { Try { $Date = [datetime]::ParseExact($Date, 'yyyyMMdd', $Null) } Catch { $Date = $Null } }
# Create New Object with empty Properties
$Publisher = Try { $thisSubKey.GetValue('Publisher').Trim() } Catch { $thisSubKey.GetValue('Publisher') }
$Version = Try {
#Some weirdness with trailing [char]0 on some strings
$thisSubKey.GetValue('DisplayVersion').TrimEnd(([char[]](32,0)))
} Catch { $thisSubKey.GetValue('DisplayVersion') }
$UninstallString = Try { $thisSubKey.GetValue('UninstallString').Trim() } Catch { $thisSubKey.GetValue('UninstallString') }
$InstallLocation = Try { $thisSubKey.GetValue('InstallLocation').Trim() } Catch { $thisSubKey.GetValue('InstallLocation') }
$InstallSource = Try { $thisSubKey.GetValue('InstallSource').Trim() } Catch { $thisSubKey.GetValue('InstallSource') }
$HelpLink = Try { $thisSubKey.GetValue('HelpLink').Trim() } Catch { $thisSubKey.GetValue('HelpLink') }

$Object = [pscustomobject]@{
Computername = $env:COMPUTERNAME
DisplayName = $DisplayName
Version = $Version
InstallDate = $Date
Publisher = $Publisher
UninstallString = $UninstallString
InstallLocation = $InstallLocation
InstallSource = $InstallSource
HelpLink = $thisSubKey.GetValue('HelpLink')
EstimatedSizeMB = [decimal]([math]::Round(($thisSubKey.GetValue('EstimatedSize')*1024)/1MB,2))
}
$Object.pstypenames.insert(0,'System.Software.Inventory')
Write-Output $Object
}

} Catch { Write-Warning "$Key : $_" }
}
} Catch {}
$reg.Close()
} # end IF Paths
}
# Run the scriptblock and store results in the $64bit variable
$softwares = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock | where DisplayName -eq 'Crowdstrike Sensor Platform'

foreach ($software in $softwares)
{
IF($software){
Write-Output "Currently $($software.Displayname) version $($software.Version) Installed. Attempting removal with Msiexec "
IF($software.UninstallString -match 'WindowsSensor.x64'){
$e = ($software.UninstallString).split('"')[1]
Write-Output "Running $e /uninstall /quiet"
Start-Process $e -ArgumentList "/uninstall /quiet"
}
Write-Output "Extracting Uninstall string from $($software.UninstallString)"
$UninstallString = $software.UninstallString | Select-String -Pattern '{[-0-9A-F]+?}' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value
Start-Process MsiExec -ArgumentList "/X $UninstallString /qn" -Wait
$cs = get-service csagent -ErrorAction SilentlyContinue
IF($cs){
Write-Output "Failed to remove Crowdstrike using MSIExec."
$events = Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='MSIInstaller'
} -MaxEvents 10 | Where-Object Message -match "Crowdstrike"
ForEach($event in $events){
Write-Output "$($event.TimeCreated) >> $($event.Message)"
}
}else{ Write-Output "Removed Crowdstrike with MSIExec. "}
}else{
Write-Output "Did not detect Crowdstrike as installed software in registry."
}
}
}
else
{
write-output "Falcon Agent removed"
}

 

Reply