I expect that most of you with enterprise-wide antivirus installations probably have vendor tools for managing all of your clients. If so, don't go away just yet. Even though I'm going to demonstrate how to get antivirus product status with PowerShell, the scripting techniques might still be useful. Or you might learn a bit more about WMI and the CIM cmdlets. Let me start with a simple command to get antivirus information from your local computer, assuming you are running PowerShell 3.0 or later.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Try this command:
Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct
In earlier versions of Windows, this information was stored in the SecurityCenter namespace. I don't recall exactly which version of Windows where this changed to SecurityCenter2 but hopefully this works for you and you see something like this:
On my computer, which is running Windows 8.1, you can see two products. What you can't tell is the status of each product. Well, actually you can but you need to decode the product state property. The first step to decode it is to convert it to hex.
'0x{0:x}' -f 393472
I converted the Windows Defender status for a value of 0x60100.
Next, we can look at the middle two parts of this value, 01. If this matches '10' then the product is enabled. Anything else and it is not. With this, I can see that Windows Defender is not enabled. The last 2 parts, 00, will indicate if the product is up to date or not. A value of 00 means it is up to date. However, in this case, I think this means that the last time this product was enabled it was up to date. That's where I think the TimeStamp property comes in handy. Converting the status on the ESET product gives me a value of 0x41000 which decodes as enabled and up to date.
Once I have a basic command I can build a PowerShell function to turn it into a reusable tool.
Because the function uses Get-CimInstance I wrote it to support computer names and CIMSessions either as parameter values or via the pipeline. You'll notice that I used multiple parameter sets to collect the "raw" antivirus product information from WMI and format it with custom properties that reflect decoding the ProductState. At the end of the function, the results are written to the pipeline. By default only enabled products are displayed since I figured that would be more useful. But you can see everything with the -All parameter.
Here are a few screenshots of the command in action.
Finally, as I was working on this I stumbled across a� PowerShell "feature" I didn't know about.
For stand-alone functions like this one, I always write comment-based help. I usually include a Parameter section for each one. Initially, I did not, although in the code I added a comment to one of the parameters.
#The default is enabled products only. [switch]$All
When I ran full help I was amazed to see this text.
Awesome!! I added a similar comment for the other parameter in the Param block. I suppose if I wanted to provide extensive parameter information I'd use the .Parameter section in comment-based help. But since usually I only need a quick description putting it in the Param block makes things easier for me.
So there it is. A relatively simple PowerShell function using WMI and CIM to retrieve information from remote computers. You could use it as a framework for practically any WMI class. All you would need to do is modify the namespace, class name, and output properties. In fact, this gives me an idea but that will have to wait for another day.
If you run into any issues with the function, please post a comment on the GitHub gist.
Enjoy.