Windows 计划程序每月第二和第三个周末

Windows 计划程序每月第二和第三个周末

是否可以使用 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

相关内容