Sytone's Ramblings

The occasional posts of a guy who plays with technology.

PowerShell Cron Script

2021-01-22 3 min read General

I was looking for a way to schedule jobs and yes windows has a task scheduler built in, however I wanted a bit more flexibility and less complexity.

On the unix platform you can use cron. It is a scheduler that uses a simple format to define the time when the process should start and the process command.

I was going to look at using it when I thought about the parsing that would be needed, I dod not want a system that much that I would write a cron parser. So pulling up search I thought to see if I could find someone who has done this. And what do you know, I found a PowerShell script that would test a cron string and return the time of execution. Bingo!

The cron expression tester can be seen below, this is the link to the gist.

To use this script I wrote a very small wrapper around it using my SimpleSettings module, which I probably should put on github at some point. As I use the amazing Windows Terminal I made a profile entry to start the script directly from the drop down menu. So all I do is open up Terminal and start the cron script. I do this as I do not always want the automation to run, this is part of the flexibility. If I was using Task Scheduler in windows I would have to enable/disable them all the time.

The script I use to wrap the Test-CronExpression script is below. I am sure there may be a nicer way to do it but it works, if it works for purpose there is not point in optimizing it any further, time is to important!

I use https://crontab.guru/ to help check and create any entries I need.

Start-CronScheduler.ps1

#Set-SimpleSetting -Section "crontab" -Name "crontab" -Value @(@{cron = "* * * * *"; command = "Get-Date"})

while($true) {

    $crontab = Get-SimpleSetting -Section "crontab" -Name "crontab" -DefaultValue @(@{cron = "* * * * *"; command = "Get-Date"})

    foreach ($cronJob in $crontab) {
        if(Test-CronExpression.ps1 -Expression $cronJob.cron) {
            Invoke-Expression -Command $cronJob.command
        }
    }

    $gap = 0
    while($gap -eq 0) {
        $now = Get-Date
        $nextMinute = ($now).AddMinutes(1).AddSeconds($now.Second*-1)
        $gap = ($nextMinute - $now).Seconds
    }
    Start-Sleep -Seconds $gap
}

Add-CronAction.ps1

[CmdletBinding()]
param (
    [String]
    $CronPattern,
    [String]
    $Command
)


$crontab = Get-SimpleSetting -Section "crontab" -Name "crontab" -DefaultValue @(@{cron = "* * * * *"; command = "Get-Date"})

wi "Current Cron entries"

$newCronTab = @()
foreach ($cronJob in $crontab) {
    wi "$($cronJob.cron) $($cronJob.command)"
    $newCronTab += @{cron = $cronJob.cron; command = $cronJob.command}
}

wi "Adding: $CronPattern $Command"

$newCronTab += @{cron = $CronPattern; command = $Command}

wi "New cron entries"

foreach ($cronJob in $newCronTab) {
    wi "$($cronJob.cron) $($cronJob.command)"
}

Set-SimpleSetting -Section "crontab" -Name "crontab" -Value $newCronTab

Badgerati/Test-CronExpression.ps1