¿Gráfico de Windows Task Scheduler?

4

¿Alguien sabe si hay alguna herramienta / utilidad que pueda hacer un gráfico de todas las tareas en el Programador de tareas de Windows en función de la fecha y la hora, por lo que sabré si hay alguna superposición en cierto punto de tiempo que cause la sobrecarga del servidor?

Tenemos un servidor para todas las tareas programadas y últimamente se está ejecutando lentamente debido al mal diseño realizado por el ex administrador, ahora necesito encontrar una ventana de ejecución para cada tarea, puedo hacer el gráfico manualmente en Excel pero es simplemente demasiado mucho que pasar por uno por uno

Esperemos que haya algunas utilidades que puedan hacer esto.

Root Loop
fuente
alguna idea chicos? Parece que no hay tal zumbido de utilidad ...
Root Loop
Para crear un gráfico de este tipo (GANTT), es probable que no solo necesite la hora de inicio, sino también la hora de finalización o la duración de cada tarea. Esta información no está disponible por adelantado bajo Windows. Por lo tanto, si conoce la duración de la experiencia, deberá reunir los datos para una herramienta de gráficos externa como sourceforge.net/projects/ganttproject
Axel Kemper
Gracias, intenté algo similar a esto, no es exactamente lo que estoy buscando. Creo que es mejor hacerlo yo mismo en excel.
Root Loop

Respuestas:

2

Este script de Powershell leerá el registro de eventos del programador de tareas y lo exportará a CSV Task Name, Start Date, Finish Date y Duration Para todas las tareas que se lanzaron. Luego, puede enviar estos datos a la hoja de cálculo de su elección y construir un diagrama GANTT.

Requisitos:

  • PowerShell 2.0
  • Windows Server 2008 \ Vista

Script acepta los siguientes argumentos:

  • Ordenadores : matriz de nombres de computadora para consultar. Si no se especifica, se consultará la computadora local.
  • MaxEventos : Cantidad máxima de eventos para leer del registro de eventos. El valor predeterminado es 100.
  • Camino : carpeta existente en el disco, donde se guardarán los CSV. Si no se especifica, se utilizará la carpeta de script. Los CSV se nombran así: COMPUTERNAME_TaskScheduler.csv.
  • Usuario : Nombre de usuario para autenticación remota.
  • Contraseña : Contraseña para el usuario. Si no se especifica, será solicitado por el script.
  • Verboso : guión le dirá lo que está pasando a través de Write-Verbose mensajes

Ejemplos (ejecutados desde la consola de PowerShell):

Obtenga datos de la computadora local, procese los últimos 100 eventos, guarde el archivo CSV en la carpeta del script:

.\TS_Gantt.ps1

Obtenga datos de computadoras remotas, procese los últimos 200 eventos, guarde archivos CSV en el c:\ts_gantt carpeta:

.\TS_Gantt.ps1 -Computers Sun, Earth, Moon -MaxEvents 200 -Path 'c:\ts_gantt'

Guión ( TS_Gantt.ps1 ):

Param
(
    [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
    [ValidateNotNullOrEmpty()]
    [string[]]$Computers = $env:COMPUTERNAME,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateRange(1, 2147483647)]
    [int]$MaxEvents = 100,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateScript({
        if(!(Test-Path -LiteralPath $_ -PathType Container))
        {
            throw "Folder doesn't exist: $_"
        }
        $true
    })]
    [ValidateNotNullOrEmpty()]
    [string]$Path,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [ValidateNotNullOrEmpty()]
    [string]$User,

    [Parameter(ValueFromPipelineByPropertyName = $true)]
    [string]$Password

)

# Get script path, to save CSV's, if not specified
if(!$Path)
{
    if($psISE.CurrentFile.FullPath)
    {
        $Path = $psISE.CurrentFile.FullPath | Split-Path
    }
    elseif($script:MyInvocation.MyCommand.Path)
    {
        $Path = $script:MyInvocation.MyCommand.Path | Split-Path
    }
    else
    {
        $Path = $PWD.Path
    }

    Write-Verbose "No Path specified, defaulting to: $Path"
}

# Get user credentials, if needed
if($User)
{
    Write-Verbose "User specified: $User"
    if($Password)
    {
        Write-Verbose 'Password specified, converting to credentials object'
        $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force
        $Credentials =  New-Object System.Management.Automation.PSCredential -ArgumentList $User, $SecurePassword
    }
    else
    {
        Write-Verbose 'Password not specified, requesting from user.'
        $Credentials = Get-Credential -UserName $User -Message "Enter password for user: $User" -ErrorAction Stop
        if(!$Credentials)
        {
            Write-Verbose 'User cancelled password request'
        }
    }
}

# https://mnaoumov.wordpress.com/2014/05/15/task-scheduler-event-ids/
$TaskStartId = 100
$TaskFinishId = 102
$FilterXml = @"
<QueryList>
  <Query Id="0" Path="Microsoft-Windows-TaskScheduler/Operational">
    <Select Path="Microsoft-Windows-TaskScheduler/Operational">*[System[(EventID=$TaskStartId or EventID=$TaskFinishId)]]</Select>
  </Query>
</QueryList>
"@

# Hashtable to hold results
$Result = @{}

