Time check in powershell keeps returning minus error if run overnight

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

4 answers

  • answered 2020-10-16 07:23 Alex_P

    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))
    {...}
    

  • answered 2020-10-16 07:30 Lieven Keersmaekers

    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"
    }
    

  • answered 2020-10-16 10:34 marsze

    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
    

  • answered 2020-10-16 21:58 confuzzled

    Thanks everyone. They are all great answers. Im new to this platform so not sure which one to mark as correct as they all work well!