Windows 任务计划程序图表?

Windows 任务计划程序图表?

是否有人知道是否有任何实用程序/工具可以根据时间和日期制作 Windows 任务计划程序中所有任务的图表,这样我就会知道某个时间点是否存在重叠导致服务器过载?

我们有一个用于所有计划任务的服务器,由于前任管理员的设计不佳,它最近运行缓慢,现在我需要找出每个任务的运行窗口,我可以在 excel 中手动制作图表,但逐一进行实在是太多了。

希望有一些实用程序可以做到这一点。

答案1

此 Powershell 脚本将读取任务计划程序的事件日志并导出为 CSV Task NameStart Date和所有已启动的任务。然后,您可以将这些数据输入到您选择的电子表格中并构建 GANTT 图表Finish DateDuration

要求:

  • PowerShell 2.0
  • Windows Server 2008\Vista

脚本接受以下参数:

  • 电脑要查询的计算机名称数组。如果未指定,则将查询本地计算机。
  • 最大事件数从事件日志中读取的最大事件数量。默认值为 100。
  • 小路磁盘上现有的文件夹,CSV 将保存在此文件夹中。如果未指定,则将使用脚本文件夹。CSV 的命名方式如下:COMPUTERNAME_TaskScheduler.csv
  • 用户远程认证的用户名。
  • 密码用户密码。如果未指定,脚本将请求该密码。
  • 详细脚本将通过消息告诉您发生了什么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 PC 上运行此脚本(避免这个错误)。此外,现在兼容 PowerShell 2.0。

更新(2):我已经调整了脚本的路径检测,所以现在它在 Powershell ISE 中不会中断。此外,我发现在某些 PC 上,任务计划程序日志被禁用。以下是验证日志记录是否已启用的方法:

  1. 检查是否已All Tasks History启用。它应该显示Disable All Tasks History(呃):

所有任务历史记录

  1. 检查任务计划程序的Operational事件日志是否已启用。打开:

    Event ViewerApplications and Services LogMicrosoftWindowsTask SchedulerOperational→ 右键单击​​它,(或转到右侧窗格)Properties

任务计划程序操作事件日志

任务计划程序操作事件日志属性

更新 (3):修复了丢失或不可用的事件日志的处理问题,添加了一堆Verbose消息。

相关内容