Private/Get-NextScheduledEnv.ps1
|
function Get-NextScheduledEnv { <# .SYNOPSIS Calculates when the next scheduled environment activates. .DESCRIPTION Iterates the next 7 days from the given reference time and checks each scheduled environment's day and startHour. Returns a formatted string describing the earliest upcoming activation: "{EnvName} ({DayName} at {startHour}:00)". If no environments have a schedule configured, returns a descriptive message indicating no scheduled environments exist. Used by Select-EnvkEnvironment to populate the log message when no environment matches the current schedule and no fallback is defined. .PARAMETER Config The parsed config object returned by Get-EnvkConfig. Mandatory. Must contain an environments property with PSCustomObject environment definitions. .PARAMETER Now The reference datetime for calculating the next activation. Defaults to the current system time (Get-Date). Injectable for deterministic testing. .OUTPUTS System.String A formatted next-activation string, e.g., "Work (Monday at 07:00)". Returns "No scheduled environments configured" when no environments have a schedule. .NOTES Author: Aaron AlAnsari Created: 2026-02-25 Algorithm: iterate from $Now forward through the next 7 days. For each candidate day, check every scheduled environment. An environment matches the candidate day if its schedule.days contains the day name. If we are still on today, only days whose startHour is in the future count. The earliest (by datetime) activation across all environments and candidate days is returned. End-exclusive boundary: if $Now.Hour equals startHour on the same day, it IS a future activation (the current hour is the start of the window, not past it). We use -gt for the same-day hour exclusion: the activation is in the past only if the start hour is strictly less than the current hour. #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(Mandatory)] [PSCustomObject]$Config, [Parameter()] [datetime]$Now = (Get-Date) ) # Collect all scheduled environments (those with a non-null schedule block). $scheduledEnvs = @($Config.environments.PSObject.Properties | Where-Object { $null -ne $_.Value.schedule } | ForEach-Object { [PSCustomObject]@{ Name = $_.Name; Schedule = $_.Value.schedule } }) if ($scheduledEnvs.Count -eq 0) { Write-EnvkLog -Level 'DEBUG' -Message 'Get-NextScheduledEnv: no scheduled environments configured' return 'No scheduled environments configured' } $earliest = $null $earliestEnvName = $null $earliestDayName = $null # Check each of the next 7 days (today through 6 days ahead). for ($dayOffset = 0; $dayOffset -le 6; $dayOffset++) { $candidate = $Now.Date.AddDays($dayOffset) $candidateDay = $candidate.DayOfWeek.ToString() foreach ($envEntry in $scheduledEnvs) { $sched = $envEntry.Schedule # Skip environments whose schedule does not include this candidate day. if ($null -eq $sched.days -or @($sched.days) -notcontains $candidateDay) { continue } # Skip environments with missing or invalid hour fields. if ($null -eq $sched.startHour) { continue } $activationTime = $candidate.AddHours($sched.startHour) # On today, skip if the activation time is already in the past. # Using -le so that an activation at the current hour is still "in the future" # (the environment's window may still be open, but we are looking for NEXT start). # Use -lt so the exact current hour counts as a future start only when we have # not yet reached startHour. If current hour equals startHour, the activation # started NOW -- treat as past so we look for a genuinely future one. if ($dayOffset -eq 0 -and $activationTime -le $Now) { continue } if ($null -eq $earliest -or $activationTime -lt $earliest) { $earliest = $activationTime $earliestEnvName = $envEntry.Name $earliestDayName = $candidateDay } } } if ($null -eq $earliest) { # No activation found in the next 7 days (very unusual config -- e.g., all # environments scheduled only for today and already elapsed). Write-EnvkLog -Level 'DEBUG' -Message 'Get-NextScheduledEnv: no upcoming activation found within 7 days' return 'No upcoming activation within 7 days' } $hourFormatted = '{0:D2}:00' -f $earliest.Hour $result = "$earliestEnvName ($earliestDayName at $hourFormatted)" Write-EnvkLog -Level 'DEBUG' -Message "Get-NextScheduledEnv: next activation is $result" return $result } |