Este script do PowerShell lerá o Log de eventos do Agendador de Tarefas e exportará para CSV Task Name
, Start Date
, Finish Date
e Duration
para todas as tarefas que foram iniciadas. Em seguida, você pode alimentar esses dados para sua planilha escolhida e criar um diagrama GANTT.
Requisitos:
- PowerShell 2.0
- Windows Server 2008 \ Vista
O script aceita os seguintes argumentos:
- Computadores : matriz de nomes de computadores a serem consultados. Se não for especificado, ele consultará o computador local.
- MaxEvents : quantidade máxima de eventos a serem lidos no log de eventos. O padrão é 100.
-
Caminho : pasta existente no disco, onde os CSVs serão salvos. Se não for especificado, a pasta de script será usada. CSVs são nomeados assim:
COMPUTERNAME_TaskScheduler.csv
. - Usuário : nome de usuário para autenticação remota.
- Senha : senha para o usuário. Se não for especificado, será solicitado pelo script.
-
Verbose : o script informará o que está acontecendo via
Write-Verbose
messages.
Exemplos (executados no console do PowerShell):
Obtenha dados do computador local, processe os últimos 100 eventos e salve o CSV na pasta de script:
.\TS_Gantt.ps1
Obtenha dados de computadores remotos, processe os últimos 200 eventos, salve os CSVs na pasta c:\ts_gantt
:
.\TS_Gantt.ps1 -Computers Sun, Earth, Moon -MaxEvents 200 -Path 'c:\ts_gantt'
Script ( 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
}
Update (1): Adicionei a capacidade de autenticação como usuário diferente (parâmetros Username \ Password) e mudei para filtragem usando XML, que é mais rápido e deve permitir a execução deste script contra os PCs Vista \ Server 2008 (evita este bug ). Além disso, o PowerShell 2.0 é compatível agora.
Update (2): Eu ajustei a detecção do caminho do script, então agora ele não deve quebrar o Powershell ISE. Além disso, descobri que, em alguns PCs, o log do Agendador de Tarefas está desabilitado. Aqui está o que fazer para verificar se o registro está ativado:
- Verifique se você tem
All Tasks History
ativado. Deve lerDisable All Tasks History
(ugh):
Verifique se o log de eventos Operational
do Agendador de Tarefas está ativado.
Aberto:
Visualizador de Eventos → Log de Aplicativos e Serviços → Microsoft → Windows → Agendador de Tarefas → Operacional → clique com o botão direito do mouse (ou vá para o painel direito) Propriedades
Atualização (3): Corrigida a manipulação de logs de eventos ausentes ou não disponíveis, adicionado um monte de Verbose
mensagens.