231 lines
6.3 KiB
PowerShell
231 lines
6.3 KiB
PowerShell
function Get-CronFields
|
|
{
|
|
return @(
|
|
'Minute',
|
|
'Hour',
|
|
'DayOfMonth',
|
|
'Month',
|
|
'DayOfWeek'
|
|
)
|
|
}
|
|
|
|
function Get-CronFieldConstraints
|
|
{
|
|
return @{
|
|
'MinMax' = @(
|
|
@(0, 59),
|
|
@(0, 23),
|
|
@(1, 31),
|
|
@(1, 12),
|
|
@(0, 6)
|
|
);
|
|
'DaysInMonths' = @(
|
|
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
|
);
|
|
'Months' = @(
|
|
'January', 'February', 'March', 'April', 'May', 'June', 'July',
|
|
'August', 'September', 'October', 'November', 'December'
|
|
)
|
|
}
|
|
}
|
|
|
|
function Get-CronPredefined
|
|
{
|
|
return @{
|
|
# normal
|
|
'@minutely' = '* * * * *';
|
|
'@hourly' = '0 * * * *';
|
|
'@daily' = '0 0 * * *';
|
|
'@weekly' = '0 0 * * 0';
|
|
'@monthly' = '0 0 1 * *';
|
|
'@quarterly' = '0 0 1 1,4,7,10';
|
|
'@yearly' = '0 0 1 1 *';
|
|
'@annually' = '0 0 1 1 *';
|
|
|
|
# twice
|
|
'@semihourly' = '0,30 * * * *';
|
|
'@semidaily' = '0 0,12 * * *';
|
|
'@semiweekly' = '0 0 * * 0,4';
|
|
'@semimonthly' = '0 0 1,15 * *';
|
|
'@semiyearly' = '0 0 1 1,6 *';
|
|
'@semiannually' = '0 0 1 1,6 *';
|
|
}
|
|
}
|
|
|
|
function Get-CronFieldAliases
|
|
{
|
|
return @{
|
|
'Month' = @{
|
|
'Jan' = 1;
|
|
'Feb' = 2;
|
|
'Mar' = 3;
|
|
'Apr' = 4;
|
|
'May' = 5;
|
|
'Jun' = 6;
|
|
'Jul' = 7;
|
|
'Aug' = 8;
|
|
'Sep' = 9;
|
|
'Oct' = 10;
|
|
'Nov' = 11;
|
|
'Dec' = 12;
|
|
};
|
|
'DayOfWeek' = @{
|
|
'Sun' = 0;
|
|
'Mon' = 1;
|
|
'Tue' = 2;
|
|
'Wed' = 3;
|
|
'Thu' = 4;
|
|
'Fri' = 5;
|
|
'Sat' = 6;
|
|
};
|
|
}
|
|
}
|
|
|
|
function ConvertFrom-CronExpression
|
|
{
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$Expression
|
|
)
|
|
|
|
# split and check atoms length
|
|
$atoms = @($Expression -split '\s+')
|
|
if ($atoms.Length -ne 5) {
|
|
throw "Cron expression should only consist of 5 parts: $($Expression)"
|
|
}
|
|
|
|
# basic variables
|
|
$aliasRgx = '(?<tag>[a-z]{3})'
|
|
|
|
# get cron obj and validate atoms
|
|
$fields = Get-CronFields
|
|
$constraints = Get-CronFieldConstraints
|
|
$aliases = Get-CronFieldAliases
|
|
$cron = @{}
|
|
|
|
for ($i = 0; $i -lt $atoms.Length; $i++)
|
|
{
|
|
$_cronExp = @{
|
|
'Range' = $null;
|
|
'Values' = $null;
|
|
}
|
|
|
|
$_atom = $atoms[$i]
|
|
$_field = $fields[$i]
|
|
$_constraint = $constraints.MinMax[$i]
|
|
$_aliases = $aliases[$_field]
|
|
|
|
# replace day of week and months with numbers
|
|
switch ($_field)
|
|
{
|
|
{ $_field -ieq 'month' -or $_field -ieq 'dayofweek' }
|
|
{
|
|
while ($_atom -imatch $aliasRgx) {
|
|
$_alias = $_aliases[$Matches['tag']]
|
|
if ($null -eq $_alias) {
|
|
throw "Invalid $($_field) alias found: $($Matches['tag'])"
|
|
}
|
|
|
|
$_atom = $_atom -ireplace $Matches['tag'], $_alias
|
|
$_atom -imatch $aliasRgx | Out-Null
|
|
}
|
|
}
|
|
}
|
|
|
|
# ensure atom is a valid value
|
|
if (!($_atom -imatch '^[\d|/|*|\-|,]+$')) {
|
|
throw "Invalid atom character: $($_atom)"
|
|
}
|
|
|
|
# replace * with min/max constraint
|
|
$_atom = $_atom -ireplace '\*', ($_constraint -join '-')
|
|
|
|
# parse the atom for either a literal, range, array, or interval
|
|
# literal
|
|
if ($_atom -imatch '^\d+$') {
|
|
$_cronExp.Values = @([int]$_atom)
|
|
}
|
|
|
|
# range
|
|
elseif ($_atom -imatch '^(?<min>\d+)\-(?<max>\d+)$') {
|
|
$_cronExp.Range = @{ 'Min' = [int]($Matches['min'].Trim()); 'Max' = [int]($Matches['max'].Trim()); }
|
|
}
|
|
|
|
# array
|
|
elseif ($_atom -imatch '^[\d,]+$') {
|
|
$_cronExp.Values = [int[]](@($_atom -split ',').Trim())
|
|
}
|
|
|
|
# interval
|
|
elseif ($_atom -imatch '(?<start>(\d+|\*))\/(?<interval>\d+)$') {
|
|
$start = $Matches['start']
|
|
$interval = [int]$Matches['interval']
|
|
|
|
if ($interval -ieq 0) {
|
|
$interval = 1
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($start) -or $start -ieq '*') {
|
|
$start = 0
|
|
}
|
|
|
|
$start = [int]$start
|
|
$_cronExp.Values = @($start)
|
|
|
|
$next = $start + $interval
|
|
while ($next -le $_constraint[1]) {
|
|
$_cronExp.Values += $next
|
|
$next += $interval
|
|
}
|
|
}
|
|
|
|
# error
|
|
else {
|
|
throw "Invalid cron atom format found: $($_atom)"
|
|
}
|
|
|
|
# ensure cron expression values are valid
|
|
if ($null -ne $_cronExp.Range) {
|
|
if ($_cronExp.Range.Min -gt $_cronExp.Range.Max) {
|
|
throw "Min value for $($_field) should not be greater than the max value"
|
|
}
|
|
|
|
if ($_cronExp.Range.Min -lt $_constraint[0]) {
|
|
throw "Min value '$($_cronExp.Range.Min)' for $($_field) is invalid, should be greater than/equal to $($_constraint[0])"
|
|
}
|
|
|
|
if ($_cronExp.Range.Max -gt $_constraint[1]) {
|
|
throw "Max value '$($_cronExp.Range.Max)' for $($_field) is invalid, should be less than/equal to $($_constraint[1])"
|
|
}
|
|
}
|
|
|
|
if ($null -ne $_cronExp.Values) {
|
|
$_cronExp.Values | ForEach-Object {
|
|
if ($_ -lt $_constraint[0] -or $_ -gt $_constraint[1]) {
|
|
throw "Value '$($_)' for $($_field) is invalid, should be between $($_constraint[0]) and $($_constraint[1])"
|
|
}
|
|
}
|
|
}
|
|
|
|
# assign value
|
|
$cron[$_field] = $_cronExp
|
|
}
|
|
|
|
# post validation for month/days in month
|
|
if ($null -ne $cron['Month'].Values -and $null -ne $cron['DayOfMonth'].Values)
|
|
{
|
|
foreach ($mon in $cron['Month'].Values) {
|
|
foreach ($day in $cron['DayOfMonth'].Values) {
|
|
if ($day -gt $constraints.DaysInMonths[$mon - 1]) {
|
|
throw "$($constraints.Months[$mon - 1]) only has $($constraints.DaysInMonths[$mon - 1]) days, but $($day) was supplied"
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
# return the parsed cron expression
|
|
return $cron
|
|
} |