Featured image of post Monitoring with PowerShell: Monitoring Bitdefender status

Monitoring with PowerShell: Monitoring Bitdefender status

We’re considering moving RMM systems, and that means reevaluating parts of our stack. One of the pain points in our current stack is the monitoring of anti-virus, we often felt like there is not enough transparency and data returned via our RMM system. Either the system does not return the current state of alerts or forces us to use separate portals.

So I’ve built this for any potential RMM system, decreasing the need to switch a lot between applications, get alerted earlier and allow reporting directly from the RMM system on any threats you’ve encountered.

Quarantine monitoring

To monitor the quarantine we grab the information from the SQLLite Database that Bitdefender creates. To do that we’ll need to download the SQLLite dll that allows us access via Powershell. Remember to host this yourself somewhere. 🙂

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
if (!$SQLLite) {
    Invoke-WebRequest -uri "https://cyberdrain.com/wp-content/uploads/2021/02/System.Data.SQLite.dll" -UseBasicParsing -OutFile "C:\Programdata\System.Data.SQLite.dll"
}

try {
add-type -path "C:\Programdata\System.Data.SQLite.dll"
}
catch {
Write-Host "Could not load database components."
exit 1
}
$con = New-Object -TypeName System.Data.SQLite.SQLiteConnection
$con.ConnectionString = "Data Source=C:\Program Files\Bitdefender\Endpoint Security\Quarantine\cache.db"
$con.Open()
$sql = $con.CreateCommand()
$sql.CommandText = "select \* from entries"
$adapter = New-Object -TypeName System.Data.SQLite.SQLiteDataAdapter $sql
$data = New-Object System.Data.DataSet
[void]$adapter.Fill($data)
$sql.Dispose()
$con.Close()

$CurrentQ = foreach ($row in $Data.Tables.rows) {
    [PSCustomObject]@{
        Path               = $row.path
        Threat             = $row.threat
        Size               = $row.Size
        'Quarantined On'   = [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($row.quartime))
'Last accessed On' = [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($row.acctime))
        'Last Modified On' = [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($row.modtime))
}
}

if ($CurrentQ) {
write-host $CurrentQ
}
else {
write-host "Healthy - No infections found."
}

Scan Result monitoring

Of course just monitoring the quarantine is not enough, we also want to know the results of each scan and pick that up, For that we have the next script; this checks the last scan XML file for any aberrant behaviour such as infected files or deleted ones.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[xml]$LastScanResult = (get-childitem "C:\Program Files\Bitdefender\Endpoint Security\logs\system" -Recurse -Filter "*.xml" | Sort-Object -Property LastWriteTime | Select-Object -last 1 | get-content -raw)

if (!$LastScanResult) {
    write-host "Unhealthy - could not retrieve last scan result."
    exit 1
}
$ScanResults = [PSCustomObject]@{
    Scanned       = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.Scanned | measure-object -sum).Sum
    Infected      = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.Infected | measure-object -sum).Sum
    suspicious    = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.suspicious | measure-object -sum).Sum
    Disinfected   = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.Disinfected | measure-object -sum).Sum
    Deleted       = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.deleted | measure-object -sum).Sum
    Moved         = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.moved | measure-object -sum).Sum
    Moved_reboot  = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.moved_reboot | measure-object -sum).Sum
    Delete_reboot = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.delete_reboot | measure-object -sum).Sum
    Renamed       = ($LastScanResult.ScanSession.ScanSummary.TypeSummary.renamed | measure-object -sum).Sum
}

$Alertresult = $ScanResults | Select-Object -Property * -ExcludeProperty Scanned | Where-Object { $_.psobject.properties.value -gt 0 }

if ($Alertresult) {
    write-host "Unhealthy - Last scan found issues"
    $ScanResults
}
else {
    write-host "Healthy - Last scan found no issues."
    $ScanResults
}

And that’s it! as always, Happy PowerShelling!

All blogs are posted under AGPL3.0 unless stated otherwise
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy