-1

I have created a scheduled task in Windows that consists of running a batch script. The problem is that this task has to be scheduled every 1st day of the month except for weekends.

For example, for the month of May, this task should run on May 02nd.

As I can't do it via the task scheduler, my idea is to schedule the execution task every day and add a condition checking that the execution day is the 1st day of the month excluding weekends.

This script would be of the following form :

if today = firstday
C:/MyExec/popo.exe arg1 arg2

Can you help me to write this script please?

Thank you in advance.

Labedos
  • 63
  • 9
  • 1
    Just for clarity, does the method need to take into account anything else? like if the first non weekend day(s) fall on a public or bank holiday for instance! – Compo May 04 '22 at 11:05
  • Please edit-in a sample of the date format displayed by echoing `%date%`. Is there a way to determine whether the process has been run this month? – Magoo May 05 '22 at 17:06
  • As I said I only take into account the days without week-end (saturday and sunday). Furthermore, I edited my pseudoscript. – Labedos May 06 '22 at 13:10

3 Answers3

0

There are loads of standard methods already created for this, so just for me to experiment a bit, here is an untested method (untested meaning I simply ensured there are no syntax errors, but I have not tested all dates scenarios etc:

@echo off
if not exist _mlock break>_mlock
for /f "tokens=1-3*delims=_" %%i in ('PowerShell -Command "& {Get-Date -format "dd_ddd_MM"}"') do (
    if %%i lss 5 if /i not "%%j" == "Sat" if /i not "%%j" == "Sun" findstr "m%%k">nul _mlock || (
        echo m%%k>"_mlock"
        start "" "C:\MyExec\popo.exe" "arg1" "arg2"
    )
)

The concept: Use powershell to get a non-locale dependent dd ddd mm (04 Wed 05). I check for the day number, if it is less than 5 (overkill in this scenario) and if the ddd is not Sat or Sun and if the month's lock file does not contain the current month number, it will launch the command. If however the lock file contains the month, it will skip it until the month is updated in the file.

You're welcome to test this, if you are not happy with the temp holding file method, you can also let it add the month as a lock to the batch-file itself instead.

Notes:

  1. This does not cater for public holidays, only weekends as per your request.
  2. The ddd day result is language dependent and will require you to amend Sat and Sun accordingly on non English Operating systems.
Gerhard
  • 22,678
  • 7
  • 27
  • 43
  • Your solution look condensed. If it's untested I need to try it out in my environment. Thank you very much – Labedos May 05 '22 at 08:42
  • I is not untested in its entirety, I tested it on the current days and mimic'd weekends which worked. I just did not tested different months etc. – Gerhard May 05 '22 at 08:52
0

This version is language-independent, excepted for optional display, and doesn't require lock files.

I've put comments inside the batch itself, feel free to ask for precisions if needed. I've tested it for March and May 2022, it works and doesn't trigger the command more than one time per month.

@echo off
setlocal enableextensions enabledelayedexpansion

REM Get current date. Powershell is used to get values in a fixed order.
for /f "usebackq tokens=1-3 delims=/" %%A in (`PowerShell -Command "& {Get-Date -format "dd/MM/yyyy"}"`) do (
    set DD=%%A
    set MM=%%B
    set YY=%%C
    REM Scheduled day.
    set EDD=01
)
REM Not during first 3 days after scheduled day? Skip.
set /A maxday=!EDD!+2
if !DD! LEQ !maxday! (
    if !DD! GEQ !EDD! (
        goto :can_test
    )
)
echo !DD!/!MM!/!YY!: Not first days after scheduled day, no need to test.
goto :eof
:can_test
REM Compute day of week: 0=Monday, ... 5=Saturday, 6=Sunday.
set /A c=(14-!MM!)/12
set /A y=!YY!-!c!
set /A m=!MM!+(12*!c!)-2
set /A d=((!EDD!-1+!y!+(!y!/4)-(!y!/100)+(!y!/400)+((31*!m!)/12))) %% 7
REM Get human-readable day. Change according to your own language, if needed. Keep order, of course.
set DAYS=Monday Tuesday Wednesday Thursday Friday Saturday Sunday
set /A i=0
for %%A in (!DAYS!) do (
   set DAY=%%A
   if !i! EQU !d! goto :found_day
   set /A i+=1
)
:found_day
echo Day of week for !EDD!/!MM!/!YY!: !d! ^(!DAY!^)
REM If EDD is during week-end, increase expected day (2 days for Saturday, 1 day for Sunday)..
if !d! GEQ 6 (
    set /A EDD+=7-!d!
    REM Handle non-significative zero.
    if !EDD! LSS 10 (
        set EDD=0!EDD!
    )
    echo On week-end, schedule it to !EDD!/!MM!/!YY! instead.
)
REM Are we on scheduled day EXACTLY?
if !DD! EQU !EDD! (
    REM Executing command now.
    echo Executing: C:\MyExec\popo.exe arg1 arg2
    REM C:\MyExec\popo.exe arg1 arg2
    goto :eof
)
REM We're before or after schedule, but still within the first three days in the month.
echo Unscheduled for today ^(!DD!/!MM!/!YY!^).
goto :eof

The "day of week" formula comes from here: Mathematical curiosities / Find the day of the week with a given date (in French).

I took also Gerhard's trick for obtaining a fixed date format quickly through Powershell. It could also have been done with an embedded VBS script, since this language natively have the Weekday function, but it may have been quite unreadable to add a temporary script generation within the batch itself.

Wisblade
  • 1,483
  • 4
  • 13
  • 1
    Hello, Thank you for your complete reply. Getting the first non week-end look more complex than I thought – Labedos May 05 '22 at 08:40
  • In fact, it's a generic solution for any "find the next business day on a particular day" problem. I've indeed modified the 1st test to set it fully working, even if you now plan to do that on 15th instead of 1st of each month (set `EDD` accordingly). It seems complicated because it works for every case, and for every locale (we write dates as DD/MM/YYYY in my country, for example). For your particular problem, you COULD hardcode the result, computed with Excel, and put the correct days (including public holidays) for the next 5 years - only 60 values to store... Simple, but not upgradable. – Wisblade May 05 '22 at 14:13
0

Sorry for this answer but I've no reputation to add a comment below the answer I'm referring to, the one by Wisblade:

https://stackoverflow.com/a/72113645/16641207

And I think it is important to make some additions to his beautiful answer.

I'm answering just to point out that in the wonderful piece of batch posted by Wisblade, to avoid sundays and saturdays too, at line 38 instead of this:

if !d! GEQ 6 (

there should be:

if !d! GEQ 5 (

because numbering in the "array" begins with zero.

I would also underline that this conditional expression should be changed if weekend days are different in the country where the code is used: e.g. in Israel one should check if !d! is NOT 0 and NOT 6 (not a monday nor a sunday, but saturdays are workdays there, too).

Apart from that, I gave a big +1 to his question, works so beautifully. I used in a scheduled task, combined with the ability of Windows Scheduled Tasks to be scheduled only on first mon/tue/wed/thu/fri of every month, and doing this I'm able to execute my instruction just on first working day of every month.

Simple and effective.