Operations and settings¶
Runs¶
- Scheduled daily (times below, UTC) and on demand via Collect now in the portal.
- Logs: Application Insights in the Wardline resource group.
- Cost: Flex Consumption with daily runs, a small storage account and Log Analytics with little data – usually a few euros per month; larger tenants accordingly more.
App settings¶
Set by the install script; change them in the Function App configuration or via the install script parameters.
| Setting | Default | Meaning |
|---|---|---|
WL_MODULES |
endpoint,agents |
Enabled modules (endpoint, agents, access, licensing) – derived from -Features |
WL_FEATURES |
hunting,indicators |
Endpoint data sources (hunting, indicators, inventory) – derived from -Features |
WL_SCHEDULE_ENDPOINT |
0 17 2 * * * |
Schedule of the endpoint collection (NCRONTAB, UTC) |
WL_SCHEDULE_AGENTS |
0 32 2 * * * |
Schedule of the agents collection |
WL_SCHEDULE_ACCESS |
0 47 2 * * * |
Schedule of the access collection |
WL_SCHEDULE_LICENSING |
0 17 3 * * * |
Schedule of the licensing collection |
WL_LICENSING_DAYS |
30 |
Observation window for device logons (7–90, Licensing module) |
WL_LICENSING_DEVICES_PER_USER |
5 |
Devices covered per user licence |
WL_LICENSING_DETAIL |
users |
users keeps UPNs in the licensing snapshot, aggregate pseudonymises them |
WL_CHANGE_RETENTION_DAYS |
365 |
Retention of the change history (-ChangeRetentionDays) |
WL_SNAPSHOT_RETENTION_DAYS |
365 |
Retention of the snapshots (-SnapshotRetentionDays); informational – the storage lifecycle rule enforces it |
WL_DEVICE_INVENTORY |
false |
Device inventory via Intune Remediations (-DeviceInventory) |
WL_DEVICE_LOOKBACK_DAYS |
7 |
How far back device state is read from Advanced Hunting |
WL_DATA_APP_ID |
– | Pre-created data-access app (workload identity federation) |
WL_UPDATE_CHECK |
true |
Daily check for new releases (no tenant data sent) |
WL_NOTIFY_WEBHOOK |
– | Webhook for notifications about new findings (-NotifyWebhookUrl) |
WL_NOTIFY_MIN_SEVERITY |
High |
Minimum severity of new findings that are sent (-NotifyMinSeverity) |
WL_UPDATE_REPOSITORY |
– | Different GitHub repository for the update check (e.g. an internal mirror) |
WL_MAX_GROUP_MEMBERS |
10000 |
Cap when resolving group members (Access module) |
WL_PAGE_SIZE |
2000 |
Devices per stored page (state/endpoint-devices/NNNN.json) |
WL_FINDING_ROLLUP |
200 |
Above this many devices, identical per-device findings are rolled up into one finding with the device count |
WL_TENANT_ID, WL_CLIENT_ID, WL_STORAGE_ACCOUNT, WL_STORAGE_SUFFIX |
set by the template | Do not change |
Notifications¶
After each run Wardline can post new findings (not in the previous run, at least WL_NOTIFY_MIN_SEVERITY, not
accepted) to a webhook:
- Teams: create a workflow in the channel with the template "Post to a channel when a webhook request is received" and pass its URL. Wardline sends an Adaptive Card with the findings and a link to the portal.
- E-mail or anything else: a Power Automate flow with the trigger "When an HTTP request is received" – the payload
also contains the plain field
wardline.findings(severity, category, title, device, andassigneewithtype,displayNameandmailwhen the finding is assigned to someone). A flow can useassignee.mailto notify the person, group or distribution list directly.
./setup/Install-Wardline.ps1 -ResourceGroup rg-wardline -NotifyWebhookUrl "https://…" -NotifyMinSeverity High
Re-runs keep the webhook unless you pass a new one. Wardline only sends findings – no exclusion values or command lines.
Notices after a run¶
Missing data does not abort a run; it shows up as a notice in the portal.
| Notice | Meaning | What to do |
|---|---|---|
HTTP 403 … Not in the token: X |
Permission X is not granted, or was granted after the managed identity's current token was issued |
Re-run the install or Grant-WardlinePermissions.ps1 (lists what is granted). Azure caches managed identity tokens for up to 24 hours – the notice disappears with the next token. |
HTTP 403 … The token contains X |
The permission is there, but the API refuses anyway | Usually a missing licence (Agent ID, Agent 365) or a preview API that is not enabled in the tenant |
HTTP 400/404 on agent APIs |
The API is not available in the tenant (yet) | Nothing – the agents module shows what it can |
Storage layout¶
| Container | Content |
|---|---|
state |
Current state per module, change history, run log, update info, exceptions, assignments and their audit log |
state/endpoint-devices/, state/endpoint-coverage/ |
Device and coverage lists in pages of WL_PAGE_SIZE entries, with a tab-separated search index (endpoint-devices.tsv) and a fingerprint list for drift detection |
snapshots |
Dated snapshots of every run (optionally immutable) |
config |
Your custom baseline (mdav-baseline.json) |
Large fleets¶
Wardline is built for tenants with a few hundred up to several hundred thousand devices:
- Advanced Hunting returns at most 100,000 rows per query. When a query hits that limit Wardline counts the
result and re-runs it in hash shards over
DeviceId, so every device is collected exactly once. The run also keeps within the 45-calls-per-minute budget of the API. If a shard is still truncated the run shows a notice. - Device lists are not stored inside the snapshot but in pages; the snapshot keeps the aggregates
(
deviceStats) the charts need. The portal loads the full list up to 10,000 devices; above that the Devices view searches and filters on the server (api/devices) and opens single devices viaapi/device. - Findings that affect more than
WL_FINDING_ROLLUPdevices (e.g. Tamper Protection off on 12,000 devices) are rolled up into one finding with the device count and a sample of names; the exact set is one filter click away in the Devices view. - Function memory: the template deploys 4 GB instances (
instanceMemoryMB). A run with 300,000 devices takes roughly 15–30 minutes, most of it waiting for Advanced Hunting; 2 GB is enough below ~50,000 devices. tests/Invoke-WardlineScaleTest.ps1 -Devices 300000runs the paging, search and drift code against a synthetic fleet locally and prints timings.