是否可以使用 Windows Scheduler 在每个月的第二个和第三个星期六之后的星期日运行任务?
长版本
我们有一些维护脚本,可以让系统在周六下午 6 点离线进行修补,并在周日早上 6 点重新上线;维护(例如 Windows 更新)在这两个时间段之间进行。系统通常需要在每月的第一个周末和最后一个周末进行维护,因此我们只在每月的第二个周末和第三个周末进行维护。
一个潜在的问题是,如果一个月从星期日开始,那么我们会在第三个星期六将系统离线,但在星期日将其重新联机的脚本会在前一周运行(即在该月的第三个星期日)。
这在脚本中很容易解决;只需安排任务每周运行,然后检查它是否是第二个或第三个星期六之后的星期日,以确定是否继续运行或终止。
然而,还有更好的方法吗?
答案1
2016 年只有一个月(5 月)受到影响。为什么不直接将 5 月从任务计划中排除,然后手动运行脚本,或者为 5 月创建单独的计划任务?您可以通过创建两个计划任务轻松将其扩展到未来几年。一个计划任务按预定义的时间表运行,但不包括从星期日开始的月份,另一个计划任务仅包括从星期日开始的月份。
2016 年有一个月份受影响。接下来的 4 年中每年有两个月份受影响,2021 年有一个月份受影响。
答案2
注意:我最终只是在代码的开头附加了一个脚本来确定我们是否在窗口中,然后让调度程序每周运行该代码。
param (
[string]$ScriptPath
,[int]$StartDay = 10
,[int]$EndDay = 24
)
#
# Only run the given script if the current date falls on a weekend between the start and end dates (is designed specifically to cope
# with tasks initiated over weekends, so requires that both the saturday and sunday of the current date fall in this window)
#
function Test-DateIsInMaintenanceWindow {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline = $true)]
[System.DateTime]$Date = (Get-Date)
, [int]$StartDay = 10
, [int]$EndDay = 24
)
begin {
if($StartDay -ge $EndDay) {
throw "We expect the start date to be before the end date; logic for these dates being the same, or switched (i.e. to cover crossing a month boundary) are beyond the designed requirements"
}
$EndDayLocal = $EndDay - 1 #we only test the Sat / we want to ensure we account for the following Sun
}
process {
[boolean]$IsWeekend = $true #assume it's the weekend; we confirm this later
[DateTime]$Sat = $Date
switch ($Date.DayOfWeek) { #we could use 6 and 0 instead of Sat and Sun to avoid language issues; but all our servers are US/UK, and the readability is clearer with week names
'Saturday' {$Sat = $Date}
'Sunday' {$Sat = $Date.AddDays(-1)}
Default {$IsWeekend = $false}
}
write-output (new-object PSObject -prop @{
Date = $Date
Day = $Date.DayOfWeek
OK = $IsWeekend -and (($Sat.Day -ge $StartDay) -and ($Sat.Day -le $EndDayLocal))
})
}
}
if ((Test-DateIsInMaintenanceWindow).OK) {
&$ScriptPath
} else {
throw 'Script should''t run today'
}
#Code to say which weekends fall in our maintenance window
1..4000 | %{(get-date).AddDays($_)} | ?{$_.DayOfWeek -like 'S*'} | Test-DateIsInMaintenanceWindow -StartDay 10 -EndDay 24 | ft -AutoSize