4

Кто-нибудь знает, есть ли какая-либо утилита / инструмент, который может составить диаграмму всех задач в планировщике задач Windows на основе времени и даты, поэтому я буду знать, есть ли какое-либо совпадение в определенный момент времени, вызывающее перегрузку сервера?

У нас есть сервер для всех запланированных задач, и в последнее время он работает медленно из-за плохого дизайна, сделанного бывшим администратором, теперь мне нужно выяснить окно запуска для каждой задачи, я могу сделать диаграмму вручную в Excel, но это слишком много пройти через один за другим.

Надеюсь, что некоторые утилиты смогут это сделать.

1 ответ1

2

Этот сценарий 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. Кроме того, я обнаружил, что на некоторых ПК журнал планировщика заданий отключен. Вот что нужно сделать, чтобы убедиться, что ведение журнала включено:

  1. Проверьте, включена ли у вас All Tasks History . Следует прочитать Disable All Tasks History (тьфу):

История всех задач

  1. Проверьте, включен ли журнал Operational событий планировщика заданий. Открыто:

    Просмотр событийЖурнал приложений и службMicrosoftWindowsПланировщик задачОперативный → щелкните его правой кнопкой мыши (или перейдите на правую панель) Свойства

Журнал событий планировщика заданий

Планировщик заданий

Обновление (3): Исправлена обработка отсутствующих или недоступных журналов событий, добавлена куча Verbose сообщений.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .