Microsoft Graph
Query the beta endpoint with KQL. Kustodian plans the requests, pushes what it can into $filter, and runs the rest locally.
users · applications · devices · groups …
A desktop KQL workbench for Microsoft Graph, Defender advanced hunting and Azure Resource Graph. One query language, completion that knows the schema, and results right beside your query.
Built on .NET 10 and React. Download for Windows 11, macOS 14+ and Linux.
// Apps with a secret past its end date applications | mv-expand cred = passwordCredentials | where todatetime(cred.endDateTime) < now() | summarize expired = count() by displayName, appId | order by expired desc
Screenshots use sample data.
Why Kustodian
Graph speaks OData, but $filter works on some properties and not others, and there are no joins or aggregates. You still page through results and parse the JSON yourself. Kustodian sends OData what the server can handle, then runs the rest of your KQL in memory: mv-expand, join, summarize and more.
GET /applications?$select=appId,displayName,passwordCredentials&$top=999 GET /applications?$skiptoken=… GET /applications?$skiptoken=… $filter on passwordCredentials/endDateTime: not supported → parse the JSON, flatten and compare dates in a script
applications | mv-expand cred = passwordCredentials | where todatetime(cred.endDateTime) < now() | summarize expired = count() by displayName → $filter where Graph supports it, the rest in memory
Three sources, one editor
Query the beta endpoint with KQL. Kustodian plans the requests, pushes what it can into $filter, and runs the rest locally.
users · applications · devices · groups …Hunting queries go straight to the service through security/runHuntingQuery, with the same completion and results.
DeviceProcessEvents · IdentityLogonEvents · EmailEvents …Inventory and posture across your Azure estate, scoped to the subscriptions you pick.
resources · securityresources …Explain
Explain shows exactly what a Graph query will do to your tenant, without sending anything.
Features
Completion and errors from each source’s schema, including nested and mv-expanded fields.
Virtualized grid, charts, JSON and diagnostics. Compare two runs. Export to CSV, JSON or Markdown.
Write {name} once and fill it at run time. Keep snippets and saved queries close.
Tabs survive restarts. History, saved queries and a command palette for everything else.
Send any request, like Graph Explorer, then open the response as a KQL tab to keep digging.
A shortcut for every action, and light and dark themes that follow your system.




Privacy & security
Kustodian is a desktop app that signs in as you. There is no Kustodian service in the middle, and nothing leaves your machine except calls to Microsoft.
Permissions
Kustodian uses delegated permissions: it reads what the app you sign in with is allowed to, and never more than your own roles allow.
Microsoft’s public client, already consented in most tenants. A good start for common Graph and Azure Resource Graph queries, but its permissions are fixed: security data, audit logs and advanced hunting are often out of reach.
Grant exactly the read permissions your queries need. Kustodian can create the app for you, with the smallest set of permissions that covers your tables; an admin grants consent once.
Get started
Get the package for your platform from the latest release. Builds are self-contained: no .NET to install.
Kustodian-<version>-x64.msi (or -arm64.msi) installs for you alone, no admin rights needed. Add ALLUSERS=1 to install for everyone. Or extract Kustodian-<version>-win-x64.zip (or -win-arm64.zip) anywhere; unblock it in Properties first. On an unsigned build, SmartScreen asks once: More info → Run anyway.
> msiexec /i Kustodian-<version>-x64.msi ALLUSERS=1
Open Kustodian-<version>-osx-arm64.dmg (or -osx-x64.dmg; the same app is in the .zip) and drag Kustodian to Applications. The app is signed with a Developer ID and notarized by Apple, so it opens without a prompt. If a release’s notes say it’s ad-hoc signed, allow the first open in System Settings → Privacy & Security → Open Anyway.
Needs WebKitGTK 4.1, libsecret and libnotify from your distribution. chmod +x Kustodian-<version>-x86_64.AppImage, then run it; it runs without FUSE (it extracts itself), and with fuse3's fusermount, which WebKitGTK usually brings, it mounts instead. Or extract Kustodian-<version>-linux-x64.tar.gz and run ./Kustodian.
$ sudo apt-get install \ libwebkit2gtk-4.1-0 libsecret-1-0 \ libnotify4 $ sudo dnf install \ webkit2gtk4.1 libsecret \ libnotify
Then sign in with your work account and open your first tab. The install guide, step by step →
.NET SDK 10 and Node.js 22. On Linux, also the WebKitGTK 4.1 and libsecret development packages. The build embeds the web UI for you; no separate frontend step.
$ sudo apt-get install \ libwebkit2gtk-4.1-dev libsecret-1-dev $ git clone https://github.com/FrodeHus/kustodian $ cd kustodian $ dotnet run --project src/Kustodian
Issues, ideas and pull requests are welcome.