是否有人知道是否有任何实用程序/工具可以根据时间和日期制作 Windows 任务计划程序中所有任务的图表,这样我就会知道某个时间点是否存在重叠导致服务器过载?
我们有一个用于所有计划任务的服务器,由于前任管理员的设计不佳,它最近运行缓慢,现在我需要找出每个任务的运行窗口,我可以在 excel 中手动制作图表,但逐一进行实在是太多了。
希望有一些实用程序可以做到这一点。
答案1
此 Powershell 脚本将读取任务计划程序的事件日志并导出为 CSV Task Name
、Start Date
和所有已启动的任务。然后,您可以将这些数据输入到您选择的电子表格中并构建 GANTT 图表Finish Date
。Duration
要求:
- 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 上,任务计划程序日志被禁用。以下是验证日志记录是否已启用的方法:
- 检查是否已
All Tasks History
启用。它应该显示Disable All Tasks History
(呃):
检查任务计划程序的
Operational
事件日志是否已启用。打开:Event Viewer→ Applications and Services Log→ Microsoft→ Windows→ Task Scheduler→ Operational→ 右键单击它,(或转到右侧窗格)Properties
更新 (3):修复了丢失或不可用的事件日志的处理问题,添加了一堆Verbose
消息。