Currently we help companies protecting their devices. Some of them are willing to shift to other AV products like Microsoft Windows Defender.
The challenge in these operations is to monitor the state of Antivirus products while and after reconfiguring. Together with the help of the great support team of Defender I could build a solution to this problem. To help others and working consistently I have putted the findings in a new PowerShell Module that is available for anyone from PowerShell Gallery and or GitHub.
Let me explain first why we need this Modules and or PowerShell cmdlets.
For PowerShell and Windows Defender there is the perfectly fine Get-MPComputerStatus. And while the description of this cmdlet states: “This command gets the status of antimalware protection software installed on the computer.” to my finding it doesn’t provide that a generic status.
If I run this cmdlet while a Non-Microsoft antivirus product is installed and active the output looks as:
So can we check for the current state of any Antivirus product installed using a different approach?
From a user perspective we can monitor the current state via opening the custom protocol handler that is implemented by Windows Defender
windows windowsdefender://providers/ this is an easy way to open the correct dialog directly.
For the sake of this demonstration I installed 2 additional Antivirus Products. In this dialog you can see the current security products that are installed and monitored by Windows Security Center. Their respectively status is shown.
My goal is to gather this information by using PowerShell.
Specifically for antivirus products we can execute the following command to gather the information:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-CimInstance –Namespace root/SecurityCenter2 –ClassName AntivirusProduct |
If you don’t have access to the CimInstance or WMI you could also try:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Get-ChildItem –Path "HKLM:\SOFTWARE\Microsoft\Security Center\Provider\Av" | Get-ItemProperty |
In the returned objects you will find the following fields
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
displayName : Windows Defender | |
instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} | |
pathToSignedProductExe : windowsdefender:// | |
pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe | |
productState : 393472 | |
timestamp : Wed, 01 Apr 2020 16:56:49 GMT | |
PSComputerName : |
For registry this looks as:
Among others there is this productState (or STATE) value.
This value contains information about the statuses of the product.
By using the right equations you could also determine other statuses, for example if it is up-to-date.
On docs pages there is some documentation about the interface and actual api that exposes this information.
We can find out that the api exposes information about:
Enumerations
Title | Description |
---|---|
WSC_SECURITY_PRODUCT_STATE | Defines the current state of the security product that is made available to Windows Security Center. |
WSC_SECURITY_SIGNATURE_STATUS | Reports the current version status of the security product to Windows Security Center. |
I couldn’t find any publicly available information about these Enumerations from Microsoft but there are others that gained some information from the W10 SDK.
From MS support we received confirmation that the productState bitmask flag is 0x0000F000 and the value for Enable should be 0x1000.
The value is set using Bit Fields, this is an object member which contains multiple members that stores the information in just a couple of bits.
More information about this: https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields
Using bitwise operators and some help from Microsoft Support we could figure out how we can determine the product status by using one equation.
I have made some PowerShell Enumerators to help creating readable code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Flags()] enum ProductState | |
{ | |
Off = 0x0000 | |
On = 0x1000 | |
Snoozed = 0x2000 | |
Expired = 0x3000 | |
} | |
[Flags()] enum SignatureStatus | |
{ | |
UpToDate = 0x00 | |
OutOfDate = 0x10 | |
} | |
[Flags()] enum ProductOwner | |
{ | |
NonMs = 0x000 | |
Windows = 0x100 | |
} | |
[Flags()] enum ProductFlags | |
{ | |
SignatureStatus = 0x000000F0 | |
ProductOwner = 0x00000F00 | |
ProductState = 0x0000F000 | |
} |
Using this information I wrote this little function that will return true of false.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Test-IsProductStateOn { | |
<# | |
.SYNOPSIS | |
Tests if given product state has product state flag to On | |
.DESCRIPTION | |
Registry, WMI and other properties may contain a DWORD value or data object that represents the state of the corresponding product. | |
Specific state of the product is set to a bit in this DWORD, these states can be optained using bitwise operations. | |
This function will return true if the flag for product state is set to on, meaning this product is enabled. | |
.PARAMETER ProductState | |
The value (DWORD) containing the bitflags. | |
.EXAMPLE | |
PS C:\> Test-IsProductStateOn -ProductState 393472 | |
False | |
This example shows basic functionality | |
.OUTPUTS | |
Bool | |
.NOTES | |
This function was build to resolve the state of a Antivirus Provider registered in Security Center. | |
Using this function it is possible to read which product is set to On or not. | |
Other states are Off, Snoozed and Expired which can be resolved by using the enums provided in this module. | |
Example: Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | Where-Object {($_.productState -band [ProductFlags]::ProductState) -eq [ProductState]::Off} | |
Will list all products that are disabled. | |
Use Add-ProductStates to return the actual state or cast the value using the stateflag | |
$prod = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | |
[SignatureStatus]($prod[0].productState -band [ProductFlags]::SignatureStatus) | |
#> | |
[CmdletBinding()] | |
param ( | |
# Product State contains a value (DWORD) that contains multiple bitflags and we use the productState flag (0000F000) | |
[Parameter(Mandatory, Position = 0, ValueFromPipelineByPropertyName, HelpMessage = "The value (DWORD) containing the bitflags.")] | |
[Alias("STATE")] | |
[UInt32]$ProductState | |
) | |
try | |
{ | |
if( $([ProductState]::On -and $($ProductState -band [ProductFlags]::ProductState) ) ) | |
{ | |
return $true | |
} | |
else | |
{ | |
return $false | |
} | |
} | |
catch | |
{ | |
return $false | |
} | |
} |
As you can see in the Enumerators list, Enable isn’t the only status these products can have, also Snooze is a state. In that case we will return false too ofcourse.
It is possible to return the actual state that a given product currently is in. Bear in mind productState has multiple members. That is why we need to set a Bitmask to retrieve the correct state.
To help out others and to work consistent among different scripts and projects I added some functions and enumerators to the PowerShell Module.
In 1 line of PowerShell code you can make use of this function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Install-Module wrt.helpers –Scope CurrentUser –Force | |
Test-IsProductStateOn 39756 |
TIP: Have a look at the function Add-ProductStates, this accepts array of products and adds members state and signatureStatus
I you have any requests or issues for this Module please let me know in this post or post an issue on the GitHub page.