Time check in powershell keeps returning minus error if run overnight

Viewed 63

I accidently managed to schedule a GPO task out at the wrong time which caused no amount of trouble so I have decided to add a time check to my powershell scripts to make sure they only run outside of core working hours. I had this code in one of my folders from ages ago that I found on a gist, but unfortunately cannot find the link to give proper credit.

If it is run in daytime hours it works perfectly but when the hours are overnight, it returns a minus int error.

Here is the following code:

     Function TimeCheck {


  $script:WorkingHours = "18:00-7:00"

  if ($script:WorkingHours -match '^[0-9]{1,2}:[0-5][0-9]-    [0-9]{1,2}:[0-5][0-9]$') {

        $current = Get-Date
        $start = Get-Date ($script:WorkingHours.split("-")[0])
        $end = Get-Date ($script:WorkingHours.split("-")[1])

        # correct for hours that span overnight
        if (($end-$start).hours -lt 0) {
            $start = $start.AddDays(-1)
        }

        # if the current time is past the start time
        $startCheck = $current -ge $start

        # if the current time is less than the end time
        $endCheck = $current -le $end

        # if the current time falls outside the window
        if ((-not $startCheck) -or (-not $endCheck)) {

    write-host "[-] Time is outside operational window"

            # sleep until the operational window starts again
            $sleepSeconds = ($start - $current).TotalSeconds

            if($sleepSeconds -lt 0) {
                # correct for hours that span overnight
                $sleepSeconds = ($start.addDays(1) - $current).TotalSeconds
            }
            # sleep until the wake up interval
    
    write-host '[!] sleeping for' $sleepSeconds

            Start-Sleep -Seconds $sleepSeconds
        }
    }

}

All ideas are welcome, hopefully someone can see something I cannot!

Thanks

3 Answers

If your post refers to the time-regex you created, I swiftly wrote this few lines of code.

$start = Get-Date -Hour 18 -Minute 0 -Second 0 -Format HH:mm
$end = Get-Date -Hour 7 -Minute 0 -Second 0 -Format HH:mm
$now = Get-Date -Format HH:mm
if (($now -gt $start) -or ($now -lt $end))
{...}

Instead of using string manipulation, I suggest you start with actual DateTime objects. It would simplify your code and be more robust in the end.

Following script checks if the current (date)time is between a given start/endtime

$start = ([DateTime]::ParseExact('18:00', 'HH:mm', $null)).TimeOfDay.TotalSeconds
$end = [DateTime]::ParseExact('07:00', 'HH:mm', $null).TimeOfDay.TotalSeconds

$current = (Get-Date).TimeOfDay.TotalSeconds
if (($start -gt $end) -and (($start -lt $current) -or ($current -lt $end))) {
    write-host "[-] Time is in operational window"
} elseif (($start -lt $end) -and (($start -lt $current) -and ($current -lt $end))) {
    write-host "[-] Time is in operational window"
} else {
    write-host "[-] Time is outside operational window"
}

You should work with the appropriate type for time, namely TimeSpan, which make comparisons a lot easier:

[timespan]$start = ($script:WorkingHours -split "-")[0]
[timespan]$end = [timespan]($script:WorkingHours -split "-")[1]
[timespan]$current = (Get-Date).TimeOfDay

# the check
$outsideOperationalWindow = $current -lt $start -and $current -ge $end
Related