Compliance report
Auditors and customers ask the same questions: are all devices reporting, patched, configured as required, up to date, and running your app? This program answers for every device, in a CSV you can open in a spreadsheet or attach to your evidence.
Needs: a service account with ViewDevices, and .NET 10.
OHR_TOKEN=ohrs_… dotnet run compliance-report.cs -- com.example.yourapp > devices.csvdevice,serial,fleet,last_check_in,os_build,security_patch,agent,agent_current,settings_in_sync,settings_errors,app_version,compliant,reasons6,A0000A00042,Downtown store,2026-11-03 16:43:05Z,OhrTech/aleph/aleph:…,2026-11-05,1038,True,True,0,4.2.0,True,8,A0000A00043,Airport kiosk,2026-11-03 05:36:07Z,OhrTech/aleph/aleph:…,2026-11-05,1038,True,True,1,4.2.0,False,1 setting(s) failed#:package OhrTech.Management@*// Writes a CSV of every device's state against your bar: checked in recently, a recent security// patch, settings applied, the OhrTech Agent up to date and, optionally, your app installed. Open it in a spreadsheet or// attach it to your audit evidence.// OHR_TOKEN=ohrs_… dotnet run compliance-report.cs > devices.csv// OHR_TOKEN=ohrs_… dotnet run compliance-report.cs -- com.example.yourapp > devices.csv// Needs ViewDevices.using OhrTech.Management;
var requiredApp = args.FirstOrDefault();var checkInWithin = TimeSpan.FromHours(24);var patchWithin = TimeSpan.FromDays(90);
using var api = OhrManagementClient.ForServiceAccount( Environment.GetEnvironmentVariable("OHR_TOKEN") ?? throw new InvalidOperationException("Set OHR_TOKEN to a service account token."));
Console.WriteLine("device,serial,fleet,last_check_in,os_build,security_patch,agent,agent_current,settings_in_sync," + "settings_errors,app_version,compliant,reasons");foreach (var summary in await api.ListDevicesAsync()){ var d = await api.GetDeviceAsync(summary.DeviceId); var reasons = new List<string>();
if (d.LastCheckIn is not { } seen || DateTimeOffset.UtcNow - seen > checkInWithin) reasons.Add("not checked in for 24 hours"); if (!DateTime.TryParse(d.Os.SecurityPatch, out var patch)) reasons.Add("security patch not reported"); else if (DateTime.UtcNow - patch > patchWithin) reasons.Add("security patch over 90 days old"); if (d.Settings.InSync != true) reasons.Add("settings not applied yet"); if (d.Settings.Errors > 0) reasons.Add($"{d.Settings.Errors} setting(s) failed"); if (d.Agent.Outdated) reasons.Add("Agent update pending");
string? appVersion = null; if (requiredApp != null) { appVersion = (await api.ListInstalledAppsAsync(d.DeviceId)).FirstOrDefault(a => a.Package == requiredApp)?.Version; if (appVersion == null) reasons.Add($"{requiredApp} not installed"); }
Console.WriteLine(string.Join(",", d.DeviceId, Csv(d.Serial), Csv(d.FleetName), d.LastCheckIn?.ToString("u"), Csv(d.Os.Fingerprint), Csv(d.Os.SecurityPatch), d.Agent.Version, !d.Agent.Outdated, d.Settings.InSync, d.Settings.Errors, Csv(appVersion), reasons.Count == 0, Csv(string.Join("; ", reasons))));}
static string Csv(string? value) => value is null ? "" : value.IndexOfAny([',', '"', '\n']) < 0 ? value : $"\"{value.Replace("\"", "\"\"")}\"";How it works
Section titled “How it works”For each device, GET /v1/devices/{id} gives its last check-in, OS build and security patch level,
OhrTech Agent version and whether its settings applied, and GET /v1/devices/{id}/apps its installed
apps. A device is compliant when it checked in within 24 hours, runs a security patch from the last
90 days, applied its current settings without errors, runs the current Agent and, if you name one,
has your app installed. reasons says why not.
Make it yours
Section titled “Make it yours”- Require a minimum version of your app by comparing
app_version. - Check particular settings:
GET /v1/devices/{id}/settingsshows each one’sreportedvalue and status. - Keep the CSV from each month, as a record of your fleet’s state over time.