Make an unknown argument an error, not a shrug

The script had no CmdletBinding, so PowerShell dropped unrecognised named
arguments into $args instead of failing. A typo in a manifest entry Args -
"-WindowStartMinutes 45" - would have been ignored silently, and the capture
would have run at the wrong time with nothing in the log to explain it. That
is exactly how an hour went into debugging a time gate that was working.

Also adds WindowStartMinute so the window can open at :45 rather than on the
hour. A shift change is a moment, not an hour, and the first run of the day is
easiest to watch when it lands when somebody expects it.
This commit is contained in:
cproudlock
2026-08-25 14:37:00 -04:00
parent ba4df185cd
commit f99ece1366

View File

@@ -46,6 +46,12 @@
# Always exits 0 so the GE-Enforce "last run result" stays clean. Failures are # Always exits 0 so the GE-Enforce "last run result" stays clean. Failures are
# logged, never thrown. # logged, never thrown.
# CmdletBinding so an unknown argument is an ERROR, not a shrug. Without it a
# script's param block silently drops unrecognised named arguments into $args -
# so a typo in the manifest entry's Args ("-WindowStartMinutes 45") would be
# ignored and the capture would quietly run at the wrong time, with nothing in
# the log to say why. Cost me an hour of debugging a gate that was fine.
[CmdletBinding()]
param( param(
[string]$BaseUrl = '', [string]$BaseUrl = '',
# Root of the opaque-backup tree. The snapshot lands in # Root of the opaque-backup tree. The snapshot lands in
@@ -80,6 +86,12 @@ param(
# GE-Enforce fires every 5 minutes, so this runs on the first cycle inside # GE-Enforce fires every 5 minutes, so this runs on the first cycle inside
# the hour and the 24h throttle stops it running again that day. # the hour and the 24h throttle stops it running again that day.
[int[]]$WindowHours = @(14), [int[]]$WindowHours = @(14),
# Minute the window OPENS within those hours. 0 means the whole hour.
# Set from the manifest entry's Args when the first run of the day should
# land at a particular time - the shift change is a moment, not an hour,
# and a capture is easiest to watch when somebody expects it.
[ValidateRange(0, 59)]
[int]$WindowStartMinute = 0,
# Used ONLY once the backup is overdue - the other two shift changes. They # Used ONLY once the backup is overdue - the other two shift changes. They
# are unattended, so they are a fallback for a bay that is busy at 14:00 # are unattended, so they are a fallback for a bay that is busy at 14:00
# every day, not part of the normal schedule. # every day, not part of the normal schedule.
@@ -178,7 +190,11 @@ if ($MyInvocation.InvocationName -eq '.') { return }
# out-of-window cycle costs a clock read and nothing else. # out-of-window cycle costs a clock read and nothing else.
if (-not $Force) { if (-not $Force) {
$now = Get-Date $now = Get-Date
$inwindow = ($WindowHours -contains $now.Hour) # Both the hour AND the minute, so a window can be "14:45 onwards" rather
# than the whole of the 14:00 hour. GE-Enforce fires every 5 minutes, so
# the capture starts on the first cycle at or after that time and the 24h
# throttle stops it running again that day.
$inwindow = ($WindowHours -contains $now.Hour) -and ($now.Minute -ge $WindowStartMinute)
# The marker file is stamped on every post attempt, so its age answers # The marker file is stamped on every post attempt, so its age answers
# "when did a capture last get through" - which is what the escalation # "when did a capture last get through" - which is what the escalation
@@ -213,7 +229,8 @@ if (-not $Force) {
# marking parts and the port is not ours to take. # marking parts and the port is not ours to take.
$allowed = $inwindow $allowed = $inwindow
if (-not $allowed -and $overdue) { if (-not $allowed -and $overdue) {
$allowed = ($OverdueWindowHours -contains $now.Hour) $allowed = ($OverdueWindowHours -contains $now.Hour) -and
($now.Minute -ge $WindowStartMinute)
} }
if (-not $allowed) { if (-not $allowed) {
@@ -232,7 +249,7 @@ if (-not $Force) {
# was built to stop. # was built to stop.
Write-ShopdbQuietState -Kind $KIND -State 'outside-window' -Message ( Write-ShopdbQuietState -Kind $KIND -State 'outside-window' -Message (
'Outside the capture window ({0}). The marker port is shared with eDNC, so the daily capture waits for a shift change. Use -Force to override.' -f 'Outside the capture window ({0}). The marker port is shared with eDNC, so the daily capture waits for a shift change. Use -Force to override.' -f
(($WindowHours | ForEach-Object { '{0:00}:00' -f $_ }) -join ', ')) (($WindowHours | ForEach-Object { '{0:00}:{1:00}' -f $_, $WindowStartMinute }) -join ', '))
} }
exit 0 exit 0
} }