Get the Nth Working Day of the Month25 Jan 2020 · Comments: 0 · Tags: PowerShell, DateTime, WindowsTaskScheduler, ScheduledTask
- Function: Get-NthWorkingDayOfMonth
- Further Reading
I recently needed to schedule a task with Windows Task Scheduler to run at midday on the 5th weekday (Mon-Fri) of every month in 2020. Windows Task Scheduler lacks the functionality to configure such a schedule, so I needed to create a separate trigger for each month. Rather than do this by hand, I wrote a function in PowerShell to calculate the Nth weekday of a given month and year.
The function I wrote can be found here.
For further details, see Get-NthWorkingDayOfMonth.
When using this function there are a couple of caveats to consider…
If an Nth value is specified in combination with a month and year which cannot be satisfied then a terminating error is thrown, EG:
PS C:\Bitbucket> Get-NthWorkingDayOfMonth -Nth 25 -Month 1 -Year 2020 There isn't a 25th working day (Monday, Tuesday, Wednesday, Thursday, Friday) in January 2020. At C:\Bitbucket\Get-NthWorkingDayOfMonth.ps1:112 char:5 + Throw "There isn't a $($Nth)$($OrdinalIndicator) working day ($($ ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (There isn't a 2...n January 2020.:String) , RuntimeException + FullyQualifiedErrorId : There isn't a 25th working day (Monday, Tuesday, Wednesday, Thursday, Friday) in January 2020. PS C:\Bitbucket>
Depending on the use case, this may be acceptable. However, if used as part of a process which is expected to run every month then the caller would need to be written defensively to handle this situation and take some form of remedial action.
The other caveat is that it doesn’t take into consideration public holidays. Again, whether this is a concern or not is dependant on the use case.
I suppose this is why Windows Task Scheduler doesn’t provide the functionality to configure such a schedule.
Demonstration: My Use Case
Due to the caveats mentioned above, I’m not entirely sure how wise it is to use this function as part of an unattended process where the expectation is that it is guaranteed to run once a month. With that said, you may now be wondering what practical use this function has, so allow me to explain my use case…
As mentioned in the summary, I needed to schedule a task using Windows Task Scheduler to run on the 5th weekday (Mon-Fri) of every month in 2020. I started by using my function to produce a list of dates. Obtaining the 5th working day of each month where a working week consists of the days Mon-Fri is not an outlandish requirement, so I didn’t expect any errors to be returned but best to be safe…
Once satisfied there was nothing awry with the list of dates, my plan was to populate a scheduled task with a series of twelve date/time type triggers, one for each month. In my case, the scheduled task already existed, I just needed to replace the existing triggers with new date/times for 2020. I opted to do the following:
- Export the task to an XML file using the Windows Task Scheduler UI.
Get-NthWorkingDayOfMonthto produce a series of date values formatted appropriately for use in the XML file:
- Paste the values into the XML file (removing any existing values).
- Import the updated file with the
schtasks.execommand line tool:
An alternative (and in hindsight simpler) approach would have been to use
New-ScheduledTaskTrigger cmdlet to replace the existing triggers
with twelve new triggers:
Finally, to ensure that the scheduled task had been correctly populated with the triggers, I used the following:
Working on this task lead me to dabble with various scheduling tools and specifications to find out how they handled different conditions. These are just some of my notes pertaining to this research.
In my function
Get-NthWorkingDayOfMonth I took the decision to throw a
terminating error if an Nth value is specified in combination with a month and
year which cannot be satisfied. I was curious to see how this problem is handled
by the iCalendar specification.
The specification’s latest (as at Jan 2020) RFC (5545) acknowledges this issue as follows (excerpt from page 43):
The Outlook 2016 UI prevents a user from scheduling a recurrent event on a specific Nth weekday (Mon-Fri) of every month beyond the fourth:
I wondered if you could circumvent this limitation by scheduling a recurrent
event on the 4th weekday of every month, saving it to an iCalendar file (.ics),
editing the file in a text editor, replacing
importing the file. The answer is no, you can’t. When attempting to import the
file nothing happens, there’s no error message. I also tried by constructing a
minimal iCalendar file (opposed to the one produced by Outlook), this also
failed to import.