Búsqueda de sitios web

Observando al Vigilante con PowerShell


Comprobando la tarea

Es bastante sencillo utilizar Get-ScheduledTask para verificar el estado.

Si se detuvo, puedo usar Start-ScheduledTask. Naturalmente, no quiero acordarme de ejecutar esto varias veces al día, así que adopté un enfoque ligeramente diferente usando mi script de perfil de PowerShell. Como siempre tengo una sesión de PowerShell abierta, me pareció una idea inteligente. Lo primero que hago al iniciar sesión es abrir una sesión de PowerShell. En el script de mi perfil de PowerShell agregué este código.

$task = Get-ScheduledTask -taskname DailyWatcher
if ($Task.state -eq 'Ready') {
    Write-Host "Restarting scheduled task $($task.Taskname)" -ForegroundColor yellow
    $task | Start-ScheduledTask
}

Me doy cuenta de que esto sólo se ejecuta una vez cada pocos días, pero es algo. Sin embargo, debido a que mi sesión de PowerShell se ejecuta prácticamente constantemente, puedo crear un suscriptor de eventos que observe el cambio de la tarea programada.

Monitoreando al Vigilante

Si recuerda artículos anteriores, un suscriptor de evento solo dura mientras su sesión de PowerShell esté abierta. Por eso creé la suscripción a DailyWatcher en una tarea programada que se ejecuta constantemente. Dado que mi sesión de PowerShell está abierta casi con la misma frecuencia, puedo crear un suscriptor de evento interactivo. Si reinicio PowerShell, simplemente obtendré una nueva versión del suscriptor del evento. En el script de mi perfil agregué estas líneas:

#create the event subscription to monitor the scheduled task
. C:\scripts\MonitorDailyWatcher.ps1 | Out-Null

Echemos un vistazo a este guión.

#requires -version 5.1 
#requires -module CimCmdlets

#verify the scheduled task exists and bail out if it doesn't.
$name = "DailyWatcher"
Try {
    $task = Get-ScheduledTask -TaskName $Name -ErrorAction Stop
}
catch {
    Throw $_
    #make sure we bail out
    return
}

#if by chance the task is not running, go ahead and start it.
if ($task.State -ne 'running') {
    $task | Start-ScheduledTask
}

<#
the scheduled task object is of this CIM type
Microsoft.Management.Infrastructure.CimInstance#Root/Microsoft/Windows/TaskScheduler/MSFT_ScheduledTask
#>


$query = "Select * from __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'MSFT_ScheduledTask' AND TargetInstance.TaskName='$Name'"
$NS = 'Root\Microsoft\Windows\TaskScheduler'

#define a scriptblock to execute if the event fires
$Action = {
 $previous =  $Event.SourceEventArgs.NewEvent.PreviousInstance
 $current =  $Event.SourceEventArgs.NewEvent.TargetInstance
 if ($previous.state -eq 'Running' -AND $current.state -ne 'Running') {
    Write-Host "[$(Get-Date)] Restarting the DailyWatcher task" -ForegroundColor green
    Get-ScheduledTask -TaskName DailyWatcher | Start-ScheduledTask
 }
}
Register-CimIndicationEvent -SourceIdentifier "TaskChange" -Namespace $NS -query $query -MessageData "The task $Name has changed" -MaxTriggerCount 7 -Action $action

El script está escrito para ser independiente de mi perfil de PowerShell. Primero verifica que exista una tarea programada y sale con un error si no la encuentra. El script también iniciará la tarea si no se está ejecutando. Ahora viene lo bueno.

Una forma de crear un suscriptor de evento es a través de WMI. Siempre hemos podido configurar algo para observar cambios en una instancia de algo de WMI. Pero como considero que los cmdlets específicos de WMI están obsoletos, usaré los comandos equivalentes de CIM. El comando para crear la suscripción al evento es Register-CimIndicationEvent. El elemento clave es la consulta.

$query = "Select * from __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'MSFT_ScheduledTask' AND TargetInstance.TaskName='$Name'"

La referencia __InstanceModificationEvent es a una clase de sistema que debería existir en todos los espacios de nombres. Esta clase debería activar un evento cada vez que se realicen cambios en un tipo específico de objeto. En mi consulta, esto se especifica mediante la propiedad TargetInstance y el operador ISA. Si el objeto modificado es una ScheduledTask, que descubrí conectando Get-ScheduledTask a Get-Member, y si el nombre de la tarea programada específica coincide con mi tarea, se generará un evento. desencadenado y manejado por el suscriptor del evento. La otra parte muy importante de esta consulta es la encuesta. En la consulta solicito que se me notifique dentro de 10 segundos de un cambio. En otras palabras, verifique cada 10 segundos. Desea que este número sea lo suficientemente pequeño como para satisfacer sus necesidades, pero no tan pequeño como para terminar realizando encuestas constantemente.

El otro elemento de mi script es el bloque de script de acción. Cuando se activa un evento, parte de los argumentos del evento son referencias a la instancia anterior del objeto y a la instancia nueva o de destino. Esto resulta útil cuando quiero hacer algo basado en una diferencia de propiedad que es más o menos lo que estoy haciendo. Si la instancia anterior se estaba ejecutando y la nueva instancia no se está ejecutando, iniciaré la tarea programada. Es realmente así de simple.

Cuando se ejecuta mi perfil, termino con este suscriptor del evento.

Si la tarea se detiene, el suscriptor del evento ejecuta el bloque de script de acción, que, tal como está escrito, muestra un mensaje usando Write-Host en mi sesión de PowerShell.

No espero que esto suceda con frecuencia, si es que sucede. Este código es más como un seguro para mí.

Crear una suscripción a eventos basada en CIM puede ser una herramienta de gestión útil. Recomiendo empezar de forma sencilla y asegurarse de leer la ayuda completa y los ejemplos.

Volveré la próxima vez con otras cosas divertidas derivadas de mi trabajo de respaldo de PowerShell.

Artículos relacionados