โ† Help & Docs

Scheduled Runbook Execution & Drift Monitoring

Recurring script execution against device fleets or cloud tenants, with drift detection and action rules. Last updated 2026-05-14

What it does

The Ops Script Schedules page (under the Configure nav group) lets you run library scripts on a recurrence - hourly, daily, weekly, or monthly. Each run is captured with full per-target output, and consecutive runs are compared for drift. When drift or failure is detected, configurable action rules fire email notifications or open Tasker tasks for follow-up.

Use cases

Script execution-target taxonomy ADO #498

Every library script is tagged with an executionTarget field that determines where and how it runs:

TargetIconWhere it runsRequires targets?
device๐Ÿ–ฅ๏ธDispatched to Windows hostnames via the TATER Agent's command-poll loopYes - one or more lowercase hostnames
cloudโ˜๏ธRuns against an M365/Entra tenant via Graph or EXO from a runbook or interactive admin sessionNo - leave targets empty
hybrid๐Ÿ”€Author opt-in for both modes (rare)Yes when used in device mode

Why this matters: a cloud script attempted via the device-execute path will fail at runtime - there's no agent to receive it. The scheduler enforces the contract at save time: cloud scripts cannot have device targets, device/hybrid scripts must have at least one. Existing scripts default to device (matches prior behavior).

Cloud auth context (optional companion)

Cloud scripts can additionally declare cloudAuthContext to document what auth the runbook host must provide. Values:

Creating a schedule

  1. Open TATER Ops โ†’ Configure โ†’ Script Schedules and click + New Schedule.
  2. Pick a script. The dropdown shows the execution-target icon next to each script.
  3. For device/hybrid scripts: enter target hostnames (one per line, lowercase). Cloud scripts leave this empty.
  4. Set the recurrence - frequency, UTC time, and (where applicable) day of week / day of month.
  5. Add action rules. Trigger options: on-drift, on-failure, or always. Action options: email (with recipients) or tasker-task (with category + priority).
  6. Save. The cron checks every 5 minutes and runs schedules whose nextRunAt has passed.

How drift detection works

When a run completes, the scheduler queries the most recent previous run for the same schedule and compares normalized stdout per target. Any host whose stdout differs from the prior run is flagged. The run record stores:

When drift is found, run status rolls up to Drift (instead of Success) so it shows up amber in the runs list and triggers any on-drift action rules.

Drift detection precision

Phase 1 compares whitespace-normalized stdout text. Scripts that emit timestamps, GUIDs, or other always-changing data will appear to drift every run. Best practice: structure your script output so the stable signal (config values, group membership IDs, permission strings) is on its own lines, separated from the noisy metadata. Phase 2 will add JSON diff with per-property Before/After.

Action rules

Each schedule supports up to 20 action rules. They fire after a run finalizes, in order of trigger:

Email actions send via the configured notifications channel (Graph or SMTP). Tasker-task actions create a new task in TATER Ops under the supplied category and priority, with the run summary embedded in the task description and the originating schedule linked.

Recent runs & per-target output

The Recent Runs tab lists the last 50 runs across all schedules. Click any row to open the run detail modal, which shows:

Cloud script execution

Cloud-targeted schedules execute. They fire the same per-org Azure Automation webhook (Run-OpsScriptCloud) that the on-demand Run button uses — one shared dispatch, so a scheduled run cannot behave differently from a manual one.

A cloud run stays Running until the runbook posts its result back, then finalises Success, Failed, or Drift from that result. It is deliberately NOT finalised the way device runs are: device runs are judged by counting agent commands, and a cloud job has none — so the device logic would see “nothing pending”, conclude the run was over before the runbook had started, and record Failed every time.

If the organisation has no Ops Script Cloud Webhook URL configured, the run records Failed with that as the reason. It is not skipped and it is not green.

History before 2026-08-24 is not evidence. Until then a scheduled cloud script recorded Skipped, advanced its next-run time, and executed nothing — which looked identical to a working schedule on every surface. At one firm a weekly governance scan cited in a published config document as a live control had run zero times. If you have cloud schedules that predate that date, judge them by their run history, not their next-run time.

Is this schedule actually running?

A green dot and a future next-run time are not evidence that anything ran. Every schedule now carries a health verdict, computed from its real run history rather than from its settings, and shown on the schedule list, the schedule detail, and list_ops_schedules over MCP.

VerdictMeans
okRuns, and recently enough for its cadence.
stuck clockEnabled, but its next-run time is in the past — the scheduler could not advance it, so it is retrying silently.
staleNothing has actually executed for several intervals — or the schedule has never completed a real run.
inactiveDisabled, or a one-off that has fired. Nothing to say.
unknownThe cadence is not one this check understands, so whether it runs is unknown — stated rather than assumed to be fine.

Two things it deliberately does not count as an execution: a Skipped run (a skip is not a run) and a Running one (it has not finished). A schedule whose history is nothing but skips therefore reports stale — which is the honest answer, and the one the old surfaces could not give.

If the verdict cannot be computed, the schedule shows health unknown rather than nothing. Absent evidence must not read as good news.

Permissions