Этот сценарий Powershell будет читать журнал событий планировщика задач и экспортировать его в Task Name
CSV, Start Date
Finish Date
и Duration
для всех запущенных задач. Затем вы можете передать эти данные в выбранную вами электронную таблицу и построить диаграмму Гантта.
Требования:
- PowerShell 2.0
- Windows Server 2008\Vista
Скрипт принимает следующие аргументы:
- Компьютеры: массив имен компьютеров для запроса.Если не указан, он будет запрашивать локальный компьютер.
- MaxEvents: максимальное количество событий для чтения из журнала событий.По умолчанию 100.
- Путь: существующая папка на диске, где будут сохранены файлы CSV.Если не указан, будет использована папка скрипта. CSV названы так:
COMPUTERNAME_TaskScheduler.csv
.
- Пользователь: имя пользователя для удаленной аутентификации.
- Пароль: пароль для пользователя.Если не указан, он будет запрошен скриптом.
- Verbose: скрипт расскажет вам, что происходит через сообщения
Write-Verbose
.
Примеры (запускаются из консоли PowerShell):
Получить данные с локального компьютера, обработать последние 100 событий, сохранить CSV в папку сценария:
.\TS_Gantt.ps1
Получайте данные с удаленных компьютеров, обрабатывайте последние 200 событий, сохраняйте файлы CSV в папку c:\ts_gantt
:
.\TS_Gantt.ps1 -Computers Sun, Earth, Moon -MaxEvents 200 -Path 'c:\ts_gantt'
Скрипт (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
}
Обновление (1): я добавил возможность авторизации от имени другого пользователя (параметры «Имя пользователя \ Пароль») и переключился на фильтрацию с использованием XML, что быстрее и должно позволить запускать этот сценарий на компьютерах с ОС Vista \ Server 2008 (исключает эту ошибку). Кроме того, PowerShell 2.0 теперь совместим.
Обновление (2): я настроил обнаружение пути скрипта, поэтому теперь он не должен ломаться в Powershell ISE. Кроме того, я обнаружил, что на некоторых ПК журнал планировщика заданий отключен. Вот что нужно сделать, чтобы убедиться, что ведение журнала включено:
- Проверьте, включена ли у вас
All Tasks History
. Следует прочитать Disable All Tasks History
(тьфу):
Проверьте, включен ли журнал Operational
событий планировщика заданий.
Открыто:
Просмотр событий → Журнал приложений и служб → Microsoft → Windows → Планировщик задач → Оперативный → щелкните его правой кнопкой мыши (или перейдите на правую панель) Свойства
Обновление (3): Исправлена обработка отсутствующих или недоступных журналов событий, добавлена куча Verbose
сообщений.