Skip to content

fix(schtasks): use DAILY schedule for scan frequencies of 24h+#151

Open
raysubham wants to merge 1 commit into
step-security:mainfrom
raysubham:subham/fix/schtasks-daily-schedule-24h
Open

fix(schtasks): use DAILY schedule for scan frequencies of 24h+#151
raysubham wants to merge 1 commit into
step-security:mainfrom
raysubham:subham/fix/schtasks-daily-schedule-24h

Conversation

@raysubham

Copy link
Copy Markdown
Contributor

Problem

A Windows MSI/Intune deployment configured with a 24-hour scan frequency fails to install with Fatal error during installation (0x80070643). The MSI rolls back; a manual MSI install fails the same way.

Root cause

schtasks caps the HOURLY /mo modifier at 23. buildCreateArgs always emitted /sc HOURLY /mo <hours>, so a frequency of 24 produced:

schtasks /create ... /sc HOURLY /mo 24 ...
=> ERROR: Invalid value for /MO option.

The RunInstallScheduledTask custom action (agent install) then exits non-zero → MSI 1603 → Intune 0x80070643. schtasks validates /mo before /ru, so this is purely the modifier range — independent of the run-as account or locale. It reproduces on manual installs too, because the deferred custom action runs the identical command.

This only surfaced for frequencies ≥ 24h; sub-24h values (incl. the built-in default of 4) were always valid, which is why it wasn't caught earlier.

Fix

Introduce scheduleFor(hours) and route buildCreateArgs through it:

  • hours >= 24/sc DAILY /mo <hours/24> (24→1, 48→2), clamped to the DAILY ceiling of 365.
  • hours < 24/sc HOURLY /mo <hours>unchanged, floored at 1.

The clamps guarantee no scan-frequency value can ever emit an invalid /mo again. /ru INTERACTIVE for admin installs is preserved.

Testing

  • TestScheduleFor — table-driven: 1/4/12/23 stay HOURLY, 24/48/72 → DAILY, plus pathological 0→HOURLY/1 and 100000→DAILY/365.
  • TestBuildCreateArgs_DailyForTwentyFourHours — asserts /sc DAILY /mo 1 and that /ru INTERACTIVE survives the switch.
  • TestBuildCreateArgs_HourlyUnchanged — regression guard for the 1/4/12/23 hourly path.
  • gofmt, go build ./..., go vet ./..., and go test ./internal/schtasks/ all clean.

schtasks caps the HOURLY /mo modifier at 23, so a 24-hour scan frequency
produced `/sc HOURLY /mo 24`, which schtasks rejects with "Invalid value
for /MO option". The install custom action then exits non-zero and the MSI
rolls back, surfacing under Intune as 0x80070643 (and failing identically
on a manual MSI install, since the deferred custom action runs the same
command).

Map intervals of 24h or more to `/sc DAILY /mo <hours/24>` (24->1, 48->2),
clamped to the DAILY ceiling of 365 and floored at 1, so no scan-frequency
value can produce an invalid /mo. Sub-24h intervals keep the existing
HOURLY behavior unchanged.

Add scheduleFor() with table-driven unit coverage (boundaries 23/24, the
24h case, and pathological 0/100000 inputs) plus a regression guard that
the hourly path and the admin /ru INTERACTIVE binding are untouched.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Windows scheduled-task creation for scan frequencies ≥ 24 hours by avoiding invalid schtasks /sc HOURLY /mo <n> values (where n > 23) and ensuring a valid schedule/modifier pair is always emitted.

Changes:

  • Route scheduled-task argument generation through a new scheduleFor(hours) helper that selects HOURLY for <24h and DAILY for >=24h, with appropriate modifier clamping.
  • Update buildCreateArgs to use the computed schedule/modifier instead of always emitting HOURLY.
  • Add focused unit tests covering scheduleFor behavior and ensuring /ru INTERACTIVE is preserved for admin installs when switching to DAILY.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
internal/schtasks/schtasks.go Adds scheduleFor(hours) and uses it in buildCreateArgs to avoid invalid schtasks /mo values for 24h+ intervals.
internal/schtasks/schtasks_test.go Adds tests validating the new schedule mapping and argument emission for both hourly and daily cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants