Obtenga el estado del producto antivirus con PowerShell
Supongo que la mayoría de ustedes con instalaciones antivirus en toda la empresa probablemente tengan herramientas de proveedor para administrar todos sus clientes. Si es así, no te vayas todavía. Aunque voy a demostrar cómo obtener el estado del producto antivirus con PowerShell, las técnicas de secuencias de comandos aún pueden resultar útiles. O puede aprender un poco más sobre WMI y los cmdlets CIM. Permítame comenzar con un comando simple para obtener información antivirus de su computadora local, suponiendo que esté ejecutando PowerShell 3.0 o posterior.
Pruebe este comando:
Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct
En versiones anteriores de Windows, esta información se almacenaba en el espacio de nombres de SecurityCenter. No recuerdo exactamente en qué versión de Windows se cambió a SecurityCenter2, pero espero que esto funcione para usted y vea algo como esto:
En mi computadora, que ejecuta Windows 8.1, puedes ver dos productos. Lo que no se puede saber es el estado de cada producto. Bueno, en realidad puedes, pero necesitas decodificar la propiedad de estado del producto. El primer paso para decodificarlo es convertirlo a hexadecimal.
'0x{0:x}' -f 393472
Convertí el estado de Windows Defender por un valor de 0x60100.
A continuación, podemos observar las dos partes centrales de este valor, 01. Si coincide con '10', entonces el producto está habilitado. Cualquier otra cosa y no lo es. Con esto, puedo ver que Windows Defender no está habilitado. Las 2 últimas partes, 00, indicarán si el producto está actualizado o no. Un valor de 00 significa que está actualizado. Sin embargo, en este caso, creo que esto significa que la última vez que se habilitó este producto estaba actualizado. Ahí es donde creo que la propiedad TimeStamp resulta útil. Al convertir el estado en el producto ESET, obtengo un valor de 0x41000 que se decodifica como habilitado y actualizado.
Una vez que tengo un comando básico, puedo crear una función de PowerShell para convertirlo en una herramienta reutilizable.
Get-AVStatus.ps1:
#requires -version 5.1
Function Get-AVStatus {
<#
.Synopsis
Get anti-virus product information.
.Description
This command uses WMI via the Get-CimInstance command to query the state of installed anti-virus products. The default behavior is to only display enabled products, unless you use -All. You can query by computername or existing CIMSessions.
.Example
PS C:\> Get-AVStatus chi-win10
Displayname : ESET NOD32 Antivirus 9.0.386.0
ProductState : 266256
Enabled : True
UpToDate : True
Path : C:\Program Files\ESET\ESET NOD32 Antivirus\ecmd.exe
Timestamp : Thu, 21 Jul 2016 15:20:18 GMT
Computername : CHI-WIN10
.Example
PS C:\> import-csv s:\computers.csv | Get-AVStatus -All | Group Displayname | Select Name,Count | Sort Count,Name
Name Count
---- -----
ESET NOD32 Antivirus 9.0.386.0 12
ESET Endpoint Security 5.0 6
Windows Defender 4
360 Total Security 1
Import a CSV file which includes a Computername heading. The imported objects are piped to this command. The results are sent to Group-Object.
.Example
PS C:\> $cs | Get-AVStatus | where {-Not $_.UptoDate}
Displayname : ESET NOD32 Antivirus 9.0.386.0
ProductState : 266256
Enabled : True
UpToDate : False
Path : C:\Program Files\ESET\ESET NOD32 Antivirus\ecmd.exe
Timestamp : Wed, 20 Jul 2016 11:10:13 GMT
Computername : CHI-WIN11
Displayname : ESET NOD32 Antivirus 9.0.386.0
ProductState : 266256
Enabled : True
UpToDate : False
Path : C:\Program Files\ESET\ESET NOD32 Antivirus\ecmd.exe
Timestamp : Thu, 07 Jul 2016 15:15:26 GMT
Computername : CHI-WIN81
You can also pipe CIMSession objects. In this example, the output are enabled products that are not up to date.
.Notes
version: 1.1
Learn more about PowerShell:
http://jdhitsolutions.com/blog/essential-powershell-resources/
.Inputs
[string[]]
[Microsoft.Management.Infrastructure.CimSession[]]
.Outputs
[pscustomboject]
.Link
Get-CimInstance
#>
[cmdletbinding(DefaultParameterSetName = "computer")]
Param(
#The name of a computer to query.
[Parameter(
Position = 0,
ValueFromPipeline,
ValueFromPipelineByPropertyName,
ParameterSetName = "computer"
)]
[ValidateNotNullorEmpty()]
[string[]]$Computername = $env:COMPUTERNAME,
#An existing CIMsession.
[Parameter(ValueFromPipeline, ParameterSetName = "session")]
[Microsoft.Management.Infrastructure.CimSession[]]$CimSession,
#The default is enabled products only.
[switch]$All
)
Begin {
Write-Verbose "[BEGIN ] Starting: $($MyInvocation.Mycommand)"
Function ConvertTo-Hex {
Param([int]$Number)
'0x{0:x}' -f $Number
}
#initialize an hashtable of paramters to splat to Get-CimInstance
$cimParams = @{
Namespace = "root/SecurityCenter2"
ClassName = "Antivirusproduct"
ErrorAction = "Stop"
}
If ($All) {
Write-Verbose "[BEGIN ] Getting all AV products"
}
$results = @()
} #begin
Process {
#initialize an empty array to hold results
$AV = @()
Write-Verbose "[PROCESS] Using parameter set: $($pscmdlet.ParameterSetName)"
Write-Verbose "[PROCESS] PSBoundparameters: "
Write-Verbose ($PSBoundParameters | Out-String)
if ($pscmdlet.ParameterSetName -eq 'computer') {
foreach ($computer in $Computername) {
Write-Verbose "[PROCESS] Querying $($computer.ToUpper())"
$cimParams.ComputerName = $computer
Try {
$AV += Get-CimInstance @CimParams
}
Catch {
Write-Warning "[$($computer.ToUpper())] $($_.Exception.Message)"
$cimParams.ComputerName = $null
}
} #foreach computer
}
else {
foreach ($session in $CimSession) {
Write-Verbose "[PROCESS] Using session $($session.computername.toUpper())"
$cimParams.CimSession = $session
Try {
$AV += Get-CimInstance @CimParams
}
Catch {
Write-Warning "[$($session.computername.ToUpper())] $($_.Exception.Message)"
$cimParams.cimsession = $null
}
} #foreach computer
}
foreach ($item in $AV) {
Write-Verbose "[PROCESS] Found $($item.Displayname)"
$hx = ConvertTo-Hex $item.ProductState
$mid = $hx.Substring(3, 2)
if ($mid -match "00|01") {
$Enabled = $False
}
else {
$Enabled = $True
}
$end = $hx.Substring(5)
if ($end -eq "00") {
$UpToDate = $True
}
else {
$UpToDate = $False
}
$results += $item | Select-Object Displayname, ProductState,
@{Name = "Enabled"; Expression = { $Enabled } },
@{Name = "UpToDate"; Expression = { $UptoDate } },
@{Name = "Path"; Expression = { $_.pathToSignedProductExe } },
Timestamp,
@{Name = "Computername"; Expression = { $_.PSComputername.toUpper() } }
} #foreach
} #process
End {
If ($All) {
$results
}
else {
#filter for enabled only
($results).Where( { $_.enabled })
}
Write-Verbose "[END ] Ending: $($MyInvocation.Mycommand)"
} #end
} #end functionDebido a que la función usa Get-CimInstance, la escribí para admitir nombres de computadoras y sesiones CIMS, ya sea como valores de parámetros o mediante canalización. Notará que utilicé varios conjuntos de parámetros para recopilar la información "sin procesar" del producto antivirus de WMI y formatearla con propiedades personalizadas que reflejan la decodificación de ProductState. Al final de la función, los resultados se escriben en la canalización. De forma predeterminada, solo se muestran los productos habilitados, ya que pensé que serían más útiles. Pero puedes ver todo con el parámetro -Todos.
Aquí hay algunas capturas de pantalla del comando en acción.
Finalmente, mientras trabajaba en esto, me topé con una “característica” de PowerShell que no conocía.
Para funciones independientes como ésta, siempre escribo ayuda basada en comentarios. Normalmente incluyo una sección de Parámetros para cada uno. Al principio no lo hice, aunque en el código agregué un comentario a uno de los parámetros.
#The default is enabled products only.
[switch]$All
Cuando ejecuté la ayuda completa me sorprendió ver este texto.
¡¡Impresionante!! Agregué un comentario similar para el otro parámetro en el bloque Param. Supongo que si quisiera proporcionar información detallada sobre los parámetros, usaría la sección .Parameter en la ayuda basada en comentarios. Pero como normalmente solo necesito una descripción rápida, ponerla en el bloque Param me facilita las cosas.
Así que ahí está. Una función de PowerShell relativamente simple que utiliza WMI y CIM para recuperar información de computadoras remotas. Podrías usarlo como marco para prácticamente cualquier clase WMI. Todo lo que necesitaría hacer es modificar el espacio de nombres, el nombre de la clase y las propiedades de salida. De hecho esto me da una idea pero eso tendré que esperar para otro día.
Si tiene algún problema con la función, publique un comentario en la esencia de GitHub.
Disfrutar.