DaveWentzel.com            All Things Data

Programmatically Determining if Antivirus Is Running

Some corporate AV management tools (EPO for example) don't report when certain other vendors' AV software is installed/running.  Who cares?  Well, many software packages just won't install depending on your AV settings.  For instance, the SQL Server FILESTREAM functionality will actually hang the machine if certain AV products are installed.  Here is the connect bug I filed on the issue.  Where I work we actually install SQL Server as part of our product's installation routine so we can't guarantee what AV product the customer has installed.  You might think it would be simple to determine if AV is installed/running (a PowerShell script, a reg key, WMI query, etc)...well, you'd be wrong.  Here is what I learned and a little script that pieces it all together. 

If the AV vendor registers their product with Windows Security Center then either \root\SecurityCenter or \root\SecurityCenter2 will be populated.  SecurityCenter will be populated for older OSs/AV products.  Newer versions should be against SecurityCenter2.  The best practice is to query 'both namespaces.  This is poorly documented by design (see Implementing the Teredo Security Model at http://msdn.microsoft.com/en-us/library/bb190942(VS.85).aspx).  This will only work on client OSs, not server OSs.  Not sure what to do there. 

The script below tries to handle these permutations as nicely as possible.  It is vbscript but could be rewritten as PowerShell very easily.  If you are scared of scripting there is a wmic command that does the equivalent directly from a command prompt:

wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName,productState /Format:List

wmic /NAMESPACE:\\root\SecurityCenter PATH AntiVirusProduct Get displayName,enableOnAccessUIMd5Hash,onAccessScanningEnabled /Format:List

One last note, it appears as though some AV products, even when disabled and apparently uninstalled, will report back as being enabled.  I'm guessing this is because the settings are inherited from a corporate AV server, but I haven't found any additional information on this. 
Dim args, objWMIService_AV, colItems, objAntiVirusProduct,strcompanyName,strdisplayName,strVersionNumber,strproductState,colItems2,PathToSignedProductExe
Dim colFiles,itemFile,strRunType, strFinalMessage
'get the arguments
Set args = Wscript.Arguments
If args.count = 1 Then
    strRunType = args(0)
    'double-clicked the .vbs file
    strRunType = "MsgBox"
End If
Echo "  AV - Security Center Settings...if FILESTREAM hangs the machine and there are AV entries then we should consider"
Echo "  disabling AV or setting master.dbo.PCMXOPTIONS NOFILESTREAMSUPPORT to 'TRUE'"
Set objWMIService_AV = GetObject("winmgmts:\\.\root\SecurityCenter")
if err.number <> 0 Then
    Echo "      No AV registered to \root\SecurityCenter"
    Set colItems = objWMIService_AV.ExecQuery("Select * from AntiVirusProduct")
    For Each objAntiVirusProduct In colItems
        Echo "      WARNING:  AV products registered to \root\SecurityCenter"
        strcompanyName = (objAntiVirusProduct.companyName)
        strdisplayName = (objAntiVirusProduct.displayName)
        strVersionNumber = (objAntiVirusProduct.versionNumber)
        strproductState = (objAntiVirusProduct.onAccessScanningEnabled)
        Echo "      companyName:    " & strcompanyName
        Echo "      displayName:    " & strdisplayName
        Echo "      versionNumber:  " & strVersionNumber
        Echo "      onAccessScanningEnabled:    " & strproductState
    Set objWMIService_AV = Nothing
End If
Set objWMIService_AV = GetObject("winmgmts:\\.\root\SecurityCenter2")
If err.number <> 0 Then
    Echo "     No AV registered to \root\SecurityCenter2"
    Set colItems2 = objWMIService_AV.ExecQuery("Select * from AntiVirusProduct")
    For Each objAntiVirusProduct In colItems2
        PathToSignedProductExe = Replace(objAntiVirusProduct.PathToSignedProductExe,"\","\\")
        echo ("      Path " & PathToSignedProductExe)
        Set colFiles = objWMIService.ExecQuery ("Select * from CIM_Datafile Where name = '" & PathToSignedProductExe & "'",,48)
        For Each itemFile In colFiles 
            strcompanyName  = (itemFile.Manufacturer)
            strVersionNumber = (itemFile.Version)
            strdisplayName = (objAntiVirusProduct.displayName) 
            if (objAntiVirusProduct.ProductState = "266240" OR objAntiVirusProduct.ProductState = "266256") then 
                strproductState = "Scanning Enabled"
            Elseif (objAntiVirusProduct.ProductState = "262144") Then
                strproductState = "Scanning Not Enabled"
                strproductState = "Unknown State"
            End If
            Echo "      WARNING:  AV products registered to \root\SecurityCenter2"
            Echo "      strcompanyName: " & strcompanyName
            Echo "      strdisplayName: " & strdisplayName
            Echo "      strVersionNumber:   " & strVersionNumber
            Echo "      strproductState:    " & strproductState
End If
'Final Cleanup
Call FinalCleanup
On Error Goto 0
Public Sub Echo (msg)
    If strRunType = "MsgBox" Then
        strFinalMessage = strFinalMessage & vbCRLF & msg
    ElseIf UCASE(strRunType) = "ECHO" Then
        wscript.Echo msg
    ElseIf UCASE(strRunType) = "INSTALLER" Then
    End If
End Sub
Public Sub FinalCleanup
    If strRunType = "MsgBox" Then
        msgbox strFinalMessage
    End If
End Sub


Set colFiles = objWMIService.ExecQuery ("Select * from CIM_Datafile Where name = '" & PathToSignedProductExe & "'",,48) Thought I'd point out the typo. Thank you for posting your code, and I've enjoyed and found your blog immensely helpful! Set colFiles = objWMIService_AV.ExecQuery ("Select * from CIM_Datafile Where name = '" & PathToSignedProductExe & "'",,48)