# Loop through computers
foreach ($PC in $Computers){

    # Grab the events from a PC
    $Params = @{
        ComputerName = $PC
        FilterXml = $FilterXml
        MaxEvents = $MaxEvents
    }

    if($Credentials)
    {
        $Params += @{Credential = $Credentials}
    }

    Write-Verbose "Trying to get Task Scheduler's event log. Computer: $PC"
    try
    {
        $Events = Get-WinEvent @Params -ErrorAction Stop
        Write-Verbose "Success"
    }
    catch
    {
        Write-Error "Can't access Task Scheduler's event log. Computer: $PC"
        continue
    }

    if(!$Events)
    {
        Write-Error "Task Scheduler's event log is empty! Computer: $PC"
        continue
    }

    Write-Verbose 'Extracting additional data from events'
    $Events |
        ForEach-Object {
            # Hashtable for new properties
            $Properties = @{}

            # Convert the event to XML and iterate through each one       
            # of the XML message properties to extract additional data  
            ([xml]$_.ToXml()).Event.EventData.Data |
                ForEach-Object {
                    $Properties.Add($_.name, $_.'#text')
                }

            # Add extracted properties to the event object
            $_ | Add-Member -NotePropertyMembers $Properties
        }

    # Set default start\finish date for event in case
    # it's still running or was started before $MaxEvents
    $DefaultStartDate = $Events[-1].TimeCreated
    $DefaultFinishDate = Get-Date
    Write-Verbose "Default task start date: $DefaultStartDate"
    Write-Verbose "Default task finish date: $DefaultFinishDate"

    Write-Verbose 'Processing events...'
    # Group events by ID and process them
    $PcEvents = $Events |
        Group-Object -Property InstanceId |
            ForEach-Object {
                # Get Name and start\finish Date
                $TaskName = $_.Group[0].TaskName
                $StartDate = ($_.Group | Where-Object {$_.OpcodeDisplayName -eq 'Start'}).TimeCreated
                $FinishDate = ($_.Group | Where-Object {$_.OpcodeDisplayName -eq 'Stop'}).TimeCreated

                # If we can't get dates, set them to defaults
                if(!$StartDate)
                {
                    $StartDate = $DefaultStartDate
                }
                elseif(!$FinishDate)
                {
                    $FinishDate = $DefaultFinishDate
                }

                # Hashtable holding object's properties
                $ItemProp = @{
                    Name = $TaskName
                    StartDate = $StartDate
                    FinishDate = $FinishDate
                    Duration = $FinishDate - $StartDate
                }

                # Output new object to the pipeline
                New-Object psobject -Property $ItemProp |
                    Select-Object Name, StartDate, FinishDate, Duration
        }

    # Add data to results
    $Result += @{$PC = $PcEvents}
}


# Loop through results
$Result.GetEnumerator() |
    ForEach-Object {
        # Export results to CSV, one file per computer
        $CsvPath = Join-Path -Path $Path -ChildPath ($_.Key + '_TaskScheduler.csv')
        Write-Verbose "Saving data to CSV: $CsvPath"
        $_.Value | Export-Csv -LiteralPath $CsvPath -Force -NoTypeInformation
    }

Actualización (1): Agregué la capacidad de autenticarme como usuario diferente (nombre de usuario / parámetros de contraseña) y cambié a filtrado usando XML, que es Más rápido y debe permitir ejecutar este script en las computadoras Vista \ Server 2008 (evita este error ). Además, PowerShell 2.0 compatible ahora.

Actualización (2): He ajustado la detección de la ruta del script, por lo que ahora no debería interrumpirse en Powershell ISE. Además, he descubierto que en algunas PC, el registro del Programador de tareas está deshabilitado. Esto es lo que debe hacer para verificar que el registro esté habilitado:

  1. Compruebe, si tiene All Tasks History habilitado Debería leer Disable All Tasks History (ugh):

All Tasks History

  1. Compruebe si el programador de tareas Operational El registro de eventos está habilitado. Abierto:

    Visor de eventos Registro de aplicaciones y servicios Microsoft Windows Programador de tareas Operacional → haga clic con el botón derecho en él (o vaya al panel derecho) Propiedades

Task Scheduler Operational Event Log

Task Scheduler Operational Event Log Properies

Actualización (3): Se corrigió el manejo de los registros de eventos faltantes o no disponibles, se agregaron varios Verbose mensajes

beatcracker
fuente
Voy a intentar esto para asegurarse de que incluso he hecho el gráfico manualmente ya.
Root Loop
Mantenerme informado, estoy interesado en comentarios!
beatcracker
no funciona para mí en Windows 8. Se bloquea aquí: "$ Events = Get-WinEvent -ComputerName $ PC -FilterHashtable $ Filter -MaxEvents $ MaxEvents"
magicandre1981
Extraño, ejecuto 8.1 y funcionó bien para PC local y 3 servidores remotos. ¿Puedes publicar detalles de excepción? Me pregunto si esto podría ser un problema de autenticación, porque he ejecutado este script como administrador de dominio. ¿Se bloquea incluso si intentas ejecutarlo contra localhost (sin parámetros en absoluto)?
beatcracker
Intenté esto en mi caja local, funcionó, pero el resultado no fue exacto, todos los datos de inicio fueron los mismos, los datos finales estaban vacíos y todas las duraciones fueron las mismas ... Para PC remota, aparece el mensaje de error "No se puede validar argumetn en el parámetro "Ruta"
Root Loop