Record what your scheduled tasks, RMM scripts and admin jobs actually did, including the runs that failed, as priced run events in LumaTrack.
Two functions. One reports a run. The other wraps a block of work and reports whichever way it went.
Install-Module -Name LumaTrack -Scope CurrentUserWorks on Windows PowerShell 5.1 and PowerShell 7 and later. No dependencies.
$env:LUMATRACK_KEY = 'lmt_your_ingest_key'That is the whole configuration for the hosted service. Reporting goes to
https://lumatrack.io unless you set $env:LUMATRACK_URL, which you only need
on a self-hosted or custom domain.
Both are also parameters (-Url, -ApiKey) when an environment variable is
awkward. Use an ingest-scope key on a machine that runs jobs: it can record
runs and it cannot read your ledger back, so a key lifted out of an RMM script
store cannot be used to restate your history.
Keep the key in your RMM's credential store or a protected environment variable. Never in the script body.
Send-LumaTrackRun -Automation 'ad-account-cleanup' -Units 14 -DurationSeconds 42Send-LumaTrackRun -Automation 'ad-account-cleanup' `
-Status failure -FailureReason 'auth/credential' -ExternalId $TaskRunId| Parameter | Notes |
|---|---|
-Automation |
The slug, as shown in LumaTrack. Required |
-Status |
success, failure, skipped or cancelled. Default success |
-DurationSeconds |
Wall clock. Rounded to a whole second |
-Units |
Records the run processed. Drives per-unit valuation |
-ExternalId |
Your run id. Makes retries idempotent |
-FailureReason |
Root cause, e.g. auth/credential. Feeds the failure Pareto |
-Metadata |
A hashtable kept with the run |
-Url, -ApiKey |
Default to $env:LUMATRACK_URL and $env:LUMATRACK_KEY; the URL falls back to https://lumatrack.io |
-TimeoutSec |
Default 15 |
It returns a result object rather than throwing:
$result = Send-LumaTrackRun -Automation 'ad-account-cleanup'
$result.Ok # $true when it landed
$result.StatusCode # 201 recorded, 200 replay, 202 held over the plan cap
$result.Deduplicated # $true when this ExternalId was already recorded
$result.Held # $true when the plan's run cap is reached
$result.Message # why it failed, when it didInvoke-LumaTrackTrackedCommand -Automation 'ad-account-cleanup' -ExternalId $TaskRunId -ScriptBlock {
Disable-StaleADAccounts
}It times the block, reports success with the duration when it returns, and
reports failure with the exception message when it throws. Then it rethrows,
so your scheduler still sees the job fail and your monitoring still fires.
Output from the block passes straight through.
This exists because hand-rolled reporting reliably grows a success call and never grows the failure call. A ledger that only hears about the good runs produces a number nobody should put in front of a client.
Every failure path warns and returns. An unreachable host, a bad key, a
timeout, an unrecognised slug: all of them produce a Write-Warning and let
your script carry on with its real exit status. A patching job should not fail
because a telemetry endpoint was slow.
Do watch for those warnings in job output. A wrong slug means runs that never land, and an automation with no runs is easy to miss on a report.
| Code | Meaning |
|---|---|
| 201 | Recorded |
| 200 | Replay: this ExternalId was already recorded, so nothing double-counted |
| 202 | Recorded but held, because the plan's run cap is reached |
| 400 | Payload rejected, often an executed_at inside a closed month |
| 404 | No automation matches that slug |
| 429 | Rate limited; back off and retry after Retry-After |
Invoke-Pester testsPayload and parameter behaviour runs against a mocked Invoke-RestMethod. Set
LUMATRACK_TEST_STUB_URL to a stub server and one more test asserts the
request as it goes over the socket.
MIT, see LICENSE.
Built by the team behind LumaTrack, which turns run events into a value figure a finance team can check. It works against any LumaTrack host, including a free workspace.