TUNO โ Intune Operations Tools
Sign in with your Microsoft Entra account to analyze, build and validate your endpoint security configuration โ starting with AppLocker policies.
Pop-up not working? Sign in without one โ
Runs entirely in your browser โ imported policy XML never leaves your session.
What do you want to do?
๐ฅ Endpoint security
Application control and device security posture.
AppLocker builder & validator
Scan a device with the PowerShell this tool hands you, upload what it wrote, and audit the result with the AppLockerInspector check set โ enforcement posture, broad principals, user-writable paths, risky wildcards, overly broad publisher rules โ now backed by the directory permissions, signatures and blocked executions only a device can report. Verify the Microsoft apps a locked-down estate still needs (OneDrive first among them) are actually allowed, add the missing rules publisher-first, and export policy XML for a GPO or a ready-to-import Intune custom profile. Runs entirely in the browser.
Defender status
The machines where Defender is silently off or outdated, before they become incident tickets: every Windows device's protection state โ real-time protection, tamper protection, malware protection, signature currency, overdue scans, pending reboots โ read in batches of twenty rather than one device at a time, with the tenant's own rollup beside it. A device that never reported protection state is its own bucket, never healthy by omission; a flag the device did not report reads not reported, never off โ they are different answers. Reads only, no new permission. Export as Markdown or CSV.
Firewall & ASR coverage
Whether the Windows fleet actually has firewall and attack-surface-reduction enforcement, or just policy objects: every endpoint security policy โ settings catalog and the legacy intents older tenants still carry โ grouped into the portal's own disciplines, each with a verdict: covered, policies exist but none reaches anybody, or no policy at all. "Covered" is checked by construction โ a policy with no include and no tenant-wide target, or whose every assignment is an exclusion, reaches nobody and does not count. The Windows device count is the denominator: a gap on firewall or ASR is that many machines on local defaults. Reads only, no new permission. Export as Markdown or CSV.
Windows LAPS audit
Which Windows devices have an escrowed local administrator password, and how old it is โ not escrowed and stale are the two shapes of one finding, a LAPS policy that is not applying, found before the day somebody needs the password that is not there. Escrow metadata only: device names and backup times, under a permission that cannot return password values โ reading a password is a different act, and this tool does not have it. A device that cannot be matched to the escrow store is unknown, never counted as not escrowed; escrowed records for retired machines are listed, not ignored. Export as Markdown or CSV.
Secure Score visualizer
Microsoft's own measurement of this tenant, made explorable: the score with its gauge, how it sits against tenants of a similar size and against all tenants, the per-category breakdown with Microsoft's two comparison ticks on every bar, and the timeline of every reading Graph still holds. The improvement actions, ordered by the cheapest points first โ points still available weighted down by the user impact and implementation cost Microsoft publishes, with Microsoft's own stack ranking beside it and the ordering openly labelled as ours, not theirs. Graph remembers about ninety days, which is why this exports a snapshot you can upload back next quarter: the timeline then reaches past what the tenant can still be asked, with uploaded points drawn as their own marks and a snapshot from a different tenant refused rather than merged. Markdown for the monthly report, CSV for the controls and for the history. Asks for SecurityEvents.Read.All on the click. Reads only.
Endpoint security posture
The portal's Endpoint security blade, mirrored โ one read, three answers behind one rail. The disciplines: every endpoint security policy in the portal's own breakdown (antivirus, disk encryption, firewall, EDR, attack surface reduction, account protection, App Control), as the ๐ Policy overview's clickable cards โ plus two nodes the portal does not have: plain settings-catalog policies that configure Defender (MDE) or Microsoft Edge, found by their setting definition ids. ๐ฃ The impact brief: what a person will notice on their device, in end-user language, every statement derived from a policy actually present and naming it โ enforced-today and at-rollout never mixed, and a statement that only partly reaches the fleet says what happens to the rest: the remaining devices counted against the fleet, or nothing is staged to widen this where that is the truth; export as Markdown or Word for the rollout mail. ๐ Best practice: the tenant's actual setting values measured against learn.microsoft.com โ tamper protection, cloud protection, PUA, network protection, the three standard-protection ASR rules, silent BitLocker, firewall defaults, EDR onboarding, Edge SmartScreen โ each check with severity, remediation and the Learn page it stands on, and not reaching its own verdict when the right setting sits in a policy that reaches nobody. ๐ Secure Score gaps: these checks read policy, Microsoft Secure Score reads the estate, and where they disagree is the finding โ a check that passes while Microsoft still holds the points is almost never the policy, it is devices that never onboarded; every Microsoft gap no check covers is listed anyway, so a hole in the check set shows up instead of hiding. Reads only, and the posture read costs no new permission โ the Secure Score node is a separate button because it needs SecurityEvents.Read.All.
๐ Assignments & scope
Who gets what, and why.
Group Analyzer
Name an Entra group and see everything Intune sends to its members: configuration profiles, compliance, scripts and remediations, applications, app protection and configuration, enrolment restrictions, Autopilot and update profiles. Exclusions count as answers โ a policy that deliberately does not reach this group is shown alongside the ones that do. Assignments inherited from a parent group are included and say which parent they came through, and tenant-wide All Users / All Devices targets can be switched on to show the full effective surface. Or sweep the whole tenant โ one read per surface matched against every group, so the cost barely grows with the group count โ and get which groups receive what, which receive nothing, and which assignments point at groups that no longer exist. The sweep has two faces over the one read: a ranked table, and an assignment matrix โ groups down the side, surfaces across the top, exclusions as their own red counts, with an opt-in check for groups that are empty. Export as Markdown, CSV or a standalone HTML report.
Assignment what-if
Before you change a membership: pick a user or a device, name a group, and see the delta โ policies gained, policies lost, applications that will install and applications that will be uninstalled. Joining brings the group's own parents with it; leaving only severs a direct edge, and a membership held through nesting says so instead of pretending it can be removed. An exclusion met by joining is shown as a loss, because joining a group can take policy away. Or put two to four groups side by side and see what each receives that the others do not. A simulation, not a promise โ filtered assignments stay โmayโ, and reads only.
Assignment health
The assignments that exist and reach nobody, in one place โ every finding the same shape of problem: something that looks configured and is not. Policies assigned to empty groups, which have never applied and never will; assignments naming deleted groups, which target nobody silently; unassigned policies; policies whose every assignment is an exclusion, so there is nothing to exclude from; a group both included and excluded on one policy, where the exclusion wins and the include reads as reach. Optionally, the deployments Graph reports as failing โ for the surfaces that keep a cheap status, with the ones that do not named as unchecked rather than passed off as healthy.
Assignment editor UPDATED writes to the tenant
Add or remove a group across many policies at once โ the thing the portal makes you do one blade at a time. Device configurations, settings catalog, compliance and administrative templates; scripts and applications are deliberately out, because each would be a new write permission. The pipeline is the tool: read, dry-run with the group's name and member count, an automatic backup file of every assignment about to change, removals confirmed by typing the group's name โ then the write, with each policy re-read first (someone else's edit is skipped as drifted, never overwritten) and read back after, so โdoneโ is the tenant's word rather than a status code. No delete, no rename, ever.
Assignment filters UPDATED writes to the tenant
Assignment filters are load-bearing and invisible: every โmay reach itโ in the Device analyzer is a filter in the way, and nothing in the portal shows what breaks if you change one. Every filter with its platform and rule, and โ as its own optional read โ per-filter usage: which assignments on which policies reference it, matched across the Group Analyzer's own surface table. Until that scan runs, the used-by column is absent, not zero. Then the write half, under the editor's rules: create, edit with a drift stop (a filter changed since you loaded it is refused, never overwritten), read-back after every write โ and delete refused while anything references it, checked against the tenant at the moment of the click, because deleting a used filter silently widens every assignment that carried it.
Device analyzer
The same assignment graph, walked backwards from one machine: why did THIS device get that policy? Find it by name, serial, either of its two GUIDs โ or by its primary user, since the ticket names the person far more often than the serial: a UPN resolves to their devices, with a pick list when they have more than one. Then see which of its own groups, which of its primary user's groups, or which tenant-wide target put each policy there. The last check-in sits at the top of the answer, because everything else is what Intune intends and a policy assigned minutes ago has not landed yet. Where the device has reported back, intended and actual sit in adjacent columns; where it has not, the state is unknown rather than assumed. Filtered assignments say may reach it โ a browser cannot evaluate a filter rule, and this one does not pretend to. Export as Markdown, CSV or a standalone HTML report.
๐ฆ Configuration
Read it out, keep a copy, put it back.
Policy overview UPDATED
Every configured policy in the tenant as clickable cards โ the sister tool ENCA's list-policies view, Intune-side-out. The thirteen surfaces sit on top as stat cards that double as filters: each says how many objects it holds and how many actually reach somebody, so "what does this tenant even have" is answered before any scrolling. One flat card grid below, filterable by verdict โ Assigned means reaching somebody by construction, excluded-only is its own finding, and an assignment filter caps reach at may. A card click opens the full policy with its settings, through the documenter's own popout โ same read, same redaction, one implementation. A surface that could not be read is a named โ card, never a silent zero. Reads only, no new permission.
Backup configuration UPDATED
Read the configuration surface โ device profiles, settings catalog with their settings, compliance with their scheduled actions, administrative templates with their definition values, and platform scripts with their bodies โ and write one .zip in your browser. The folder layout matches the PowerShell original exactly, so the two are interchangeable. Reads only, one permission. The manifest indexes every file and records what the archive cannot restore, because Graph never returns secrets and a script without a body is a file you can read but not put back. And now the other direction: restore from an archive โ create only, an editable [Restored] prefix on everything, a collision stop checked fresh before each create, administrative-template child writes included in the dry run, everything arriving unassigned by design. Widened at beta 10426 (R15): twenty-four areas, a SHA-256 per file with the manifest written last, an offline verify that names modified, missing and untracked files โ and assignments that export to assignments.json and import back, same tenant only, through the assignment editor's own write discipline.
Configuration documenter UPDATED
Every policy in the tenant, in one list you can filter and read โ settings expanded underneath, assignments resolved to group names. Then write it down: Markdown for a wiki, a standalone HTML page, or a Word document for the auditor who will edit it. Secrets are redacted and that cannot be switched off โ a script body or a certificate in a document somebody emails is a disclosure you cannot recall. A section that could not be read is named as unreadable rather than left out silently.
Settings search
โWhich policies configure BitLocker, and to what value?โ โ answered from the setting definitions rather than the policy names. One read brings Microsoft's settings-catalog definition catalog, roughly seventeen thousand entries, searched as you type with ranked matching over names, keywords and descriptions. A second, separate read brings the tenant's own settings-catalog policies, so each result can say who sets it and to what โ and until that read has run, the column says absent rather than empty. Values pass the documenter's redaction gate: a settings search is exactly the tool somebody uses to hunt for โpasswordโ, and it will not become a disclosure engine with a search box.
macOS baseline NEW writes to the tenant
Match the tenant's macOS policies against the CloudFellows baseline โ MACOS R26.xx names, versions compared โ export the catalog from the baseline tenant, import what is missing anywhere else.
Setting conflict scan UPDATED
The same setting, configured to different values in two policies โ found by setting identity, never by display name: the definition id in the settings catalog, definition-plus-category in administrative templates, the typed property within one policy type in device configurations. And one step past the tools that inspired it: a collision is only a conflict if the two policies can meet on a device, so every finding carries a verdict โ can collide (overlapping reach), may collide (different groups can share members; a filter is in the way), or cannot (one side reaches nobody as assigned). Redacted values are never compared โ two secrets are not known to be equal. Reads only, through the documenter's own read.
๐ Monitoring
What changed, and who changed it.
Compliance report UPDATED
The tenant's compliance story on one page: the estate rolled up โ compliant, non-compliant, in grace, unknown โ every compliance policy with its verdicts, and which setting is failing where Graph keeps a per-setting summary. Stale is its own column, not a flavour of compliant: a device that has not checked in for the threshold you set (default 30 days) is counted separately, and a compliant-but-stale machine sits in both columns with the tension stated, because its verdict is as old as its last check-in. And coverage โ the platforms nothing evaluates: enrolled devices with no compliance policy that reaches anybody, with the tenant's compliant-by-default lean read and stated, because that setting decides whether an uncovered platform silently passes Conditional Access. A policy whose statuses could not be read is listed with the gap stated โ unknown is not clean. Reads only, on permissions earlier tools already brought in.
Entra device cleanup NEW writes to the tenant
Stale directory devices, staged out in two deliberate steps: disable at 30 days of silence, delete at 90 โ and only what is already disabled. Last contact is the directory's own approximateLastSignInDateTime; a device that never reported one is unknown, not stale, and gets no action offered. Every write is preceded by a fresh per-device read (a device that woke up or was re-enabled is refused, not overruled) and followed by a read-back; deletes require the word typed, because the BitLocker recovery keys go with the object. One Markdown report carries the estate, every action taken, and everything deliberately not done. Writes to the tenant โ and Graph gates these writes on your directory role, said before the run.
Change audit
Who changed which policy, profile, script, app assignment or enrolment setting โ when, from where, and what actually moved, field by field, rather than two blobs of JSON printed side by side. Two views over one read: policy changes with a severity on each, and all events filtered by actor, activity, category and result. Incident windows down to the last hour, review windows out to thirty days โ which is where Intune's audit retention ends, and the tool says so rather than offering a window that returns a confidently empty answer.
๐ก Access & roles
Who can change Intune, and how much of it.
Intune RBAC
Every Intune role definition, built-in and custom, with each assignment under it, the users and groups in it resolved to names, the scope tags it is limited to and what it is scoped over โ in one page rather than one blade per role. Roles with nobody in them are one toggle away, because an empty role is a fact worth seeing and it is one membership change from being live. Concentrations worth a second look are flagged as observations, never a score. And the line nothing else says: this is Intune RBAC only, so the Entra directory roles that also grant full Intune access are not in it. Export as Markdown, CSV or a standalone HTML report.
Multi-admin approval
Whether multi-admin approval is protecting anything: every approval policy and what its type gates, the requests of a chosen window โ pending, approved, rejected, and how long approval actually takes โ and coverage computed the way MAA works: a gate applies to its operation type tenant-wide, and a category with no policy has no gate at all. A policy whose approver groups hold nobody is flagged as a gate nobody can open. The admins-without-approval-rights list carries the Intune-RBAC-only warning, because the Entra directory admins who can change the most are not in it. Reads only, no new permission. Export as Markdown or CSV.
Restricted AUs
Create and manage restricted management administrative units โ the only place in Entra where membership can be put out of reach of every tenant-wide role. Inside one, only a principal holding a role scoped to that unit may change the members; Global Administrator and Privileged Role Administrator can manage the unit but not what is in it. List every unit with its members and its scoped administrators, create one (the creator becomes its administrator by default, because a unit nobody is scoped to is a vault nobody can open), rename it, delete it, and add or remove members and grants. ๐ง Frozen members are flagged: a role-assignable group inside a restricted unit has members nobody at all can change. Ported from ENCA's T27 without its Conditional Access baseline. Writes to the tenant.
Group migration
A group is made role-assignable for one side effect: only Global Administrator or Privileged Role Administrator may change its members. A restricted management administrative unit does that job better โ it lets you name who may manage the group โ and drops the role-assignable costs: the 500-per-tenant cap, no dynamic membership, no nesting control. The two can never be combined; a group that is both is a group whose members nobody can edit. Because isAssignableToRole is immutable this is a recreate, so the new group has a new object id: the tool repoints the four Intune surfaces it is already permitted to write, names every reference it cannot, and says out loud that anything outside Intune is invisible to it. The original is renamed aside as your rollback, never deleted. Writes to the tenant.
โ About this app
What changed, where it is heading, how it works.
What's new
Everything added or changed, per build.
Roadmap
Where TUNO is heading โ shipped, next, later.
Help
What each tool does, what it reads, and the security model.
๐ AppLocker builder & validator
Scan a device, upload what the scan produced, edit the policy here, and export it as XML for a GPO or as a ready-to-import Intune custom profile. Everything is audited in the browser with the check set from Spencer Alessi's AppLockerInspector, and the Microsoft coverage table answers the question every lockdown discovers too late: can a standard user still run OneDrive, Teams, Edge and Office? Nothing is uploaded โ the file is read in this tab and stays there. You can skip step 1 entirely and import a plain policy XML instead; the scan is what lets the tool see the ACLs a browser cannot.
Scan a device optional โ but it is what makes the audit real
Run this on a clean reference machine โ a freshly built image with your standard applications installed and nobody yet working in it. Not your own laptop. It reads directory permissions, signatures and the AppLocker event log, builds a publisher-first rule set from what it finds, and writes one .json bundle. It changes nothing on the device.
Why the machine matters more than the switches. The policy this produces says: everything on that machine is allowed, and nothing else is. From a clean image that is a baseline. From a device someone has used for two years it allows two years of accumulation โ installers in Downloads, a dev toolchain, whatever a colleague once ran from a zip โ which is the exact permission AppLocker is deployed to take away. The scan checks whether the machine looks clean and says so loudly if it does not, but it cannot refuse to run.
What the resulting policy allows: what is on the reference image ยท anything the Intune Management Extension delivers, named explicitly so trimming a default rule cannot silently kill software deployment ยท anything a local administrator runs. Everything else is blocked โ a standard user's own profile above all.
7 companion scripts โ cleanup pair, IT-TOOLS provisioning pair, events-collection set โพ
The fourth and fifth are the IT-TOOLS provisioning pair โ the fourth creates the house folders with the admin-only ACL the standing allow rules depend on (and proves SYSTEM can write to IT-TOOLS\LOGS, where the house scripts log), the fifth is its detection half so the pair ships as an Intune Remediation. Deploy it BEFORE the policy, because ProgramData lets a standard user create missing subfolders and own them, which would turn the standing allow into a bypass โ and unlike the cleanup pair, leave it assigned: a folder that drifts writable after provisioning is exactly what its detection exists to catch. The second and third are for devices that already carry an AppLocker policy โ the cleanup that runs before the new policy is deployed, and its detection half for shipping that pair as an Intune Remediation. Order matters: unassign the old profile, run the cleanup, deploy under a new grouping. The full procedure is in step 5. The last three are the events-collection set โ a Remediation pair whose detection always triggers (the "remediation" IS the harvest: CodeIntegrity and AppLocker events into CSV/XML, an HTML report, and a JSON bundle) plus the Live Response zipper for fetching the results. Upload the AppControlEvents_Bundle_*.log a device produces and this tool matches every blocked or audited event against the draft on screen, with a recommendation per file โ the audit month, made legible.
๐ Deploy the pairs as Intune Remediations from here writes to your tenant
No Sysinternals needed. Write access is worked out natively from each directory's DACL, with Deny entries honoured. AaronLocker and the walkthroughs based on it shell out to AccessChk.exe and parse its output; this does not, which is why there is nothing else to download โ and its own alternate-data-stream check ORs the rights across every matching entry without looking at whether one of them is a Deny, so a Deny there reads as a grant. Nothing here is downloaded or executed from anywhere but this site.
How to run it, and what each switch is for
The normal run. Elevated PowerShell โ unelevated it cannot read every DACL or the event logs, and the bundle records that the run was partial rather than pretending it was complete.
Set-ExecutionPolicy -Scope Process Bypass -Force .\Invoke-TunoAppLockerScan.ps1
It writes three files next to itself: TunoAppLockerScan-<DEVICE>-<stamp>.json (upload this one), plus an Audit and an Enforce .xml for direct GPO use.
Include the per-user installs. OneDrive and Teams install into the user's profile, which is user-writable by definition โ they are the applications a first AppLocker rollout breaks, every time.
.\Invoke-TunoAppLockerScan.ps1 -Scope System,ProgramFiles,ProgramData `
-Path "$env:LOCALAPPDATA\Microsoft\OneDrive","$env:LOCALAPPDATA\Microsoft\Teams"
Switches worth knowing:
-Scopeโ which roots to walk:System,ProgramFiles,ProgramData,UserProfiles,Custom. Default isSystem,ProgramFiles.-KnownAdminโ groups that are administrators here but are not in the local Administrators group, e.g."CONTOSO\Workstation-Admins". Write access granted to them stops being reported as a hole.-PublisherRuleGranularityโ how specific the generated rules are, fromPublishertoPublisherProductBinaryVersion. DefaultPublisherProductBinary.-EventDaysBackโ how far back to read the AppLocker logs. Default 30.-DeepScanโ report every writable directory instead of stopping at the first one on each branch. Slower, more evidence.-SkipRuleGenerationโ collect the evidence and let this tool build the rules instead.
Scan more than one machine. A laptop build and a kiosk build do not have the same holes. Run it on each, and work through the bundles one at a time.
Upload what the scan wrote โ the .json bundle.
It carries the generated rule set, the policy the device was really running, the directories a standard user can write to, the unsigned binaries sitting in them, and what AppLocker has already blocked. The tool loads the generated AuditOnly policy by default and you can switch to either of the others once it is open.
No scan? A plain policy XML works too โ a GPO export (Group Policy Management Editor โ Application Control Policies โ AppLocker โ right-click โ Export Policyโฆ) or Get-AppLockerPolicy -Effective -Xml > policy.xml. You lose the ACL and event evidence, which is exactly the part a browser cannot work out for itself.
Or load the sample policy to see what the audit and the Microsoft coverage check produce.
Coming back mid-loop with only an events bundle? Upload it with the same button โ the fleet evidence card appears below, and it can pull the deployed AppLocker profile straight from the tenant to judge against, so nothing needs hunting for on disk.
๐ What's new
Everything added or changed in TUNO, newest first.
๐ Group Analyzer
A group is a shared handle: one admin targets a compliance policy at it, another assigns four applications, a third puts an Autopilot profile on it โ and then somebody adds a user, and none of that is visible at the moment of the change. This reads it back out of the tenant. Intune surfaces after Ugur Koc's Get Group Assignments; the analysis machinery is ENCA's Group Analyzer. Reads only โ each surface asks for its own scope on the click, and nothing is written or stored.
Intune only, on purpose. Where a group is used in Conditional Access, group-based licensing, directory roles or access packages is the same question asked of Entra, and answering it needs permissions TUNO has no reason to hold. That is ENCA's Group Analyzer, which is signed in for exactly that.
Off by default because it is loud and it is the same answer for every group: a tenant-wide assignment is not about this group. It is on the list because the question an admin is usually asking โ what actually lands on these devices โ has a bigger answer than the group's own assignments, and nothing else on this page would tell them so.
๐ Change audit
Somebody changed something and a fleet of devices behaved differently the next morning. This reads the tenant's own audit log and says who, what, when and โ the part the portal will not give you โ which fields moved. After Ugur Koc's Policy Changes Monitor and Get Intune Audit Logs; the diff is ENCA's Change audit. Reads only.
Thirty days is the whole log. Intune keeps audit data for thirty days and then it is gone from the service โ not archived, not slower to reach, gone. There is deliberately no ninety-day option here: ENCA offers one because the directory audit log holds longer, and pointing that at Intune would return an empty answer for days thirty-one to ninety that looks exactly like a quiet tenant.
Pick the window, read once, then filter what was read โ changing a filter costs nothing and asks the tenant nothing. The category, operation and actor lists are built from what your tenant actually emitted in the window, never from a fixed list: the script this borrows from ships one containing values Graph never returns, so picking one gave you nothing and looked like a quiet tenant.
๐งน Entra device cleanup writes to the tenant
Stale devices leave in two deliberate steps: no contact for 30 days โ disable (reversible โ the portal can re-enable); disabled AND silent for 90 โ delete. A 90-day device that is still enabled is a disable candidate, never a delete โ the gap between the steps is where somebody notices the laptop in the drawer still matters. Last contact is the directory's approximateLastSignInDateTime: the name says approximate, and a device that never reported one is unknown, not stale โ no action is offered on a guess.
Every write is checked twice. A fresh per-device read before it (signed in since the plan โ refused, it woke up; re-enabled since โ refused, somebody wants it back) and a read-back after it. Deleting a device object deletes its BitLocker recovery keys โ the delete button arms only after typing DELETE โ and an Autopilot-registered device is refused by the service until deregistered. Graph gates device writes on your directory role (Cloud Device Administrator or Intune Administrator among them): consent alone does not open them, and a refusal is explained as who you are, not what TUNO may do. ๐ One Markdown report carries the estate, the actions, and everything deliberately not done.
๐ฆ Backup configuration
Everything Intune holds as configuration, read out and written to one .zip in this tab. After Ugur Koc's Backup Intune Configuration โ the folder layout and file names are his, exactly, so an archive written here can be restored by his script and one written by his script can be read back here. Reads only, and one permission: DeviceManagementConfiguration.Read.All, asked on the click.
Two things a backup cannot contain, said here rather than discovered at restore. Graph never returns secret values โ encrypted OMA-URI settings, passwords and certificate payloads come back as references only, and after a restore they must be entered again by hand. And a script saved without its body is a file you can read but not put back; the manifest records which files those are rather than leaving you to find out.
The original has this as a switch and mentions the consequence only in its notes. It is here because a script body can be large and you may only want the inventory โ but the archive it produces will not put a script back, and the manifest marks every file it applies to so that can be checked before anyone relies on it.
Three of the five areas cost an extra read per object. A settings-catalog policy's settings, an administrative template's definition values and a script's body are not on the list endpoint โ it returns a count, or a null, where the content should be. Those run several at a time here rather than one after another, and an object whose detail cannot be read is left out of the archive rather than written without it: a policy restored with the right name and no settings is worse than one that is visibly missing.
๐ฅ Restore from an archive writes to the tenant
Load a backup โ this tool's or the original script's, the layout is shared โ pick objects, dry-run, apply. Create only: nothing of yours is patched or deleted (the one exception: an administrative template this restore half-created and failed to finish is rolled back โ its own mess, not yours). Every object arrives under an editable [Restored] prefix and unassigned โ a group GUID from the source tenant either does not exist here or names a different group, so assignments do not travel. A name that already exists in the tenant stops that object: skipped as collided, checked fresh immediately before each create, never overwritten and never duplicated silently. The write permission is asked at the apply, never before.
๐ Verify an archive โ offline, no sign-in
Every file in a TUNO archive (build 10426 on) carries a SHA-256 in the manifest, and the manifest is written last โ its presence is what marks a backup complete. Load an archive and this recomputes every hash in the tab: modified, missing and untracked files are named, an archive without a manifest is called what it is โ a backup that never finished โ and an older archive is called unverifiable rather than quietly passed. After TenuVault's verify (MIT).
๐ Policy overview
Every configured object in the tenant as clickable cards โ ENCA's list-policies view, Intune-side-out. The read is the ๐ Configuration documenter's own thirteen-surface read โ one implementation, so the two tools cannot disagree about one tenant โ and a card click opens the documenter's popout with the full settings, redaction included. The surface cards on top double as filters: click one to see only it, click again for everything; the verdict chips do the same. ๐ Cards or โฐ List โ the same objects either way: cards to scan a tenant you do not know, the table to compare a column down a long list.
The verdict is the house claim, not a new one. Assigned means at least one include or tenant-wide target โ reaching somebody by construction. Excluded-only is its own verdict, not a flavour of unassigned: the policy has assignments and every one says "not you". An assignment filter caps reach at may, worn on the card, because the rule is evaluated by the service against inventory a browser cannot see. Whether an included group is actually empty is the ๐ฉบ Assignment health tool's finding โ pointed at, not half-repeated. A surface that could not be read is a named โ card: unknown, never zero. Reads only.
๐ Configuration documenter
Thirteen configuration surfaces read once, then browsed and written down. The list is the tool you use on a Tuesday โ every policy in the tenant, filterable, settings expandable underneath, assignments resolved to group names. The document is the artefact an auditor asks for and nobody has. Coverage after Ugur Koc's IntuneDocumentation, whose plan decided which surfaces belong in a tenant document and in what order. Reads only.
Secrets are redacted, and there is no switch. A tenant document is the most widely circulated thing this tool can produce โ it goes to auditors, into wikis, onto shared drives. A script body, a certificate, a pre-shared key or an encrypted OMA-URI value in one of those is a disclosure that cannot be recalled. Every such field is replaced with a marker, so the document records that a value is set without carrying it.
Reimplemented, not forked. The original is licensed Elastic 2.0, which permits self-hosting but not offering the work as a service โ so this is built from its published coverage list and shares none of its code. It also has a server tier: its browser hands a token to its own backend, which calls Graph and streams the result back. TUNO has nowhere to put one, so the collection runs in this tab โ which is, as it happens, the more literal version of โruns in your browserโ.
Nothing to filter yet. These are switched off until you read the configuration. Platform is not here: it appears in the selection bar once there is something to filter, and stays with you as you scroll โ its list is built from what your tenant actually returns, with a count beside each entry, so it cannot exist before the read either.
Filters apply to what has already been read, so changing one costs nothing and asks the tenant nothing. The exports follow the SELECTION, not the filter โ the filter narrows what you are looking at, the tick boxes decide what you are sending. That separation is what lets you filter to find three policies, tick them, clear the filter and still export three. Everything is selected after a read; every export's header states how many of how many were chosen, so a partial document can never be mistaken for a complete one.
๐ฅ Device analyzer
Name one device โ or its user โ and get the answer to โwhy did this machine get that policyโ. The Group Analyzer asks what a group receives; this walks the same assignment graph backwards โ the groups the device is in, the groups its primary user is in, and the tenant-wide targets that need no group at all โ and says which of them put each policy here. Reads only.
Everything here is what Intune INTENDS. What the device actually has is whatever it collected the last time it talked to the service, so the last check-in sits at the top of the answer rather than in a details panel: a policy assigned ten minutes ago has not reached a machine that last synced yesterday. Where Graph reports what the device itself said โ configuration and compliance state โ that sits in its own column next to the assignment. Where it does not, or could not be read, the state is unknown, never โfineโ.
An assignment carrying a device filter is an open question and is shown as one. The filter rule is evaluated by the service against inventory a browser cannot see, and Graph has no call that answers โwould this filter include this deviceโ. Those rows say may reach it and name the filter. They will never say yes.
Matched exactly. The primary user is a search key โ the enrolment record names its user, so a UPN or the exact display name finds their machines with no extra permission โ and a GUID is tried three ways: the Intune device id, the Entra device id, and the user's object id, because which one is on a support ticket is a coin toss. When more than one device matches โ a user with a laptop and a phone is the normal case โ the matches are offered as a pick, never an error. Filtering the device inventory server-side is not supported for every property on every tenant; when a filter is refused the inventory is listed and matched here instead, and the report says which route answered.
On by default here, unlike the Group Analyzer, and that is deliberate. For a group an All Devices assignment is the same answer every time and says nothing about the group you asked about. For a device it is the answer: All Devices reaches this machine whatever else is true, so leaving those rows out would produce a report missing policy the device is definitely getting. All Users lands on the person, so on a device with no primary user it reaches nothing โ and the row says so.
๐ก Intune RBAC
Who can change Intune, in one page: every role definition โ built-in and custom โ each assignment under it, the users and groups in it resolved to names, and what it is scoped to. After Ugur Koc's Get Intune Role Assignments (MIT), whose question this is. The portal makes you click into each role one at a time, which is why nobody audits this. Every role carries a โ permissions button โ what it allows, the portal's per-category grid on one page, read on the click. A member that is a group carries a ๐ฅ members button: who is in it โ every user, nested groups flattened โ read live on the click, because whoever can change that group's membership can grant the role without holding it. Reads only: DeviceManagementRBAC.Read.All for the roles, User.Read.All and Group.Read.All to turn member GUIDs into names and, on the click, to expand a group.
This is Intune RBAC only, and that is the most important line on the page. The Entra directory roles โ Global Administrator, Intune Administrator โ grant full access to Intune and do not appear in deviceManagement/roleAssignments at all, so they are not here. An access review that reads this as the complete list of who can change Intune is missing the accounts with the most access. That sentence is in every export too.
Names are resolved in one call, not two per member. The original probes /users/{id} and then /groups/{id} for each member โ up to two round trips each, on a surface where a hundred members is ordinary. Every principal in the report goes through directoryObjects/getByIds here, a thousand at a time, and the response says what type each object is, so there is nothing to probe.
A role with nobody in it is a fact worth seeing rather than a row worth hiding โ it is one membership change away from being a live grant. Since build 10417 empty roles are shown by default, folded and dimmed; tick this to hide them where fourteen idle built-ins are noise. The toggle re-renders what has already been read and asks the tenant nothing.
The flags at the bottom are observations, not a score. An assignment scoped to all devices, a broad built-in role with a lot of members, a role whose members are all one nested group โ each is worth a second look, and whether any of them is wrong depends on things this tool cannot see. There is deliberately no number: a score invites somebody to chase it rather than read it.
๐ Group migration writes to the tenant
Turn a role-assignable security group into a plain one inside a restricted management administrative unit. Role-assignable was only ever a way to keep membership away from tenant-wide group administrators; a restricted unit does that and lets you name who may manage it, without the 500-per-tenant cap, the ban on dynamic membership or the loss of nesting control. Ported from the sister tool ENCA's โฆ Migrate, Intune-side-out.
The two can never be combined, and that is the state this tool exists to get you out of. A role-assignable group admits only Global Administrator or Privileged Role Administrator; a restricted unit blocks exactly those two; and neither can be assigned at administrative-unit scope. A group that is both is a group whose members nobody can edit โ ๐ง frozen. This tool refuses to create that state and names it where it already exists.
isAssignableToRole is immutable, so this is a recreate and the new group has a NEW OBJECT ID. That single fact is the whole risk. What TUNO may write it repoints โ the four surfaces T11 already writes, using T11's own engine so the drift check and the verify read-back are the ones in production. What it may not write it names: applications, scripts, app protection and configuration, enrolment restrictions, Autopilot, update rings. Each would need a write scope this registration does not declare, and adding one is a decision taken in the open rather than a side effect of a feature.
And everything outside Intune is invisible here โ Conditional Access, group-based licensing, Azure RBAC, app role assignments all address a group by object id. TUNO does not read them and will not pretend to. The original is renamed aside, never deleted: it keeps its members, stays role-assignable, and is your rollback until you have checked them.
Reads every role-assignable security group in the tenant โ Group.Read.All, plus AdministrativeUnit.Read.All for the restricted units. Nothing is written until a plan has been read and the group's name has been typed.
๐ก Restricted AUs writes to the tenant
A restricted management administrative unit takes its members out of reach of every tenant-wide role. Only a principal holding a role scoped to that unit can change them; Global Administrator and Privileged Role Administrator can manage the unit itself but not the objects inside it. This is where ๐ Group migration files a migrated group, and this is where those units are created and managed. Ported from the sister tool ENCA's T27, without its Conditional Access baseline.
The flag is immutable. isMemberManagementRestricted is set when a unit is created and can never be added to or removed from an existing one โ so there is no "convert": the editor changes the name and the description, and a unit under the right name without the flag has to be renamed aside and replaced.
A unit with no scoped administrator is a vault nobody can open. Tenant-wide roles are blocked by design, so somebody must hold a role scoped to it or its members are unmanageable by everyone. New units therefore get one at creation, defaulted to you โ whoever creates the unit is its administrator unless you say otherwise.
๐ง Frozen members are flagged. A role-assignable group inside a restricted unit admits only GA/PRA while the unit blocks exactly those two, so nobody at all can change its members. ๐ Group migration is the way out.
Reads every administrative unit in the tenant โ AdministrativeUnit.Read.All. Members and administrators are read per unit, when you open one. Graph gates these on your directory role as well as on consent: Privileged Role Administrator is the least privileged role that can manage restricted units.
New restricted administrative unit
Delete administrative unit
Deleting the unit does not delete its members โ they lose the restricted shield and become manageable tenant-wide again. That is the change worth pausing over: it happens to every member at once. Type DELETE to confirm.
๐ฎ Assignment what-if
What would change if this user or device joined โ or left โ that group? Policies gained, policies lost, applications that would install or be uninstalled, before anybody touches the membership. After Ugur Koc's Intune Assignment Checker (MIT); assignments are read through the Group Analyzer's own source table, so the two tools can never disagree about which surfaces exist. Reads only.
A simulation, not a promise. Assignment filters and dynamic-group rules are evaluated by the service against inventory a browser cannot see. Rows they touch say may, and the tool refuses to promote may to will in either direction. Tenant-wide assignments are not in the delta at all โ they apply whatever the groups say.
Joining brings the group's parents with it โ membership of a child is membership of its ancestors, and a what-if that forgot that would understate every join onto a nested group. Leaving only severs a direct edge: a membership held through another group cannot be resigned from here, and the answer says so rather than pretending.
๐ฉบ Assignment health
The assignments that exist and reach nobody. Policies assigned to empty groups; assignments naming deleted groups; unassigned policies; policies whose every assignment is an exclusion; one group both included and excluded on the same policy. After Ugur Koc's Intune Assignment Checker (MIT), whose idea this is: an assignment reaching an empty group is a finding, not a row. Reads only.
Findings, not a score. Whether an empty group is a mistake or a landing zone prepared for next quarter is something this tool cannot know โ it reports the fact and leaves the judgement where it belongs. And a surface that could not be read is unknown, never healthy: the absence of a finding is only evidence where something actually looked.
Status exists cheaply for device configurations, compliance policies, scripts and remediations. Settings catalog, ADMX, apps and app protection keep theirs behind the reports API and are named as unchecked rather than passed off as healthy.
๐ฆ Settings search
Search across what can be configured โ the settings-catalog definition catalog, roughly seventeen thousand definitions โ and then across what is: which of the tenant's policies set a matching definition, and to what value. The last piece of Ugur Koc's Intune Assignment Checker (MIT) worth having. The ๐ Configuration documenter searches the settings of policies it has read โ that finds a setting only if you already know which policy holds it; this searches the other way round. Reads only.
Two reads, deliberately separate. The catalog is Microsoft's and says nothing about your tenant; it is read once per session and searched in memory. The tenant read is the same one-request-per-policy cost the backup pays, and it is optional โ until it runs, the โset byโ column is absent, not empty. Secret-bearing values are redacted through the documenter's own gate, with no switch to turn that off.
โ๏ธ Setting conflict scan
The same setting configured to different values in two policies โ the value-shaped contradiction, where ๐ฉบ Assignment health finds the assignment-shaped ones. After IntuneShade (Alper Atar, MIT), with one step past it: a collision is only a conflict if the two policies can meet on a device, so every finding carries a verdict computed from the assignments โ and โmayโ means may, never yes. Reads only โ settings catalog, device configurations and administrative templates, through the ๐ documenter's own read: same redaction, same honesty about what could not be read.
Identity is exact or it is not claimed. Settings catalog settings match by definition id; administrative templates by definition and category; device configurations by typed property within one policy type. A settings-catalog policy and a legacy device configuration driving the same CSP are not matched โ that would be display-name matching, and a scan that guesses identities produces conflicts that do not exist. Findings, not a score: whether a real collision is a mistake or two deliberate baselines is not something this tool can know.
๐ macOS baseline writes to the tenant
The tenant's macOS policies matched against the CloudFellows macOS baseline, the sister tool ENCA's baseline machinery Intune-side-out. The name is the identity: a baseline policy starts with MACOS, carries its permanent release number R26.xx, and ends with a version โ the number is matched, the versions are compared segment-wise, and a number match the rest of the name contradicts is a clash, never silently trusted. Every baseline line lands in one bucket: up to date, outdated, newer than baseline, missing, number clash, or not in the baseline.
The baseline is authored on the baseline tenant (cloudfellows.dev), where this screen offers the export that writes the catalog file โ names, numbers, versions and the raw policy bodies. Everywhere else the tool compares against the bundled catalog or a loaded file, and can import what is missing: create-only through the Backup tool's own restore pipeline, canonical names kept (the name is the identity), everything arriving unassigned โ reach is โ๏ธ the Assignment editor's act.
๐งฉ Assignment filters writes to the tenant
The portal shows a filter's rule; it does not show what breaks if you change it. After IntuneShade (Alper Atar, MIT). Reading the list costs one request; the usage scan is one read per assignment surface โ the ๐ Group Analyzer's own source table, so the day a surface is added there it is counted here โ and until it runs the used-by column is absent, not zero.
The writes carry the โ๏ธ editor's rules: the write permission is asked at the click and never before; an edit is preceded by a fresh read and refused as drifted if anybody changed the filter since it was loaded; every write is followed by a read-back, so โdoneโ is the tenant's word. And the rule this tool exists for: delete is refused while any assignment references the filter โ verified against the tenant immediately before the act, with โcould not checkโ refusing too โ because a filter deleted while in use silently widens every assignment that carried it to the whole target group.
๐ Compliance report
The estate, the policies, and what is failing โ in one read instead of a morning of portal blades. After IntuneShade (Alper Atar, MIT). The numbers are Graph's cheap per-policy rollup, refreshed on Intune's schedule rather than live, and the report says so; the per-device answer for one machine โ intended versus actual, with the check-in first โ is the ๐ฅ Device analyzer's job and this page points there rather than half-doing it. Reads only, on permissions earlier tools already brought in.
Stale is its own column. A compliance verdict is whatever the device reported at its last check-in; a machine silent for six weeks โis compliantโ the way a photograph is the weather. Compliant-but-stale devices are counted in both columns, deliberately โ resolving that tension quietly in either direction would be a lie in that direction.
And the gap the rest of the report cannot show: coverage. A platform with enrolled devices and no compliance policy that reaches anybody is not failing anything โ there is nothing to fail โ and if the tenant marks unassigned devices as Compliant, those machines pass Conditional Access silently. The coverage section finds those platforms from the reads this report already does, and reads the tenant's compliant-by-default setting so the lean is stated, not footnoted. After Ugur Koc's Get Compliance Policy Coverage (MIT).
โ๏ธ Assignment editor writes to the tenant
Bulk assignment changes across device configurations, settings catalog, compliance policies and administrative templates โ after Maxime Guillemin's Intune Toolkit (MIT), whose question this is. The write discipline is TUNO's own: read โ plan โ backup โ confirm โ apply โ verify, in that order, enforced by the screen and not by your care. The write permission is asked for at the apply click and never before โ reading and planning cost nothing but reads.
What it will not do. Scripts and applications each need a write permission the registration does not hold, and adding one is a decision to take in the open, not a feature's side effect โ they are absent, not forgotten. Deleting and renaming policies stay in the Toolkit's own โAdvanced Actionsโ; neither belongs in a browser tool whose whole argument is that it cannot do much harm. And the assign call replaces the whole list, so every policy is re-read at apply time: one that changed since the plan was made is skipped as drifted rather than overwritten, because replacing a list somebody else just edited is how two admins erase each other.
๐บ Roadmap
Where TUNO is heading, laid out in time. Order and scope may change โ real-tenant feedback decides what lands first.
Each item carries a reference (Rnn) so it can be pointed at without quoting the title โ same rules as ENCA: a reference belongs to its item permanently, is never reused once the item ships, and the numbers are not a priority order. An item that ships moves from Next to Now with its reference intact.
In beta today running on the beta channel, not yet in production
Nothing โ this channel and the beta channel currently match. New work lands on beta first and appears here until it is promoted.
Now shipped & shipping
R01 ๐ AppLocker builder & validator live ยท build 3
Web-based AppLocker policy analysis after Spencer Alessi's AppLockerInspector: import the XML, get the weak/misconfigured/risky settings with severity, reason and recommendation โ plus the check the PowerShell original does not have: a Microsoft app coverage table that verifies OneDrive (per-user!), Teams, Edge, WebView2, Office click-to-run, the Intune agent and friends are actually allowed to run for a standard user, with one-click publisher-first fixes and XML export back into the GPO.
R04 ๐ Group Analyzer live ยท build 4
Name an Entra group, get everything Intune sends to its members across nine surfaces and twenty Graph endpoints. The machinery is ENCA's T19 โ source descriptors with their own scopes and runners, a flat hit shape, a failing source reported and never fatal, and ancestors rather than just the group itself. The Intune surface map and two behaviours come from Get Group Assignments (Ugur Koc). Exclusions are read as assignments: โthis policy does not reach youโ is the same question as โthis policy reaches youโ, and a report showing only inclusions is wrong half the time. Tenant-wide targets are a toggle โ All Users and All Devices land on the group's members too, so the effective surface is larger than the group's own assignments; off by default because it is the same answer for every group, on the list because nothing else would say so. And the thing neither parent has, which the script's own notes call out as not evaluated: nested group inheritance, so an assignment reaching this group through a parent is included and names the parent it came through. A surface that could not be read is never shown as empty โ it is shown as unknown, with the scope and the Intune RBAC role it would need.
The tenant sweep (beta 10319) asks the same question of every group at once. A sweep reads each surface once and matches every group against it, so three hundred groups is still twenty reads. The default scope takes the ids off the assignments themselves and enumerates nothing โ the fastest scope, and the one that cannot find unused groups, which the screen says where the choice is made rather than leaving an empty list to read as a clean bill of health. The counted scopes enumerate and can. Dangling references โ an assignment naming a group the directory no longer has โ are kept and flagged, because nothing in the portal will tell you.
Shipped Intune-only, and that is a change from what this card used to promise. It said the Entra areas would stay as context. They cannot: Conditional Access, group-based licensing, directory roles and access packages need scopes TUNO's registration does not hold and has no reason to. Half-reading them with the permissions to hand would be worse than not reading them, so the tool says so and points at ENCA, which is signed in for exactly that.
R05 ๐ Change audit live ยท build 4
One tool over deviceManagement/auditEvents, two views, one read โ after Ugur Koc's Policy Changes Monitor and Get Intune Audit Logs. Policy changes carries a severity read off the activity; all events filters by actor, activity, category and result with wildcards honoured as wildcards. The field-level diff is ENCA's T16, ported, and it is the reason to use this rather than the portal: modifiedProperties values arrive as JSON strings, sometimes double-encoded, sometimes wrapped in a one-element array, and the useful answer is a list of what moved โ with assignment lists compared as sets, so you see added and removed rather than two blobs.
Three upstream bugs fixed. The two scripts window the same endpoint two different ways and a bare date means midnight, so โthe last dayโ was anything between a minute and 24 hours โ full ISO-8601 UTC in both. The fixed category list contains values Graph never emits, so choosing one returned nothing and read as a quiet tenant โ the categories come from the tenant's own data. And the policy view is not capped at five rows after paging everything, which is what the original does. A fourth, smaller one: every resource on a record is inspected rather than only the first, because an assignment change puts the policy in slot 0 and the group in slot 1.
The windows stop at 30 days, and that is the honest limit rather than a shortcut. Intune keeps audit data for thirty days and then it is gone from the service. ENCA offers a ninety-day review window because the directory audit log holds longer; the same option here would return an empty answer for days thirty-one to ninety that looks exactly like a quiet tenant.
R08 ๐ฆ Backup Intune configuration live ยท build 5
After Ugur Koc's Backup Intune Configuration. Five areas over ten Graph endpoints, written to one .zip in the browser. The folder layout and file names are his, exactly โ restore is driven by folder names in both his script and R09, so an archive written here restores with his and one written by his reads back here. Reads only, one scope. Three of the five areas cost an extra request per object because the list endpoint returns a count or a null where the content should be; those run several at a time rather than in series with a sleep, which is what the original does.
An object whose detail could not be read is left OUT of the archive, not written without it. A settings-catalog policy restored with the right name and no settings is worse than one that is visibly missing, because the first looks like it worked. An area that could not be read at all marks the whole archive partial, in the manifest and on screen.
The manifest says what the archive cannot do. It keeps the original's four fields so the shape stays familiar and adds an index of every file with its type, surface and whether it is restorable, plus the tenant it came from โ six months later the question is โis this the right tenantโ. Two limits are stated up front rather than found at restore: Graph never returns secret values, so encrypted OMA-URI settings, passwords and certificates are references that must be re-entered by hand; and a script saved without its body cannot be put back, which the original's own switch produces silently.
Five areas is a floor, not a ceiling, and an archive nobody can verify is a file you hope is a backup โ R15 shipped in beta 10426: twenty-four areas, a SHA-256 per file with an offline verify, and assignments that export and import โ R16 compares two of them without a tenant.
R06 ๐ Configuration documenter live ยท build 5
Thirteen configuration surfaces read once, then browsed and written down โ two views over one read, because you browse what you are about to document. The list is the Tuesday tool: every policy in the tenant, filterable by name, setting, platform and whether it is assigned to anything, with the settings expandable underneath and assignments resolved to group names. The document is what an auditor asks for. Markdown for a wiki, a standalone HTML page that prints cleanly, and a Word document with real Word tables rather than a run of paragraphs somebody has to reformat. The filters apply to the exports, and every export header states how many of how many objects it holds โ a narrowed document cannot be mistaken for a complete one.
Redaction is not a setting. This is the most widely circulated artefact TUNO produces โ auditors, wikis, shared drives โ and a script body, a certificate, a pre-shared key or an encrypted OMA-URI value in one of those is a disclosure that cannot be recalled. Every such field is replaced with a marker recording that a value is set without carrying it, and there is deliberately no switch to turn it off.
Reimplemented, not forked โ the original is Elastic 2.0, which permits self-hosting but not offering the work as a service, so this is built from its published coverage list and shares none of its code. And unlike a backup, a policy whose settings could not be read is still listed, with the gap stated: a document that admits what it does not know is more useful than one missing the object entirely. PDF next
R03 ๐ฅ Intune device analyzer live ยท build 5
R04 read from the other end. Name a device โ by name, serial, or either of the two GUIDs every machine has โ and the same assignment graph is walked backwards: the groups the device itself is in, the groups its primary user is in, and the tenant-wide targets that name no group at all. Every row says which of those put the policy there. The endpoint list is not a second copy: T06 builds a match set and hands it to the Group Analyzer's own source table, because the first time somebody added a surface to one and not the other, this tool would have started reporting a device as unaffected by a workload it never looked at.
Tenant-wide targets are ON here, and that is the difference from R04 rather than a preference. For a group, All Devices is the same answer every time and says nothing about the group you asked about. For a device it is the answer โ All Devices reaches this machine whatever else is true โ so leaving those rows out would produce a report missing policy the device is definitely getting. All Users lands on the person, so on a device with no primary user it reaches nothing, and the row says that rather than being quietly dropped.
Intended and actual are two columns, and the gap between them is the point. Everything read from an assignment is what Intune intends; what the machine has is whatever it collected at its last check-in, so the check-in time is the first thing on the page and the report states plainly that a policy assigned minutes ago has not applied. Where deviceConfigurationStates and deviceCompliancePolicyStates answer, the device's own verdict sits beside the assignment. Where they 403, come back empty, or cannot be matched to a policy with certainty โ two policies sharing a name is enough โ the state is unknown. Never โfineโ by omission.
A filtered assignment is an open question and is shown as one. The filter rule is evaluated by the service against inventory a browser cannot see, and there is no Graph call that answers โwould this filter include this deviceโ. Those rows say may reach it and name the filter; they never say yes. Reads DeviceManagementManagedDevices.Read.All and R04's scopes, plus one new one: Device.Read.All, because the Entra device object is not the Intune enrolment record and only the directory can say which groups a machine is in.
R07 ๐ก Intune role assignments live ยท build 5
After Ugur Koc's Get Intune Role Assignments (MIT), whose question this is. Every role definition, built-in and custom, each assignment under it, the users and groups in it resolved to names, its scope tags and what it is scoped over โ one page instead of one portal blade per role, which is why nobody audits this. Names are resolved in one call rather than two per member: the original probes /users/{id} and then /groups/{id} for each principal, and directoryObjects/getByIds answers a thousand at once and says what type each object is, so there is nothing to probe.
Two things the original does not read, both of which change the answer. Scope tags, which are how a tenant gives a regional helpdesk a role over only its own devices โ a report that omits them overstates every scoped assignment. And the scope itself: scopeType and resourceScopes are read together, so โall devicesโ and โGraph did not sayโ are different answers here. The original falls back to the literal string โAllโ when resourceScopes is empty, which is right often enough to be dangerous.
Empty roles are a toggle, not a hidden row. A role with nobody in it is one membership change from being a live grant. The toggle re-renders what has already been read and asks the tenant nothing.
Concentrations are OBSERVATIONS and there is deliberately no score. An assignment scoped to all devices; a broad built-in role with a lot of members, at a threshold that is stated on the screen because it is arbitrary; a role whose members are all one group, where whoever can change that group's membership can grant the role without holding it. Whether any of those is wrong depends on things this tool cannot see, and a number would invite somebody to chase it rather than read it.
And the sentence neither the script nor the portal says, which is on the screen and in all three exports: this is Intune RBAC only. Global Administrator and Intune Administrator are Entra directory roles, they grant full access to Intune, and they do not appear in deviceManagement/roleAssignments at all. An access review that takes this for the whole list is missing the accounts with the most access.
R13 โ๏ธ Assignment editor live ยท build 8 writes to the tenant
After Intune Toolkit by Maxime Guillemin (MIT) โ a WPF application that does the thing every admin wants and the portal makes slow: add and remove assignments in bulk, across settings catalog, device configuration, compliance, administrative templates, endpoint security intents, Autopilot, app configuration, every application type and every script type. With filters and install intent. Plus backup and restore of the assignments themselves, which is a smaller and more useful thing than R08's full configuration archive: you can put assignments back without touching the policies.
This would be the second thing in TUNO that writes, and the first that writes at scale. T01 creates one profile after a read that refuses to overwrite. This changes what lands on real devices, in bulk, and the mistake it enables is not a duplicate policy but a policy reaching the wrong population โ which is invisible until somebody's laptop behaves differently. It gets T01's rules and more: ReadWrite asked on the click and never at sign-in, a dry run listing every operation with the group NAME and its member count before anything is sent, removals confirmed separately from additions, and the assignment state captured to a file first so there is always a way back.
Two of its features are deliberately not on this card. It can hard-delete policies and rename them; both are behind its own โAdvanced Actionsโ toggle and neither belongs in a browser tool whose whole argument is that it cannot do much harm. If TUNO ever deletes a policy it will be its own decision, not one inherited.
Shipped narrower than the card promised, on purpose. Four surfaces โ device configurations, settings catalog, compliance, administrative templates โ because they are the ones under the write permission the registration already holds. Scripts, applications, app configuration and endpoint security intents each need a write scope TUNO does not carry, and adding one is a decision to take in the open (the R18 rule), not a feature's side effect. The promised rules all arrived, plus two the card did not name: every write is preceded by a fresh read, so a policy edited by somebody else between plan and apply is skipped as drifted rather than overwritten; and every write is followed by a read-back, so โdoneโ is the tenant's word. Filters on untouched assignments survive the round trip โ the assign call replaces the whole list, and dropping one would silently widen an assignment nobody meant to touch.
R21 ๐งฉ Assignment filters live ยท build 8 writes to the tenant
Also after IntuneShade, and both halves shipped together. The read half: every filter with its platform and rule, and per-filter usage โ which assignments on which policies reference it โ read through R04's own source table, exactly as the card promised, so a surface added there is counted here. The usage scan is optional and the used-by column is absent, not zero, until it runs; a surface that could not be read makes every zero a floor, and the screen says so.
The writes carry R13's rules, sized for one object: the write scope at the click, an edit preceded by a fresh read and refused as drifted if the filter changed since it was loaded, every write verified by read-back, delete confirmed by typing the name. And the rule the card was written for: delete is refused while usage is non-zero โ checked against the tenant's own payload associations at the moment of the act, not against the session's cached scan, and โcould not checkโ refuses too, because a filter deleted while in use silently widens every assignment that carried it. This is the first PATCH and the first DELETE in the application; both arrived in the Graph layer with the same no-retry rule writes have always had.
R09 ๐ฅ Restore Intune configuration live ยท build 8 writes to the tenant
After Ugur Koc's Restore Intune Configuration, living inside the ๐ฆ backup tool โ the file you load is the file the other half wrote, and the original script's archives load too, because the folder layout is shared. Pick a single policy, a selection, or everything; dry-run; apply. The dry run lists every operation, including the ADMX definition-value child writes the original's -WhatIf never shows, and every create is verified by read-back: โcreatedโ is the tenant's word.
TenuVault's two rules shipped exactly (Ugur Koc, MIT): create only โ nothing of yours is patched or deleted, the single exception being an administrative template this restore half-created and failed to finish, which is rolled back as its own mess; and every object gets a name prefix, [Restored] by default, editable per row. The collision stop sits on top: a name that exists in the tenant skips that object, checked at dry run and re-checked fresh immediately before each create.
Two departures from this card's first draft, both deliberate. The card offered โoverwrite, skip or renameโ at a collision โ overwrite is not offered: it is a patch wearing a restore's clothes, and create-only is the stronger rule; rename is the editable name column, skip is the default. And assignments are not restored at all rather than off-by-default: a source-tenant group GUID either does not exist in the target or, worse, names a different group โ every object arrives unassigned and the result says so per row, which is also this card's promised TenuVault principle (nothing arrives already reaching people) applied the simplest way. Scripts saved without bodies cannot be selected and say why; secrets arrive as references to re-enter, as the backup's manifest always warned. Scopes at the apply click: the config write for four areas, the scripts write for platform scripts โ both already declared.
R28 ๐ Compliance coverage โ the platforms nothing evaluates live ยท build 9
After Ugur Koc's Get Compliance Policy Coverage (MIT). The gap the compliance report itself cannot show, because every number it has comes from policies that exist: a platform with enrolled devices and no assigned compliance policy. Those devices are not failing anything โ there is nothing to fail โ and depending on one tenant setting they report compliant by default and sail through every Conditional Access check that requires a compliant device. The device count per platform is the priority order, and unassigned compliance policies are listed beside the gaps they would close.
Not a new tile โ a section in the ๐ Compliance report, and that is the point. The script's two reads are exactly the two T13 already does: compliance policies with assignments, devices with their operating system. The R19 rule applies โ a second question over one read asks the tenant nothing new โ so this ships inside T13 with zero new Graph traffic and no new scope. Platform identity is the script's own mapping, kept: a compliance policy's OData type names its platform 1:1, and device operating systems normalise to T05's one vocabulary rather than three spellings of Windows. "Covered" is narrowed the R26 way: a policy whose only assignments are exclusions, or none, covers nothing by construction โ group scoping within a platform stays unevaluated, said on screen.
And the sentence the original leaves as a footnote becomes a read. Its notes say "check the tenant's Mark devices with no compliance policy assigned as setting" โ because that setting decides whether an uncovered platform is a nuisance or a hole: compliant-by-default means uncovered devices pass Conditional Access silently. TUNO reads the setting (deviceManagement/settings, on the config read it already holds) and states which way the tenant leans next to every gap; a setting that could not be read is said, with the portal path, rather than guessed.
Shipped as carded, one refinement found in the building: a platform is three answers, not two. Devices and no covering policy is the gap; devices and a covering policy is covered โ with a filter capping the claim at may, worn on the verdict; and a platform whose policies exist but whose devices do not is context, not a gap, listed so an unassigned macOS policy in a Windows-only tenant does not read as a hole. When either half of the read fails, coverage says unknown, not uncovered โ a gap table computed from half a read would be the confident overstatement the section exists to prevent.
R29 ๐ Windows LAPS audit live ยท build 9
After Ugur Koc's Get Windows LAPS Audit (MIT). Windows LAPS escrows each machine's local administrator password into Entra; this reads the escrow metadata โ which devices have a backed-up password and how old it is โ and cross-references every Intune Windows device: not escrowed and stale beyond the rotation threshold are the two shapes of the same finding, a LAPS policy that is not applying, found before the day somebody needs the password that is not there.
This is the first new permission since the Device analyzer, and it goes on in the open โ the R18 rule. DeviceLocalCredential.ReadBasic.All, and ReadBasic deliberately: Graph cannot return a password value through it, only device name and backup time. The full Read.All, which does return passwords, is what R10's helpdesk viewer would need and is deliberately not asked for here โ auditing that escrow works and reading a password are different acts, and the smaller one should not carry the larger one's scope. The registration script and SECURITY.md take the scope in the same build; every customer tenant pays one more admin-consent round trip, said here rather than discovered. And a second gate the consent cannot open: Graph answers this endpoint only for accounts holding specific directory roles โ Intune Administrator among them โ so a signed-in reader without one gets a refusal, and the screen says why before the run rather than printing a bare 403.
Two honesty rules past the original. A device whose enrolment record carries no Entra device id cannot be matched to the escrow store โ the original counts it not escrowed, which accuses a machine it never looked up; here it is unmatchable, unknown, its own bucket. And escrow records matching no enrolled Windows device โ retired machines whose passwords are still held โ are listed as their own answer rather than silently ignored, because credential metadata that outlives the machine is worth a look. Reads only; passwords are never retrieved, and there is no switch that would.
Shipped as carded, one addition found in the building: escrowed-with-no-timestamp is its own bucket. A record whose backup time cannot be parsed is neither healthy nor stale โ calling it either would be a guess, so it reads age unknown, counted and listed. The role-gate refusal is detected and named on screen โ "this is about who you are, not what TUNO may do" โ and the stale threshold is yours (default 60 days, the original's).
R15 ๐ฆ Backup, widened and checkable live ยท build 9
After Ugur Koc's TenuVault TUI (MIT), which backs up twenty-seven policy types where R08 covers five. The missing twenty-two are not obscure: security-baseline intents, Autopilot profiles, enrolment configurations, feature, quality and driver update profiles, macOS custom-attribute scripts, assignment filters, scope tags, device categories, terms and conditions, notification templates, app configuration for devices and for managed apps, app protection for iOS, Android and Windows, Windows Information Protection, and app categories. Most of them TUNO already reads somewhere โ R06 documents thirteen surfaces โ so the gap is the archive, not the plumbing.
And an archive you can check. TenuVault writes a SHA-256 per policy file and a verify that reports modified, missing and untracked files โ entirely offline, no tenant. An archive nobody can verify is a file you hope is a backup. Its atomicity trick is worth copying exactly: metadata.json is written LAST, so its presence is what marks a backup complete, and a folder without one is hidden rather than offered. TUNO builds its zip in memory and hands it to the browser in one act, so a half-written archive is less likely โ but "less likely" is not "cannot", and a manifest that only exists when the run finished is a better guarantee than a promise.
Assignments captured optionally with a groups.json beside them, read-only and for auditing rather than restore โ group ids are tenant-specific and copying them across tenants is meaningless, which TenuVault says plainly and R09 already agrees with.
Shipped inside ๐ฆ Backup configuration (R08's tool, T04, v0.3) โ one screen, not a second tool. Nineteen new export areas joined the interop five; the five keep the PowerShell original's folder names exactly, the new folders are TUNO's own, because TenuVault is a Go binary with its own layout and claiming byte-interop with it would be a claim nothing verifies โ what is TenuVault's here is the coverage, the checksum per file and the manifest-written-last rule, credited. Every file carries a SHA-256 in the manifest; verify runs offline in the tab โ modified, missing and untracked named, no manifest called what it is, an older archive called unverifiable rather than quietly passed.
And one departure from this card, decided by Mihai: assignments are exportable AND IMPORTABLE. The card said assignments.json would be read-only for auditing. It is now also a restore path โ same tenant only (the archive carries the tenant's id and a mismatch is refused outright, no override; cross-tenant is R17's problem, deliberately unbuilt), the four surfaces under the held write scope, targeting the same policy ids never a namesake, all-or-nothing per policy when a group in the archived list has since been deleted โ writing the list without it would change its meaning, and a dropped exclusion widens. The write runs through the assignment editor's own machinery: dry run, drift skip, read-back verify. groups.json stays what it was โ names resolved at backup time, for the audit question the directory can no longer answer.
R11 ๐ฎ Assignment what-if live ยท build 9
After Ugur Koc's Intune Assignment Checker (MIT). Before you add somebody to a group, what will they receive โ and if you take them out, what will they lose? Pick a user or a device, name a group, and get the delta against what they have today: policies gained, policies lost, applications that will install, applications that will be uninstalled. Then the comparison the portal cannot do at all: put two or more groups side by side and see what each receives that the other does not.
This is the one capability of his suite that TUNO has nothing like. The reading half is already here โ R04 answers โwhat does this group receiveโ, R03 answers โwhy did this device get thatโ, and both already show exclusions, inheritance and filters. What neither answers is what would happen if, and that is the question asked at the moment a change is still cheap to reverse. It also brings the third subject: TUNO can start from a group or a device, not yet from a person.
It reads only, and it is a simulation rather than a promise. Group membership rules, assignment filters and per-device applicability all sit between an assignment and a device, and a browser can evaluate none of them with certainty โ so the answer will say which parts are computed and which are inferred, the same way R03 already refuses to claim a filtered assignment applies.
Shipped as promised, with the mechanics stated rather than implied. Joins carry the group's own parents; leaves rebuild the closure from the remaining direct memberships, so a policy still reachable through a second group is not reported lost; a membership held only through nesting says so instead of simulating a removal the portal does not offer. The delta's third state is the reason to run it: joining a group can take policy away, and an uninstall intent that starts to apply reads "will be uninstalled" rather than "gained". Person-subject support arrived with it โ the third subject the card asked for.
R12 ๐ฉบ Assignment health live ยท build 9
Also after Intune Assignment Checker. The assignments that exist and reach nobody, in one place. Empty groups โ a policy assigned to a group with no members is configuration that has never applied and never will, and nothing in the portal surfaces it. Failed assignments โ deployments Graph reports as failed rather than pending. Unassigned policies, which R06 can already filter for but does not treat as a finding. Each is the same shape of problem: something that looks configured and is not.
Distinct from what R04's sweep already finds. That reports dangling references โ an assignment naming a group the directory no longer has. An empty group still exists; it simply has nobody in it, which is a different fault with the same symptom.
Shipped with three findings the card did not promise: excluded-only policies (every assignment an exclusion โ nothing to carve from), one group included and excluded on the same policy (the exclusion wins; the include reads as reach), and deleted-group references listed per assignment. Deployment failures are read where Graph keeps a cheap per-policy status, and the surfaces that keep theirs behind the reports API are named as unchecked rather than passed off as healthy. Enrolment defaults are exempt from the unassigned finding โ unassigned is their normal state.
R14 ๐ฆ Settings search live ยท build 9
The last piece of Intune Assignment Checker worth having: search across setting definitions rather than policy names. โWhich policies configure BitLocker, and to what value?โ โ answered against the settings-catalog definition catalog, roughly seventeen thousand definitions, with the abbreviations and near-misses an admin actually types. R06 searches the settings of the policies it has already read, which finds a setting only if you already know which policy holds it; this searches the other way round.
A separate card because it needs a separate thing: the definition catalog itself, which is large, changes as Microsoft ships settings, and has to be fetched and cached rather than derived from the tenant. That is a different problem from reading assignments and it should not be smuggled into a tool that does not have it.
Shipped, with one departure from this card's own caution. The card said the catalog "has to be fetched and cached rather than derived from the tenant" โ it is fetched per session and held in memory, not persisted: seventeen thousand definitions store fine in a tab and go stale on disk. Tenant usage is a second, separate read, and until it runs the "set by" column is absent, not empty. Values pass the documenter's redaction gate โ the same implementation, because a second copy would be a second place for a pre-shared key to escape.
R19 ๐งฎ Assignment matrix live ยท build 9
After IntuneShade by Alper Atar (MIT), whose single best screen this is: every group down the side, every policy surface across the top, one grid instead of one portal blade per policy. TUNO had already paid for the data โ R04's tenant sweep reads each surface once and matches every group against it โ so this shipped as a second view over the sweep's one read: a Table/Matrix switch that re-renders what was read and asks the tenant nothing, and a group click that lands in single-group mode through the tile's own pipeline.
A cell is a claim, and the grid does not overstate it. Includes are the count; exclusions are their own red โn, counted per surface and never folded in, because โthis policy does not reach youโ drawn as coverage is the exact overstatement a matrix invites. A dangling reference wears the sweep's own deleted flag instead of counting as coverage, and the sweep's scope caveat travels with the view.
The empty-group check is opt-in and absent-not-empty โ one $top=1 membership probe per group, batched twenty a trip (R12's technique), behind a button that says what it costs. Until it runs, the grid says plainly that empty and populated look the same; after it, a group nothing can reach says empty, and a probe that failed says reach? โ unknown, never passed off as either.
R20 โ๏ธ Setting conflict scan live ยท build 9
Also after IntuneShade: the same setting configured to different values in two policies. R12 finds assignment-shaped contradictions; this finds value-shaped ones, and the read is the ๐ documenter's own collect() โ same surfaces, same redaction, same failure honesty โ because a second copy of thirteen-surface reading is how two tools start disagreeing about one tenant.
The step past the original arrived as promised: a collision is only a conflict if the two policies can meet on a device. Every finding carries a verdict from the assignments โ can collide (a shared included group, or tenant-wide reach meeting anything), may collide, cannot collide. And โcannotโ is narrower than the card first said, on purpose: it is claimed only where one policy reaches nobody by construction โ no include, no tenant-wide target. โDisjoint populationsโ cannot be claimed from group ids, because two different groups can share members and a browser cannot see membership: different groups are may, an assignment filter caps any verdict at may (the filter id now rides along on the documenter's assignment rows for exactly this), and may means may โ the R03 rule.
Identity is exact or it is not claimed โ a departure from this card's own first draft. The card said R14's catalog would recognise a setting โacross settings catalog, device configuration and ADMXโ. It cannot: a legacy device configuration's typed property carries no definition id, and matching it to a catalog setting would be display-name matching wearing a canonical hat. Shipped instead: definition id within the settings catalog, definition-plus-category within ADMX, typed property within one policy type for device configurations โ and a cross-surface collision on the same CSP is stated as not detected rather than half-detected. Redacted values are never compared: two secrets are not known to be equal, and a conflict row printing them would be a disclosure. Findings, not a score. Reads only, no new scope.
R22 ๐ Compliance report live ยท build 9
Also after IntuneShade. The tenant's compliance story on one page: the estate rolled up โ compliant, non-compliant, in grace, unknown โ every policy with its verdicts, and which setting is failing where Graph keeps a per-setting summary, worst first. Stale is its own column, not a flavour of compliant: the threshold is on screen (default 30 days), and a compliant-but-stale device sits in both columns with the tension stated, because a verdict is as old as the check-in that produced it.
No new scope, as promised โ the estate rides R03's device read, the policies ride the config read. The R12 honesty rule arrived with it: the numbers are Graph's cheap per-policy rollup, refreshed on Intune's schedule and labelled so; a policy whose statuses could not be read is listed with the gap stated, never absent; and per-device drill-down for one machine is named as R03's job rather than half-done here. Exports Markdown, CSV, and a stale-devices CSV. HTML export next
R24 โ Self-host branding live ยท build 9
ENCA's mechanism, ported whole: the โ gear next to Sign out, on any non-production host โ product and organisation names, logos, login text and light/dark identity colours, through the same override mechanism as the hosted per-audience looks. Chrome only; exports keep the neutral product credit. Apply keeps the look in this browser; Download produces selfhost-branding.json, Import reads one back into the form for review โ and serving that file next to index.html gives every visitor the branding and softens the red BETA ribbon to a neutral SELF-HOSTED one, because a deliberately configured instance is not a test site. What the gear will never configure is the canonical host: that drives the production check and the export credit, and a settings dialog must not be able to make a copy claim to be production.
R25 ๐ฆ Defender status report live ยท build 9
After Ugur Koc's Get Defender Status Report (MIT), whose question is the one that becomes an incident ticket later: on which machines is Defender silently off or outdated? The tenant's own protection rollup (deviceProtectionOverview) for immediate context, then every Windows device's windowsProtectionState โ real-time protection, tamper protection, malware protection, signature currency, overdue quick and full scans, a pending reboot, a device state that is not clean โ with each device carrying its list of findings rather than one traffic light, because "tamper protection off" and "signatures three weeks old" are different conversations. Reads only, and no new scope: both endpoints sit under the device read T06 already brought in. Both are beta surfaces โ that is where Graph keeps protection state, and the card says so rather than leaving it to be found.
The per-device read is the whole cost, and the original pays it one device at a time โ protection state fetched in series with a sleep between requests, which on a large tenant is minutes of a terminal doing nothing. Folded into $batch, twenty a trip, with progress on screen โ the same technique R12 and R19 already use for exactly this shape of read.
A device that never reported protection state is its own bucket, never healthy by omission. The original lists these separately and that instinct is kept and sharpened: no state is a finding, not an absence โ a machine Defender has never reported on is exactly the machine this report exists to find. And the tenant rollup and the per-device sums can disagree, because Graph refreshes the overview on its own schedule; both are shown, labelled as what they are, and never quietly reconciled.
Shipped as carded, with one distinction the card only implied. The original counts a protection flag the device did not report the same as one that is off; here not reported is its own answer, per flag, on the row and in both exports โ accusing a machine of running without tamper protection when it simply did not say is the kind of overstatement audits repeat. A state that could not be read lands in the no-state bucket with its error stated, because unknown is not clean.
R26 ๐งฑ Firewall & ASR coverage live ยท build 9
After Ugur Koc's Get Firewall and ASR Status (MIT). Whether the Windows fleet actually has firewall and attack-surface-reduction enforcement, or just policy objects: every endpoint security policy โ settings catalog policies whose templateReference.templateFamily starts with endpointSecurity, plus the legacy security intents older tenants still carry โ grouped into the portal's own disciplines (firewall, attack surface reduction, antivirus, disk encryption, EDR, account protection), each with a three-way verdict: covered, policies exist but none is assigned, or no policy at all. The template-family filter runs client-side because the server-side filter is unreliable on this surface โ the script's own note, kept. The Windows device count is the denominator on purpose: a gap on firewall or ASR is not an empty table row, it is that many devices running on local defaults.
"Covered" is a claim, and this card narrows the original's. At least one assigned policy per discipline is what the script means by coverage, and per-device applicability is not evaluated โ its own note, which belongs on the screen rather than in a comment. One step past it, for free: assignments arrive $expand-ed, so "assigned" is checked by construction the R20 way โ a policy with no include and no tenant-wide target, or whose every assignment is an exclusion, reaches nobody and does not count as coverage. Whether an included group is empty is R12's finding, and the page points there rather than half-repeating it. Reads only, no new scope: the policy read rides the config scope, the device count rides T06's.
Shipped with one departure from the original that the card did not promise: legacy intents are classified, not dumped. The script lists deviceManagement/intents under a "Legacy Intent" pseudo-discipline, so a tenant enforcing firewall through an intent reads as a firewall gap โ an overstatement in the dangerous direction. Here the intent's template is resolved (one read of deviceManagement/templates) and the intent counts toward its discipline; one that cannot be classified counts toward nothing and says so. The legacy surface only answers assigned-or-not โ no assignment detail โ and the row carries that caveat rather than pretending the reach was checked.
R27 ๐ค Multi-admin approval live ยท build 9
After Ugur Koc's MAA Compliance Dashboard Report (MIT). Multi-admin approval is the Intune control where changing an app, a script, a settings catalog policy or a role โ or running a device action โ needs a second administrator to say yes, and nothing in the portal shows whether it is protecting anything. One page: every approval policy (operationApprovalPolicies) with what its type gates; the requests of a chosen window (operationApprovalRequests) โ pending, approved, rejected, cancelled, and how long approval actually takes; and coverage per resource category computed the way MAA actually works: an approval policy gates an operation type tenant-wide, so one policy of type app protects every app, and a category with no policy has no gate at all โ which is the finding.
The admins half carries R07's sentence, because the original needs it and does not say it. Its "admins without MAA approval rights" list is counted from deviceManagement/roleAssignments โ Intune RBAC only โ so Global Administrator and Intune Administrator, the accounts that can change the most, are not in it. Said on screen and in every export, verbatim from R07. Approvers are resolved from the approval policies' approver groups transitively, and names arrive through directoryObjects/getByIds โ R07's one-call technique, not the original's two probes per member.
Fewer scopes than the original asks for. The script connects with six, Directory.Read.All among them; everything here rides scopes the registration already holds โ the MAA surface and role assignments under the RBAC read, the app, script and configuration inventories under reads earlier tools brought in, group members under the group read. And "no MAA policies" is distinguished from "could not read": a tenant that has never configured multi-admin approval gets a page that says so plainly, with the uncovered categories reading as the finding they are rather than an error. Reads only.
Shipped with two findings the card did not promise. A policy whose approver groups hold no members is flagged as a gate nobody can open โ every operation it gates will sit pending until someone is added, and the emptiness is checked transitively, not read off the group list. And approved requests whose timestamps cannot be parsed are counted outside the approval-time numbers with their count stated, because an average quietly missing its slowest members reads better than the truth.
R30 ๐ Policy overview live ยท build 12
The sister tool ENCA's list-policies view, Intune-side-out: every configured object as clickable cards, the thirteen surfaces on top as stat cards that double as filters โ Option B of a two-option mockup round. The read is the ๐ documenter's own collect(), one implementation so two tools cannot disagree about one tenant, and a card click opens the documenter's own popout, extracted in the same build so the policy template exists once. Verdicts are the house claims: Assigned = reaching somebody by construction, excluded-only its own finding, a filter caps reach at may. A surface that could not be read is a named โ card and deliberately not a filter. Reads only, no new permission, no exports โ the document is the documenter's job, one click away.
R31 ๐งญ Endpoint security posture live ยท build 12
The portal's Endpoint security blade, mirrored โ Option B of a two-option mockup round: a rail of the portal's own nodes, plus two the portal does not have (settings-catalog policies configuring Defender or Edge, found by their setting definition ids), and two analyses in the same rail. ๐ฃ The impact brief is the sister tool ENCA's T32 translated from sign-ins to devices: what people will notice, in end-user language, exportable as Markdown or Word. ๐ Best practice wears ENCA's MSLearn check shape โ severity, requirement, remediation, the learn.microsoft.com page per check โ pointed at MDE and Edge, with not reaching as its own verdict when the right setting sits in a policy reaching nobody. The read is the ๐ documenter's collect() (which carries templateFamily since this build), disciplines split by ๐งฑ T16's own classifier, verdicts the house claims. Cross-checked against ShadowDeploy MDE's defId families โ BUSL-licensed, so checked against, not ported; every check stands on its Learn page.
A third analysis arrived with R02 (beta 10500): ๐ Secure Score gaps. These checks read policy โ what is configured and whether it reaches anybody. Microsoft Secure Score reads the estate โ what devices actually report. They disagree constantly and the disagreement is the finding, which neither reading produces alone: a check that passes while Microsoft still withholds the points is almost never the policy, it is machines that never onboarded, a licence the control needs, or devices that have not reported since it was written. Four buckets โ both agree, configured-but-unscored, Microsoft-only, this-tool-only โ and every pair prints both names, so a wrong match is visible rather than load-bearing; a control that matches no check is listed under Microsoft's own title, so a miss can only under-correlate. It is a separate button because it costs SecurityEvents.Read.All, and the posture read itself still costs no new permission.
R32 ๐ Filter rules, counted live ยท build 12
Every tool here could say a filter narrows an assignment and none could say by how much โ at most, may reach it, โ filter โ may. js/filterrules.js parses the documented rule grammar and evaluates it against the enrolled inventory, so ๐งฉ Assignment filters can say 312 of 9969. A count is offered only where the whole rule is understood โ not best-effort with a confidence marker, because a wrong count renders exactly as confidently as a right one. A rule outside the grammar says not evaluated and names what stopped it: deviceOwnership because Personal/Corporate against personal/company would be a guessed translation, operatingSystemSKU because Graph does not return it, app.* because it is not about devices. The number is a reading of today; the service evaluates the rule at assignment time, against inventory that moves.
R02 ๐ Secure Score visualizer live ยท build 12
The tenant's Microsoft Secure Score over Graph โ security/secureScores and the control profiles โ as the card promised: score over time, per-category breakdown with Microsoft's own comparison figures as ticks on each bar, what changed across the window, and the improvement actions that buy the most points for the least user pain. That last ordering is TUNO's, not Microsoft's, and says so wherever it renders: points still available weighted down by the userImpact and implementationCost Microsoft publishes, with a control declaring neither treated as moderate โ calling an unstated impact low is how a quick win becomes Monday's incident. Markdown for the monthly report, CSV for the controls and the history. SecurityEvents.Read.All on the click, reads only.
Two things the card did not promise. Graph keeps about ninety days, so "what changed since last month" runs out at a quarter โ the tool exports a versioned snapshot carrying the readings and the catalogue they were read under, and uploads them back, so the timeline reaches as far back as somebody kept files. Uploaded points are drawn as their own marks, a same-day clash resolves to the live reading and says how many it dropped, and a snapshot from a different tenant is refused by tenant id rather than merged with a caveat. And ๐งญ T20 correlates against it: Secure Score reads the estate, the posture checks read policy, and a check that passes while Microsoft still holds the points is the finding neither tool could produce alone.
R33 ๐ Group migration live ยท build 12
The sister tool ENCA's โฆ Migrate, Intune-side-out. A group is made role-assignable for one side effect: only Global Administrator or Privileged Role Administrator may change its members. A restricted management administrative unit does that job better โ it lets you name who may manage the group โ and drops the costs role-assignable carries: the 500-per-tenant cap, no dynamic membership, no nesting control. The two can never be combined, because a restricted unit blocks exactly the two roles a role-assignable group admits, so a group that is both is a group whose members nobody can edit.
The new group has a new object id, and the tool can only move half the references. isAssignableToRole is immutable, so this is a recreate rather than a patch. The four surfaces R13's assignment editor already writes are repointed with that tool's own engine โ the fresh-read drift check and the verify read-back come along rather than being written a second time. Applications, scripts, app protection and configuration, enrolment restrictions, Autopilot and update rings are read and named, never moved: each would need a write scope this registration does not declare, and adding one is a decision taken in the open rather than a side effect of a feature.
And the sentence the tool says out loud rather than leaving to be discovered: everything outside Intune is invisible to it. Conditional Access, group-based licensing, Azure RBAC and app role assignments all address a group by object id. The original is renamed aside and never deleted โ it keeps its members, stays role-assignable, and is the rollback until those have been checked.
R34 ๐ก Restricted AUs live ยท build 12
The other half of R33. A restricted management administrative unit is the only place in Entra where membership can be put out of reach of every tenant-wide role โ inside one, only a principal holding a role scoped to that unit may change the members, and Global Administrator and Privileged Role Administrator can manage the unit but not what is in it. R33 files migrated groups into these; this creates and manages them. List, create, rename, delete, members, scoped administrators.
Three of Entra's rules, not ours, shape the screen. The restricted flag is immutable, so there is no convert and the editor says so. A unit with no scoped administrator is a vault nobody can open โ creating one without naming a keyholder is refused, and the field is prefilled with you, because whoever creates the unit is its administrator by default. And a role-assignable group inside a restricted unit is ๐ง frozen: it admits only GA/PRA, the unit blocks exactly those two, and nobody at all can change its members โ R33 is the way out.
Ported from ENCA's T27 and deliberately narrower. ENCA's version is wound through its Conditional Access baseline โ persona vaults named from CA numbers, a baseline checklist, a group-to-persona map, prefix scans over its own naming. None of that came across: it answers a question TUNO does not ask, and importing it would have meant a vocabulary this tool cannot honour.
R35 ๐ macOS baseline live ยท build 13 writes to the tenant
The sister tool ENCA's Baseline Policies machinery, Intune-side-out and pointed at macOS. The name is the identity: baseline policies start with MACOS, carry a permanent R26.xx release number and end with a version โ matched by number, compared by version, corroborated by the rest of the name so a number clash is a finding, not a silent match. The catalog is the cloudfellows.dev reference export, authored there and only there (the cfdev convention): the baseline tenant exports the file โ names, numbers, versions and raw policy bodies โ and every other tenant identifies against it and can import what is missing, create-only through the Backup tool's restore pipeline, canonical names kept, everything arriving unassigned.
R36 ๐งน Entra device cleanup live ยท build 13 writes to the tenant
Stale directory devices staged out in two deliberate steps โ disable at 30 days of silence, delete at 90, and only what is already disabled. A device with no recorded sign-in is unknown, not stale, and gets no action offered. Every write is preceded by a fresh per-device read (a device that woke up or was re-enabled is refused, not overruled) and verified by read-back; deletes arm only after typing the word, because the BitLocker recovery keys go with the object. Carries the registration's first directory-device write scope, Device.ReadWrite.All, taken in the open โ and Graph's own directory-role gate on device writes is named before the run. One Markdown report: the estate, the actions, and everything deliberately not done.
Later
R17 ๐ Tenant sync โ copy configuration between tenants would write to the tenant
After TenuVault's sync (Ugur Koc, MIT). Take configuration from one tenant and create it in another โ whole types or named policies โ for the jobs nobody has a good answer to today: standing up a new customer from a known-good baseline, keeping a pilot tenant and production in step, and lifting a policy set out of a tenant that is being decommissioned. A managed-service provider does this by hand, in the portal, once per tenant, and it is the single most repetitive thing in the job.
Two routes, and the difference is not a detail. Backup-mediated: export tenant A with R08, sign into tenant B, restore the archive โ which is really R09 with a file that came from somewhere else, needs one sign-in at a time, and leaves an artefact on disk that says exactly what was copied. Live: both tenants signed in at once, read from A and write to B in one act. TenuVault supports both and so should this โ but the backup-mediated route is the one that should exist first, because it is the one that cannot surprise you.
THE LIVE ROUTE BREAKS AN ASSUMPTION THE WHOLE APP RESTS ON. TUNO holds one signed-in account. Every safety rule it has โ the collision stop, the member count before an assignment, the tenant named in a backup manifest โ assumes you are looking at the tenant you are changing. Live sync means two accounts in two tenants held at the same time, and a mistake is no longer a duplicate policy in the tenant in front of you; it is configuration created in the wrong tenant, quite possibly a customer's. MSAL can hold two accounts and the browser can carry both tokens, so this is buildable โ but it needs the source and the target named, in words, on screen, at every step, and a confirmation that types the target tenant's domain rather than clicking a button. It is the sharpest edge on this roadmap and it should be built last.
What cannot travel, said here rather than found at the far end. Assignments do not copy โ a group id means nothing in another tenant, and one that happens to resolve there is worse than one that fails, so they are dropped and the report says which policies arrived unassigned. Secrets do not copy, for the same reason they are absent from a backup: Graph never returned them. Anything referencing a certificate, a Wi-Fi key or an encrypted setting arrives configured-but-incomplete and must be finished by hand, and the report will name every one. Objects that cannot be recreated at all โ default and singleton enrolment configurations โ are reported as skipped rather than attempted, which TenuVault learned the same way.
And the shortcut that will be tempting here is not available. TenuVault signs in with no app registration at all by borrowing Microsoft's own Graph PowerShell client id โ sound for a locally installed binary, and impossible for a web page: that application is registered as a public client with a localhost redirect, a browser needs a redirect URI of type single-page application, and Entra refuses the cross-origin token redemption outright. It could not be added either, since the application is Microsoft's. It would also be wrong if it worked โ the consent record in a customer's tenant would name Graph PowerShell rather than TUNO, and every read would appear in the sign-in log as Microsoft's tool rather than this one. SECURITY.md sets out the reasoning; the short version is that syncing between tenants means two consent records, both of which have to be real.
The rules from R09 apply unchanged, plus one of TenuVault's own: create only, never patch or delete; a name prefix on everything created; a dry run listing every operation before anything is sent. And a prefix-free sync is refused when source and target are the same tenant โ because at that point it is not a sync, it is a silent duplication of your own configuration, and TenuVault refuses it for exactly that reason.
R16 ๐ฌ Backup drift โ compare two archives, offline
Also after TenuVault, whose compare takes two backups and produces a stable, severity-ranked list of what moved between them. The interesting part is that it needs no tenant at all โ it is two folders and a diff. In TUNO that means dropping two R08 archives onto the page and reading the answer without signing in, which almost nothing here can do; only the AppLocker analysis works that way today.
Which makes it the right shape for the questions a backup is actually kept for. What changed between Friday and Monday? What is different between the pilot tenant and production? Is this month's archive meaningfully different from last month's, or just re-serialised? R05 answers the first from the audit log, but only for thirty days and only if the change was made through Intune; two archives answer it for as long as you have kept them. The field-level diff R05 already carries would do the comparing.
R18 ๐ฑ Minimum OS version maintainer would write to the tenant
After James Robinson's IntuneComplianceMaintainer (MIT). Every compliance and app-protection policy carries a minimum OS version, and that number is correct on the day it is typed and quietly wrong for the rest of its life โ which is how a tenant ends up admitting devices three releases behind on a policy nobody has opened since it was written. This reads what is currently supported โ endoflife.date for iOS, iPadOS, macOS and Android, the Graph Windows Update catalog for Windows builds โ works out what each selected policy should say, and updates the ones that are behind. Android keeps the original's two oddities because both are right: osMinimumVersion targets the oldest still-maintained release rather than the newest, so any supported device passes, and the security patch level is enforced alongside it as a separate floor.
ON DEMAND, and that is the honest difference rather than a limitation glossed over. The original is a runbook โ managed identity, Azure Automation, a schedule, application permissions โ and its whole value is that it runs when nobody is watching. TUNO has no server and nothing to schedule with, so this can only ever be the other half of the job: press it, read what it would change, decide, apply. Anyone who wants monthly enforcement unattended should run his script, and this card says so rather than implying a static page can replace it. What it can be is the thing you reach for after a Patch Tuesday, or when somebody asks whether the compliance floor is still current โ questions that today mean opening every policy in the portal one at a time.
What a browser is better at is choosing which policies. His script takes policy GUIDs pasted into a per-platform hashtable, which is what makes unattended running possible โ and also how a policy created last quarter quietly never joins the list. TUNO already reads every compliance policy by name (R06 covers thirteen surfaces), so the selection is a list you tick, and every policy in the tenant stays visible whether or not it is selected, with its current floor beside it. A maintenance tool that only shows you what it was told about cannot tell you what it was not told about.
RAISING A MINIMUM OS VERSION IS AN ACCESS CHANGE, NOT A CONFIGURATION CHANGE. This is the sharpest thing on the card and the reason it is not a small tool. Where Conditional Access grants on require device to be marked compliant โ which is most tenants that bother with compliance policies at all โ every device below the new floor stops being compliant and then stops getting in. The devices that cannot reach the new version are exactly the ones that will never come back without new hardware. So the dry run does not just list old and new: it says, per policy, how many devices currently in scope sit below the proposed floor, which is a read TUNO can actually do โ managedDevices carries osVersion, and R04's machinery already works out who a policy reaches. And it shows the grace period from the policy's own scheduled actions next to every change, because the difference between a lockout this afternoon and a warning with a week to act is written there and nowhere on the screen you are pressing the button on.
Two permission facts, both of which fail at the click rather than at sign-in. Writing needs DeviceManagementConfiguration.ReadWrite.All, which TUNO's registration already declares, and โ for app-protection policies โ DeviceManagementApps.ReadWrite.All, which it does not. That would be the second write scope in the whole application, and adding one is a decision to take deliberately rather than a line in a script. Reading the Windows catalog needs WindowsUpdates.Read.All: the original asks for ReadWrite, and read is enough, so this asks for less. But the same endpoint also requires the signed-in person to hold Intune Administrator or Windows Update Deployment Administrator as an Entra directory role โ an Intune RBAC role will not do it, consent will not fix it, and it surfaces as a 403 on the Windows half only. Better said on the screen before the run than discovered inside it.
And one thing that cannot be slipped in quietly: the page would have to talk to a host that is not Microsoft's. TUNO's content-security-policy allows connect-src to graph.microsoft.com and login.microsoftonline.com and nothing else, which is a large part of why the security documentation can say what it says. endoflife.date would be the first third-party origin this application has ever contacted, and what comes back from it decides what gets written into a customer's tenant. Two ways out, and the choice belongs on the table rather than in a commit: widen the policy by exactly one host and say so in SECURITY.md, or take the target version as something you enter, which keeps the origin list intact and moves the trust to the person pressing the button. The Windows half needs no new origin at all โ that catalog is Graph.
The rest of the original's safety rules carry over unchanged, because they are the right ones: dry run first and by default, downgrade protection on so a policy is never quietly loosened, and a cadence โ a release is not enforced until it has been out long enough for devices to have actually got it, which is the difference between a compliance policy and an outage. TUNO adds the one its own rules require: ReadWrite asked on the click, never at sign-in.
R23 ๐ค AI policy analysis bring your own key
After IntuneShade, which sends a policy to Claude and gets back what it does, what is risky about it and what to reconsider โ and, on a conflict, a suggested resolution with the reasoning. Paired with R20 that is genuinely useful: the scan finds the collision, the model argues about which value should win, the admin decides. Bring your own key, and the feature does not exist until one is entered โ no key, no button, nothing sent anywhere.
Without the server IntuneShade needed. Its Azure Function exists only to forward the request; the Anthropic API accepts direct browser calls (a request header exists precisely to declare that choice), so TUNO can do this and remain static files. The key lives in memory for the session โ not localStorage, where the original keeps it and where it survives the tab. And the payload passes the documenter's redaction gate before it leaves the browser: a policy sent for analysis is exactly as likely to carry a pre-shared key as one sent to a wiki, the original sends it raw, and this will not.
The sharp edge is the same one R18 already named: a new origin. The content-security policy allows Microsoft's two hosts and nothing else, and api.anthropic.com would be the second third-party origin ever proposed for this application โ a decision to take in the open in SECURITY.md, not a line in a commit. It sits in Later on purpose: R20 must exist first, and the origin question decided first. One of the original's AI features is deliberately not coming: the script generator. TUNO ships curated, reviewed, versioned PowerShell โ generated scripts with a tenant's write scopes at hand is the opposite of the argument this application makes.
R10 ๐ LAPS viewer admin-side โ not the self-service portal
Inspired by Daniel Fraubaum's LAPS Self-Service Portal, and deliberately not a port of it. His design cannot be built as a browser-only tool, and the reason is worth stating rather than discovering. Reading a Windows LAPS password with delegated permission requires the signed-in user to hold Cloud Device Administrator or Intune Service Administrator โ precisely the roles an ordinary employee retrieving their own laptop's password does not have. And DeviceLocalCredential.Read.All is tenant-wide with no per-device scoping, so โonly your own deviceโ is only true if something the user cannot reach enforces it. His portal puts that somewhere a browser cannot: an Azure Function holding an app-only token behind its own Managed Identity. That is the correct architecture for self-service, and TUNO has no server to put it in.
What TUNO can honestly be is the helpdesk-side tool: for staff who already hold the role, find a device and read its password without three portal blades, with the retrieval landing in the tenant's own audit log. Same problem, the half of it that fits a static site.
๐ฆ Defender status
The machines where Defender is silently off or outdated โ real-time protection, tamper protection, malware protection, signature currency, overdue scans, pending reboots, a device state that is not clean โ read per Windows device and shown worst first. After Ugur Koc's Get Defender Status Report (MIT), whose per-device read the original pays one device at a time with a sleep between requests; here it folds into $batch, twenty a trip. Reads only, and no new permission โ both endpoints sit under the device read earlier tools brought in. Both are beta Graph surfaces: that is where protection state lives.
Unknown is not healthy. A device that never reported protection state โ or whose state could not be read โ is its own bucket, because a machine Defender has never reported on is exactly the machine this report exists to find. A protection flag the device did not report reads not reported, never off: they are different answers, and counting one as the other is how audits overstate. And the tenant rollup shown beside the per-device counts is Graph's own, refreshed on its own schedule โ the two can disagree, and neither is quietly reconciled to the other.
๐งฑ Firewall & ASR coverage
Whether the tenant's Windows fleet actually has firewall, attack-surface-reduction, antivirus, disk-encryption, EDR and account-protection enforcement โ or just policy objects. After Ugur Koc's Get Firewall and ASR Status (MIT). Every endpoint security policy โ settings catalog policies with an endpointSecurity template family (filtered client-side, because the server-side filter is unreliable on this surface โ his note, kept), plus the legacy security intents โ with a verdict per discipline. Reads only, no new permission.
"Covered" is a claim, narrowed here. Coverage means at least one policy that is assigned and reaches somebody by construction: no include and no tenant-wide target is nobody, exclusions only is nobody, and an assignment filter caps reach at may. Per-device applicability is not evaluated, and whether an included group is empty is the ๐ฉบ Assignment health tool's finding โ pointed at, not half-repeated. Legacy intents are classified through their template so a tenant enforcing firewall the old way does not read as a firewall gap; one that cannot be classified counts toward nothing, said plainly.
๐งญ Endpoint security posture
The portal's Endpoint security blade, mirrored โ one read, three answers behind one rail: the disciplines with their policies as clickable cards (plus settings-catalog policies that configure Defender or Edge without being endpoint security templates, found by their setting definition ids), the ๐ฃ impact brief โ what a person will notice on their device, in end-user language, exportable as Markdown or Word โ and ๐ best practice: the tenant's actual setting values measured against learn.microsoft.com, each check carrying its severity, remediation and the Learn page it stands on. Reads only, no new permission โ the policy read is the ๐ documenter's own, so values have passed its redaction gate.
The claims are the house claims. Assigned means reaching somebody by construction; excluded-only is its own finding; an assignment filter caps reach at may. A best-practice check whose only correct configuration sits in a policy reaching nobody says not reaching โ configured is not enforced. A setting value the check set does not recognise is said to be unrecognised, never guessed. Legacy intents are classified through their template and say only assigned-or-not, because that is all their surface says.
๐ Secure Score visualizer
Microsoft Secure Score for this tenant, read over Graph and made explorable: the score with its gauge, the comparison against tenants of a similar size and against all tenants, the per-category breakdown with Microsoft's two comparison ticks on each bar, the timeline of every reading Graph still holds with what improved and what regressed across it, and the improvement actions ranked cheapest points first โ points still available, weighted down by the user impact and implementation cost Microsoft publishes on each control. Export as Markdown for the monthly report, or CSV for the controls and the history. Asks for SecurityEvents.Read.All on the click, ENCA-style incremental consent. Reads only.
These are Microsoft's numbers, not TUNO's โ Secure Score measures the estate as Microsoft observes it, so a control can be configured in a policy and reaching every device and still score zero. That difference is what the ๐งญ Endpoint security posture tool's Secure Score node exists to name. The cheapest-points ordering IS ours and says so wherever it renders; a control that declares neither impact nor cost is treated as moderate, never as low. Graph keeps about ninety days, so the timeline is capped there unless you feed it snapshots: โญณ Snapshot JSON exports the readings with the catalogue they were read under, โญฑ Upload puts them back, uploaded points are drawn as their own marks, a same-day clash resolves to the live reading, and a snapshot from a different tenant is refused โ two tenants in one timeline is not a comparison, it is a wrong graph.
๐ค Multi-admin approval
Multi-admin approval is the Intune control where changing an app, a script, a settings catalog policy or a role โ or running a device action โ needs a second administrator to say yes, and nothing in the portal shows whether it is protecting anything. After Ugur Koc's MAA Compliance Dashboard Report (MIT). Coverage is computed the way MAA actually works: a gate applies to its operation type tenant-wide, so one approval policy of type app protects every app โ and a category with no policy has no gate at all, which is the finding. Reads only, no new permission โ and fewer scopes than the original asks for.
Two sentences the numbers need. The admins list is Intune RBAC only โ Global Administrator and Intune Administrator are Entra directory roles and do not appear in it, so the accounts with the most access are not in the admins-without-MAA count; the warning is on the table and in every export, verbatim from the ๐ก Intune RBAC tool. And "no MAA policies" is an answer, not an error โ a tenant that has never configured multi-admin approval reads as exactly that, with the uncovered categories as the finding. A policy whose approver groups hold nobody is flagged as a gate nobody can open: every operation it gates will sit pending until someone is added.
๐ Windows LAPS audit
Windows LAPS escrows each machine's local administrator password into Entra; this reads the escrow metadata โ which devices have a backed-up password and how old it is โ and cross-references every Intune Windows device. After Ugur Koc's Get Windows LAPS Audit (MIT). Passwords are never retrieved, and there is no switch that would: the permission is DeviceLocalCredential.ReadBasic.All, through which Graph cannot return a password value โ reading one is a different act with a different permission, and it stays with the roadmap's helpdesk viewer (R10), not here.
Two gates, named before the run. The permission is asked on the click โ the first new one since the Device analyzer, taken in the open. And Graph answers the escrow endpoint only for accounts holding a supported directory role โ Intune Administrator among them โ so a consented tenant can still refuse a reader; that refusal is explained as the role problem it is, not printed as a bare 403. A device whose enrolment record has no Entra device id is unmatchable โ unknown, never counted as not escrowed, and escrow records no enrolled device claims are their own list.
โ Help
What TUNO is
TUNO โ Tenant Utilities for iNtune Operations is ENCA's sister tool (enca.limon-it.nl): the same idea โ static files running entirely in your browser, minimal delegated Graph permissions asked per tool, nothing stored server-side because there is no server โ applied to Intune and endpoint security instead of Conditional Access.
๐ AppLocker builder & validator
Reads NOTHING from your tenant: what you upload is parsed in this tab, audited with the AppLockerInspector check set, evaluated against a catalog of Microsoft apps (per-user OneDrive is the one everybody breaks), and exported as policy XML, an Intune custom profile, or a Markdown report. Rule evaluation here is a faithful model โ deny beats allow, exceptions carve back out, macros expand, publisher fields match โ not the AppLocker engine itself. Test in AuditOnly before enforcing, always.
The five steps. โ Download Invoke-TunoAppLockerScan.ps1 and run it elevated on a representative device. โก Upload the .json bundle it writes. โข Work through the findings and the coverage table, fixing what needs fixing. โฃ Export the policy XML for a GPO, or the Intune custom profile. โค Assign the AuditOnly profile to a pilot group, wait, re-scan, and only then enforce.
Why there is a PowerShell script at all. A browser cannot read a directory ACL, verify an Authenticode signature or open an event log โ and those three facts are most of what decides whether an AppLocker policy is sound. A rule allowing %PROGRAMFILES%\* is only as strong as the permissions underneath it, and the XML does not say what those are. The scan does, and the tool marks every verdict that came from it with ๐ฐ so you can see which half of the analysis proved what. Skip the scan and the tool still works on a plain policy XML; it just cannot tell you about the holes it cannot see.
The scripts are served from this site (/scripts/), so the copy you download always matches the build you are looking at. They are read-only on the device: neither one applies a policy, touches the local GPO, or starts the Application Identity service. Source and the full switch reference are in scripts/README.md.
๐ Group Analyzer
Reads nine Intune assignment surfaces and reports every one that names your group โ including the ones that exclude it. Each surface asks for its own scope when it runs, so a run limited to configuration profiles never prompts for the apps permission. Reads only; nothing is written, nothing is stored, and the exports are produced in your browser.
Three things the report says that a portal blade will not. โ Inherited assignments. If your group is a member of another group, anything assigned to the parent reaches your members too โ those rows are included and name the parent. If membership cannot be read, the report says the answer is direct-assignments-only rather than quietly narrowing. โก Tenant-wide reach. All Users and All Devices assignments are off by default and one toggle away; they are not about your group, but they land on it. โข Unknown is not empty. A surface that returned 403 or 404 is listed as unreadable with the scope and the Intune RBAC role it would need โ reporting it as โno assignmentsโ is the most dangerous thing this tool could do.
Why it stops at Intune. โWhere is this group used?โ has an Entra half โ Conditional Access, group-based licensing, directory roles, access packages โ and answering it needs permissions TUNO holds none of. That is ENCA's Group Analyzer, which is signed in for it. Two tools, one question, split along the line where the permissions actually divide.
๐ท AppLocker groupings โ what they are, and why yours must be unique
What a grouping is. When Intune delivers AppLocker, each rule collection is written to a CSP node whose address includes a name you choose: ./Vendor/MSFT/AppLocker/ApplicationLaunchRestrictions/{Grouping}/EXE/Policy. That name is the policy's identity on the device โ not a label, an address. Everything else about groupings follows from that one fact.
The why, in three consequences. โ Different groupings merge. A device holding groupings A and B enforces both โ deny beats allow across all of them, and a collection missing from B does not switch off its counterpart in A. Deploying a second grouping therefore never replaces the first; it stacks on it. โก Same grouping means same address, so two Intune profiles sharing a grouping write to identical nodes โ and Microsoft's own warning is that removal then breaks: โDelete/unenrollment is not properly supported unless Grouping values are uniqueโฆ the best practice is to use a randomly generated GUID.โ Unassign one profile and the CSP can delete the nodes the other still depends on, leaving orphaned policy nothing in the portal points at. โข Apply and delete both reboot the device โ the CSP's Policy nodes carry automatic reboot behaviour, so neither rollout nor rollback is quiet.
How to use it, then. One profile, one grouping, a GUID โ and you move from audit to enforce by editing that profile in place, never by assigning a second profile beside it. When migrating a device that already carries policy: unassign the old profile first (Intune sends the CSP delete), run Clear-TunoAppLockerPolicy.ps1 to sweep what unassignment leaves behind, then deploy under a new grouping. The cleanup names every MDM grouping it finds on the device โ the supported removal for a live grouping is unassigning its profile, and -RemoveMdmGroupings exists for the orphans the shared-grouping bug leaves. T01 prefills the house format โ AppLocker-<guid>, unique like the GUID Microsoft asks for, recognisable in logs unlike a bare one โ with a โป button to mint a fresh identity for a genuinely new deployment; the converter generates the same when -Grouping is omitted. Resist naming groupings pilot or production: that distinction lives in the assignment and the mode, and a hand-reusable word is exactly what produces two profiles sharing a grouping. The Intune tab warns when it sees one, and the carry-over findings show what other groupings already put on the device.
๐ฎ Assignment what-if
What would change if this user or device joined, or left, that group โ asked while the change is still cheap to reverse. Memberships today are read transitively, the hypothetical set is built (joining a group adds everything it is nested under; leaving severs one edge and rebuilds what remains), and every assignment surface is read once with each policy's effect computed under both sets. The difference is the answer. Reads only.
Four states, not two โ gained, lost, pre-excluded, unchanged โ because joining a group can take policy away: an exclusion met by joining is a loss, and that is the most surprising row this tool produces. A filtered assignment stays may in both directions; a dynamic group cannot be joined by hand, so that answer is labelled conditional on the rule; an app with intent uninstall that starts to apply says will be uninstalled, not gained.
๐ฉบ Assignment health
The assignments that exist and reach nobody, in one place: assignments into empty groups, dangling references to groups the directory no longer has, unassigned policies, excluded-only policies, one group both included and excluded on the same policy (the exclusion wins), and optionally failed deployments where Graph keeps cheap status. Every finding is the same shape of problem โ something that looks configured and is not.
Findings, not a score โ whether an empty group is a mistake or a landing zone prepared for next quarter is not something a tool can know. And unknown is never clean: a group that could not be peeked is unknown rather than empty, a surface whose status Graph keeps out of reach is named as unchecked rather than passed off as healthy.
โ๏ธ Assignment editor writes to tenant
Bulk assignment changes โ add an include, add an exclusion, or remove a group across many policies at once, the thing the portal makes you do one blade at a time. This is the tool in TUNO that writes at scale, and the pipeline is the point: read โ plan โ backup โ confirm โ apply โ verify, enforced by the screen. The dry run names every group with its member count, the backup is automatic and applying stays locked until it exists, removals are confirmed by typing the group's name, and the write scope is asked for at the apply click โ never at sign-in.
What it refuses and what it will not do. An include onto a policy that excludes the group, or an exclusion onto one that includes it, is refused as a contradiction rather than applied. A policy whose assignments changed since the plan was made is skipped as drifted rather than overwritten. Every write is verified by reading the tenant back, writes never retry, and there is no delete and no rename โ neither belongs in a browser tool whose whole argument is that it cannot do much harm.
๐ฆ Settings search
โWhich policies configure BitLocker, and to what value?โ โ answered from the setting definitions rather than the policy names. The settings-catalog definition catalog (roughly seventeen thousand entries, Microsoft's rather than the tenant's) is read once and searched as you type; a second, optional read of the tenant's own policies lets each result say who sets it and to what.
Until that second read runs, the usage column is absent โ not empty. โNobody sets thisโ and โnobody lookedโ are different answers, and the screen and the export both say which one you have. Values pass the documenter's redaction gate, because a settings search is exactly the tool somebody uses to hunt for โpasswordโ, and a result table printing secrets would be a disclosure engine with a search box.
๐ฅ Device analyzer
The Group Analyzer asks what a group receives. This asks what one device receives, and why โ walking the same nine assignment surfaces backwards through the groups the machine is in, the groups its primary user is in, and the tenant-wide targets that name no group. Every row names the relationship that put it there. The device is found by name, serial, either of its two GUIDs โ or by its primary user: a UPN, the exact display name, or the user's object id resolves to their machines straight off the enrolment record, no extra permission, and a user with more than one device gets a pick list of clickable cards. Reads only.
Read the check-in first. Every assignment here is what Intune intends; what the device has is whatever it collected the last time it talked to the service. A policy assigned ten minutes ago has not reached a machine that last synced yesterday, and no amount of correct assignment data changes that โ so the check-in time is the first thing on the page.
Three answers this tool refuses to guess at. โ A filtered assignment may or may not reach this device: the rule is evaluated by the service against inventory a browser cannot see, and Graph offers no call that answers it. Those rows say may reach it. โก A policy the device has not reported on has state unknown, not compliant โ and where a reported state cannot be tied to a policy with certainty, because two policies share a name, that is unknown too. โข Where a policy is included through one group and excluded through another, an exclusion wins in Intune and the row says excluded โ except when the two arrive through different kinds of group, device against user, where whether the exclusion applies depends on how the policy is targeted and the assignment does not say. That one is called a conflict and left to the portal.
Tenant-wide assignments are shown by default here, unlike in the Group Analyzer. All Devices reaches this machine whatever else is true, so hiding those rows would hide policy it is definitely getting. All Users lands on the person, so a device with no primary user does not receive them โ and the row says so rather than being dropped.
๐ก Intune RBAC
Every Intune role definition with its assignments, members, scope and scope tags, on one page. After Ugur Koc's PowerShell script (MIT). Every role carries a โ permissions button โ the actions it allows, grouped the way the portal groups them, read on the click from the role definition; Intune RBAC is an allow list, so anything not named is not granted. A member that is a group carries a ๐ฅ members button โ who effectively holds the role through it, transitive so nesting is flattened, users only since devices and service principals do not hold Intune RBAC, capped at 500 with the true total shown. Read on the click, never during the run, and the answer is live rather than from the report's moment. Reads only: DeviceManagementRBAC.Read.All, plus User.Read.All and Group.Read.All to turn member GUIDs into names and expand a group.
Read the first line on the screen before you rely on this. It is Intune RBAC only. Global Administrator and Intune Administrator are Entra directory roles, they grant full access to Intune, and Graph does not return them from deviceManagement/roleAssignments. Nothing this tool can ask for would show them, so it says so rather than letting the report pass for a complete answer.
Empty roles are a toggle. A role with no assignments is one membership change from being a live grant, so it is a fact worth seeing โ off by default because most tenants use a handful of the built-in roles, and switching it on re-renders what was already read rather than asking the tenant again.
The flags are observations and there is no score. An assignment scoped to all devices; a broad built-in role with a lot of members, at a threshold the screen states because it is arbitrary; a role whose members are all one group, where whoever can change that group can grant the role without holding it. Whether any of those is wrong depends on things the tool cannot see.
๐ Change audit
Reads the tenant's own audit log and says who changed what, when, from where, and which fields moved. Two views over one read: policy changes with a severity on each, and all events with actor / activity / category / result filters. Filters apply to what has already been read, so changing one costs nothing. Reads only.
Thirty days is the whole log. Intune keeps audit data for thirty days and then it is gone from the service โ not archived, not slower to reach. There is deliberately no ninety-day window: it would return an empty answer for days thirty-one to ninety that looks exactly like a quiet tenant.
Wildcards are wildcards. In the actor and activity boxes, admin* means starts-with and *Delete* means contains. A term with no wildcard is treated as contains, which is what someone typing into a filter box means โ but if you write a wildcard it is honoured exactly, rather than being quietly widened.
An event with no detail is not an event with no changes. Some audit records carry no modifiedProperties at all โ a create, usually, or a service-initiated action. Those say so explicitly rather than rendering as an empty list, because "nothing changed" and "the log does not say" are different answers.
๐ฆ Backup configuration
Reads the configuration surface and writes one .zip in this tab. Nothing is uploaded and nothing is stored โ the archive is built in memory and handed to your browser's download. One permission, read-only, asked on the click.
Interoperable on purpose. The folder names and file names match the PowerShell original exactly, because restore in both his script and TUNO's R09 is driven by folder names. A tidier scheme would have cost that, and interoperability is worth more.
Two things it cannot contain. Graph never returns secret values, so encrypted OMA-URI settings, passwords and certificate payloads come back as references and must be re-entered by hand after a restore โ that is a property of Graph, not of this tool. And a script saved without its body can be read but not put back; leaving bodies out is offered because they can be large, and every file it affects is marked in the manifest.
Missing beats wrong. An object whose detail could not be read is left out of the archive rather than written without it, because a policy restored with the right name and no settings looks like it worked. An area that could not be read at all marks the whole archive partial, on screen and in the manifest.
๐ Configuration documenter
Reads thirteen configuration surfaces once and gives you two things: a filterable list of every policy in the tenant with its settings expandable underneath, and a document you can hand to somebody. Filters apply to what has already been read, so changing one costs nothing โ and they apply to the exports too, so you can narrow to exactly what you need to circulate.
Secrets are redacted and there is no switch. Script bodies, certificates, passwords, pre-shared keys and encrypted OMA-URI values are replaced with a marker: the document records that a value is set without carrying it. This is the artefact most likely to be emailed, and a disclosure in one cannot be recalled.
Clicking a policy opens a popout. Expanding in place was wrong for a list this long โ a settings-catalog policy carries twenty-odd rows, so opening one pushed everything else off the screen and closing it lost your place. Escape, the Close button and the backdrop all dismiss it.
The exports follow the SELECTION, not the filter. Two different jobs: the filter narrows what you are looking at, the tick boxes decide what you are sending. That is what lets you filter to find three policies, tick them, clear the filter, and still export three. Everything is selected after a read; with nothing selected the export buttons disappear, because a button that would produce an empty document is worse than no button.
A partial document says which kind of partial. Every export header states how many of how many objects it holds and whether a person chose them or a filter produced them โ โI picked these twelveโ and โa platform filter left twelveโ are different claims, and neither is โthis is the tenantโ.
Unknown is stated, not hidden โ but differently from the backup tool. A section that could not be read is named as unreadable and is absent from the document. A single policy whose settings could not be read is still listed, with the gap stated, because a document is for reading rather than restoring: knowing a policy exists and that its configuration could not be retrieved is worth more than the policy silently disappearing.
๐ Security model
Sign-in is a SPA authorization-code + PKCE flow with no client secret โ the same model as ENCA, documented in SECURITY.md. You can run TUNO on your own single-tenant app registration: New-TunoAppRegistration.ps1 -SingleTenant.
๐ Credits & thanks
These community projects shaped the tools, and all deserve the credit:
- AppLockerInspector โ by Spencer Alessi. The static check set behind ๐ AppLocker builder & validator: which rules are weak, misconfigured or risky, and why. Licensed MIT.
- AaronLocker โ by Aaron Margosis (Microsoft). The approach behind
Invoke-TunoAppLockerScan.ps1: find every directory a non-administrator can write to, inventory what is in them, and build publisher-first rules with those directories carved back out. TUNO's scan reads each DACL natively rather than shelling out toAccessChk.exe, honours Deny entries, and runs on PowerShell 5.1 and 7. Licensed MIT. - IntuneAutomation โ by Ugur Koc (Microsoft MVP). The Graph work behind ten roadmap items, each linked from its own card:Get Group Assignments (R04), Policy Changes Monitor and Get Intune Audit Logs (R05), Get Intune Role Assignments (R07), Backup / Restore Intune Configuration (R08, R09), Get Defender Status Report (R25), Get Firewall and ASR Status (R26), the MAA Compliance Dashboard Report (R27), Get Compliance Policy Coverage (R28), and Get Windows LAPS Audit (R29). Which endpoints answer which question, which of them only exist on beta, and which expands are needed to make an assignment readable โ that map is his. Licensed MIT.
- IntuneDocumentation โ by Ugur Koc. The coverage plan behind R06: which surfaces belong in a tenant document, in what order, and what has to be redacted before it leaves the tenant. Licensed Elastic License 2.0 โ which permits self-hosting but not offering the work as a hosted service, so TUNO's version is a reimplementation, not a fork.
- LAPS Self-Service Portal โ by Daniel Fraubaum (base-IT). The reason R10 is scoped the way it is. His architecture keeps the privileged token on a server precisely because the browser cannot be trusted to enforce โonly your own deviceโ โ and documenting that clearly is what made it obvious which half of the problem a static site can honestly take on. Licensed MIT.
- JSZip โ by Stuart Knightley. Writes the archive in R08 without a server to zip it. Bundled in
vendor/rather than loaded from a CDN, so the page's content-security policy can keep refusing every origin but Microsoft's. Licensed MIT. - Intune Assignment Checker โ by Ugur Koc. Behind R11, R12 and R14. Most of its assignment reading TUNO already did, which is worth saying plainly; what it had that nothing here did was the simulation โ what a user or device would gain and lose by joining or leaving a group โ and the idea that an assignment reaching an empty group is a finding rather than a row. Both shipped: the simulation as ๐ฎ Assignment what-if, the findings as ๐ฉบ Assignment health, and the definition-catalog search as ๐ฆ Settings search. Licensed MIT.
- Intune Toolkit โ by Maxime Guillemin. Behind R13, shipped as โ๏ธ Assignment editor. A WPF application for bulk assignment editing across every policy, app and script type, with backup and restore of the assignments alone. The surface map is his; the write discipline TUNO put around it โ dry run, automatic backup, typed removal confirmation, drift detection, verify-by-read-back โ is not. Licensed MIT.
- IntuneComplianceMaintainer โ by James Robinson (Microsoft MVP, and the author of OpenIntuneBaseline). Behind R18. Which fields on a compliance and an app-protection policy hold the OS floor, where the supported versions come from for each platform, and the two rules that keep the automation from doing harm โ a cadence before a release is enforced, and no silent downgrade. The Android handling is the part worth copying exactly: target the oldest maintained release, and treat the security patch level as a second floor of its own. Licensed MIT.
- TenuVault TUI โ by Ugur Koc. Behind R15 โ shipped into ๐ฆ T04 at beta 10426 โ R16 and R17, and two rules borrowed into R09. Twenty-seven policy types, a checksum per file with an offline verify, and a comparison between two archives that needs no tenant. The idea worth stealing outright is the smallest one: write the manifest LAST, so its presence is what proves the backup finished. Licensed MIT.
- IntuneShade โ by Alper Atar. Behind R19, R20, R21, R22 and R23. A React console that covers much of the same ground TUNO does, and four ideas here are its: the groups-by-surfaces assignment matrix, setting-level conflict detection rather than only assignment-level, a dedicated assignment filters view with per-filter usage, and AI policy analysis on a bring-your-own key. Where the cards depart from it โ overlap-aware conflict findings, redaction before anything leaves the browser, a key that dies with the session, no script generator โ the card says so. Licensed MIT.
All are independently reimplemented here in browser-side JavaScript against Microsoft Graph โ no code was copied, and where TUNO departs from an original the roadmap card says so rather than leaving you to find out. TUNO's own machinery โ the shell, the tab bar, incremental consent, the changelog and promotion discipline โ comes from ENCA.