Sno Station is your agents' workstation: open-source software that turns the AI agents you already run into one squad on your own machine. Two heads are better than one, and they get better with every
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Organization repository · verify with a repository file
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Free, open-source toolbox for Microsoft Dynamics 365 / Dataverse — 21 modules: query with native SQL/OData/FetchXML, bulk-load, audit security, adoption & storage, explore the data model — right in your browser.
Taken from the repository README
README
Loading the full README. The saved excerpt is shown below.
Free, open-source data explorer for Microsoft Dynamics 365 / Dataverse — directly in the browser.
Colvio is a free and open-source Chrome extension that lets consultants, admins, and developers explore, query, and manage data from any Dynamics 365 / Dataverse environment — directly from the browser, with zero configuration.
No API keys. No app registration. No subscription. Just click the icon on any D365 page and start working.
D365 has always lacked a free, fast, in-browser tool for data exploration and debugging. Now it has one.
Free, open-source data explorer for Microsoft Dynamics 365 / Dataverse — directly in the browser.
Colvio is a free and open-source Chrome extension that lets consultants, admins, and developers explore, query, and manage data from any Dynamics 365 / Dataverse environment — directly from the browser, with zero configuration.
No API keys. No app registration. No subscription. Just click the icon on any D365 page and start working.
One Colvio per environment. Several environments open in the browser? Click the icon on each one: every environment gets its own Colvio tab (DEV and PROD side by side), bound to that environment's URL. Clicking the icon again, from any tab of that environment, brings its Colvio back as you left it — queries, results and scripts kept — and the other environments' tabs are left alone. Each tab's title names its environment.
Coming from XrmToolBox? See XRMTOOLBOX.md — which Colvio module replaces which tool, and what stays with XrmToolBox by design.
Why Colvio?
D365 has always lacked a free, fast, in-browser tool for data exploration and debugging. Now it has one.
Colvio brings the same philosophy to the Microsoft ecosystem:
Free forever — no freemium, no paywalls, no "Pro" tier
Zero config — uses your existing D365 browser session
Privacy first — no data leaves your browser, no telemetry, no accounts
Open source — audit the code, contribute, fork it
Features
Data Explorer
Query tabs — open several queries at once like browser tabs; each tab is fully independent (its own table, mode, filters, results), so you run them one at a time and switch to compare; rename inline (double-click), close with ✕
Query Builder — visual SELECT, WHERE (AND/OR groups, 14 operators), EXPAND (parent + child), ORDER BY, LIMIT (defaults to All — lower it for a quick preview)
Relational filters (REL) — filter the ROOT rows by related records, Advanced-Find style: conditions on a parent's fields (primarycontactid/emailaddress1 contains…) or has-at-least-one / has-none children with conditions (not opportunity_…/any(o:o/statecode eq 0) — "accounts with no open opportunity"); the generated OData is shown in the preview
OData mode — raw OData URL editing; paste any OData query or full Web API URL (from the browser, Postman, XrmToolBox — even another environment's) and Colvio opens its table, also before any table is picked
Column sorting — click any header to sort ASC/DESC
Inline edit — double-click any cell to PATCH the value directly in D365 — typed by the field's metadata: numbers, booleans, option values, dates and GUIDs validated before sending; lookups edited properly via @odata.bind (paste the target record's GUID, empty clears; polymorphic lookups get a target-table picker) with readable refusals instead of cryptic server 400s
Virtual scrolling — 60fps on 10,000+ records (only ~35 rows rendered), with a sticky horizontal scrollbar pinned to the window bottom on wide results
Auto-pagination with live timer and Stop button
⬇ To file — run the query and stream every row straight to a CSV or Excel file (page after page, nothing kept in the browser, any size; Excel gets a new sheet every 1,048,576 rows). A result too big for the browser's memory is never shown partially: the grid stays empty and offers the stream instead
👁 Save as view — the query (Builder, FetchXML or SQL) becomes a personal view of its table, with its columns, filters and sort: it shows up in the app's view selector under My views (only you see it; share it from Dynamics 365). Builder queries are converted to FetchXML, related tables included: an EXPAND becomes an outer link-entity with its columns, a REL filter a on its conditions (inner on a parent, / on children); aggregates, and OData queries are refused with the reason
API Tester
Postman-style client for the Dataverse Web API — authenticated by your active D365 session (no OAuth setup, no client secret)
GET / POST / PATCH / PUT / DELETE on relative paths or full same-org URLs (host re-validated)
Header autocomplete for common Dataverse headers (Prefer, If-Match, MSCRM.* bypass headers)
JSON body editor with line numbers and live validation pointing at the exact parse-error line
Response panel: status, elapsed time, body size, pretty JSON, headers tab
Request templates (WhoAmI, CREATE, PATCH, UPSERT by alt-key, DELETE, RetrieveCurrentOrganization)
History of the last 50 requests (stored locally; secret-bearing headers like Authorization are redacted before saving)
Copy as cURL, Ctrl/Cmd+Enter to send, multiple tabs
Script Console
Run JavaScript against the Dataverse Web API with your session — for what no screen does: fill a lookup from another table, fix data by rules, chain reads and writes, call actions
dv is a complete Web API client: get, getAll (follows @odata.nextLink), fetchXml (paging cookie), retrieve, create, update (never creates), upsert, delete, associate / disassociate, callAction / callFunction (bound or unbound), batch (up to 1,000 requests, atomic changeset or continue-on-error), entity / entitySet metadata, and request() for anything else; GUID or alternate keys; dv.withHeaders() for impersonation and MSCRM.* bypass headers
Dry run first — reads run for real, every write (helpers, raw requests, $batch content, actions) is listed in a Plan and not sent; "Run for real" is confirmed with that plan, a second time on production
Rollback journal — each row is read just before it's written and its inverse kept: updates restored column by column (lookups through their navigation property), created rows deleted, deleted rows recreated with their id and state, N:N links and single-valued $ref restored; actions are marked not reversible. Survives a reload, exports / imports as JSON
input (rows of a CSV / Excel file), log, table (exportable to CSV / Excel), progress, sleep; errors point at the script line; 429 retried after Retry-After; Stop ends the script at once
Saved scripts (work on every org: test on DEV, run on PROD), .js open / download, 6 templates (lookup from a pivot table, update from a file, delete what a FetchXML returns, $batch with bypass headers, N:N links, read-only exploration)
Isolated — the script runs in a Web Worker inside the extension's sandbox page: no network (default-src 'none'), no access to the Dynamics 365 session, the panel or extension storage; it reaches the org only through dv, whose requests are host-locked to your org
Show All Data
Auto-detect current record from D365 tab
Responsive multi-column grid that fills the screen (even 400+ field records stay readable): Logical Name, label, type, value
Filter columns, toggle empty/custom-only, clickable lookup links, copy a single field or full JSON
Inline field editing — a ✎ pencil on every writable field lets you PATCH a value straight through the API, even when the form marks it read-only (text, numbers, yes/no, dates, option sets); field-level security and privileges still enforced server-side, confirmation on production
🔐 Record access — pick a user (or "Me"): Dataverse's own answer for each right on the record (RetrievePrincipalAccess: read, write, append, append to, delete, assign, share) and why — which role or team role, at which depth (User / Business Unit / Parent: Child BU / Organization) against the record's owner and business unit, or a share (RetrieveSharedPrincipalsAndAccess, a share without the privilege behind it is called out) — plus Dataverse's own sentence (RetrieveAccessOrigin) and, for every no, what would grant it (the depth needed, a share, an assignment). The user's roles and teams, who the record is shared with, CSV / Excel export. A fixed number of reads per check (none per role, team or privilege); a gap between Dataverse's answer and the explanation is flagged (hierarchy security, inherited access)
Record activity — save the record in its D365 tab and see what each save triggered: plug-in execution chains (stage, class, duration, cascades, exceptions, full trace on click), the record's system jobs, and the cloud flows whose Dataverse trigger watches the table — triggered / may trigger / won't trigger with the reason, and their runs. Saves are observed read-only by the service worker (column names only, never values, session memory), traces matched by the response's request id when possible; auto-refresh only while something is still running; a "log every plug-in for 15–60 min" switch that reverts by itself. Click a system job for its full message, the plug-in step behind it (stage, trigger columns, run-as user, whether it has a secure/unsecure configuration — never its content) and its last 20 runs ("failing every time since …"), with a hint on what a 401 / timeout usually means; flows show their trigger in words, their error, and Open run ↗ in Power Automate
Business Process Flow manager (System Administrators) — lists every BPF instance on the record, including finished ones the form has locked: reopen, move to any stage, finish or abort (Colvio resolves the flow's real underlying table for the write)
Metadata Browser
Browse entities, fields, OptionSets by category — plus Virtual / Elastic table-type filter chips (find every virtual table at a glance)
OptionSet modal viewer with Value, Label, Description, Color — and ✏️ Edit values on a choice column: add (value optional — Dataverse applies your publisher's prefix), rename, reorder (↑ ↓, Save order) and delete options through Dataverse's own actions (InsertOptionValue, UpdateOptionValue, OrderOption, DeleteOptionValue), published right after; global choices say every column using them changes; a delete first counts the rows of the column holding the value; every write confirmed, a second time on production
Export All OptionSets — bulk CSV/Excel export of all Picklist/State/Status values for an entity (four reads, one per choice type — not one per column)
📊 Fill rate — how many rows have a value in every column of a table, exact: FetchXML aggregates (countcolumn, 40 columns per query); a table past the 50,000-row aggregate limit is counted in created-on date slices (bisection, rows without a date included) — never row by row. Columns never filled and under 5 % are summed up; the fields export gains Filled rows / Filled %
📚 Data dictionary — every column of the custom tables, the tables shown, or all tables (type, required level, custom, primary key / name, create / update, descriptions), one row per column, tables read 20 at a time and streamed to a CSV or Excel file
🔎 Search result columns — for every table, what the global search (Dataverse search) shows in its results and searches in: the table's search switch, its Quick Find view's View columns (shown, also the filters) and Find columns (searched), and the search index's status per table (rows indexed, last sync) when the environment exposes it. Enabled tables first, the org's Find-column total against Dataverse's 1,000 limit, the gaps flagged (enabled without a Quick Find view, no Find column, columns the index doesn't report yet); click a table for display names; CSV / Excel. One paged read of the views, not one per table
🧨 Dependencies of a column or a table — what blocks deleting it (Dataverse's RetrieveDependenciesForDelete) or everything that uses it (RetrieveDependentComponents): forms, views, charts, business rules, flows and workflows, plug-in step filters and images, mappings, keys, field security, apps, site maps… named, grouped, each with how to remove the dependency; the table's own parts are set apart; CSV / Excel export. Read-only, one read + one read per component type to name them
➕ Columns from file — describe columns in a CSV / Excel sheet (display name, type, required level, max length, precision, min / max, options, lookup target, format, description; schema name optional, derived with the solution's prefix), pick the unmanaged solution, and every row is checked against the table and the org before anything is sent (unknown type, duplicate or existing name, missing options, unknown target, ranges…); the valid rows are created one by one with Dataverse's own metadata bodies (text, multiline, whole number, big integer, decimal, float, currency, yes/no, date, date and time, choice, multi-select, lookup = a one-to-many relationship), the table published once, the columns reloaded; per-row result, Stop, template CSV, results export
Automation Inventory
The static inventory of everything registered to run in the org — the design-time counterpart to System Ops' runtime jobs
Plug-in steps: which class runs on which message/entity, Pre-validation / Pre-operation / Post-operation, Sync/Async, Enabled/Disabled, rank, filtering attributes, assembly — internal stage-30 platform machinery hidden by default (like the Plugin Registration Tool)
👤 Who runs it — every identity that makes something run, and what kind it is: App registration (application user, with its Entra app id), Microsoft app, Built-in (SYSTEM / INTEGRATION), Service account (non-interactive access mode), Service account? (a guess from the name or address — svc, integration, noreply…), Person, Team, or Not a Dataverse user (a connection's account that matches nobody in the environment). For each: the cloud flows and processes it owns, the real-time workflows running as their owner, the plug-in steps running as it, the connection references it owns and the connections signed in with its account. A Connections view lists every connection reference with its connector, the account it is signed in with (from Dataverse's connection instances, when the environment stores them), its owner and the flows using it (read from each flow's definition, 25 per request). Flags: disabled identities behind active automation, people (not service accounts) behind active automation, integration identities that run nothing visible (they call the Web API from outside). CSV / Excel export. Read-only
Plug-in step writes — enable / disable one step or a whole selection (select all shown, e.g. every step of an assembly before a data migration; $batch chunks, Stop), and pick an Update step's filtering attributes from its table's columns (steps without any are flagged "⚠ all"); each write confirmed with what stops or changes, a second time on production
Every process definition from the workflow table, in category tabs with counts: classic Workflows (Background/Real-time + C/U/D triggers), Cloud flows (Power Automate), Business rules, Actions, BPFs, Dialogs, Desktop flows
Honest three-way source classification — Microsoft (publisher-prefix heuristic; Dataverse doesn't stamp authorship and registers its own steps unmanaged), Managed (ISV or your own solution), Custom (unmanaged) — plus state and free-text filters, CSV/Excel export of any view
App Inventory
What each model-driven app actually exposes — tables, forms, views and modern commands, read straight from the runtime tables (appmodule, appmodulecomponent, systemform, savedquery, appaction)
The invisible include-all flag, made visible: when a maker leaves "All forms" / "All views" checked, Dataverse creates no component rows and stores no flag — Colvio infers it from the absence of explicit registrations, independently for forms and views, and badges the table ALL FORMS / ALL VIEWS (meaning every current and future form/view will surface in that app)
Per-table accordion with EXPLICIT (hand-picked in the designer) vs IMPLICIT (auto-surfaced) badges on every form and view
Modern command-bar buttons classified by their three scopes: app-specific, entity-global (every app exposing that table), or table-generic templates (every app)
Reverse search — type a form/view/button name and see which apps expose it: the impact map before editing a shared component
On-demand dependency analysis: which attributes and option sets an app's forms/views actually drag in (every required edge read page by page — no cap)
View inspector — click any view to see its filters decoded to plain language (field, operator, value, AND/OR groups, linked-table joins) and its columns: the answer to "why doesn't my record show in that list?" (usual culprit: the statecode = 0 filter hiding inactive rows)
Form subgrids — the ⊞ button on a form lists its child grids: which view each renders, through which relationship, and whether the view picker lets users switch views; Open in Explorer loads the view's FetchXML so you add your parent's filter and test exactly why a row matches or not
CSV/Excel export of the flat inventory (selected app or all apps); apps with blank display names (internal placeholders) hidden
Environment Variables
Defaults, per-environment overrides, and the ⚠ NO VALUE trap surfaced first — a variable with neither override nor default reads as an empty string in flows and plug-ins, which fail three screens later; Colvio counts them in a banner and a dedicated filter
Typed editing of the override: yes/no for Booleans (the documented convention), JSON validated before save, numbers checked; "Clear override" falls back to the default; production asks for confirmation
Secrets handled honestly — the value is a Key Vault reference, never the secret itself, and the UI says so; overriding a managed definition is flagged as the normal per-environment pattern
Filters (No value / Overridden / Secrets), search, CSV/Excel export with each variable's effective source
Web Resources
Every web resource of the org (scripts, styles, HTML, XML, images, RESX…), Microsoft's and hidden ones behind a toggle, filtered by name and kind
Editor for text kinds — Save, or Save & publish (Ctrl+S), Revert, each write confirmed (a second time on production), a resource from a managed solution warns that its next import may overwrite the change; UTF-8 BOM preserved; images previewed; anything downloads as its file; Open ↗ shows the published version in Dynamics 365
🔎 Search in contents — reads the text resources 25 per request (progress, Stop) and lists every line holding what you type (a column's logical name before deleting or renaming it, a URL, a function), case / whole-word options, a hit opens the editor on its line. The complement to Metadata › Dependencies: Dataverse's dependency tracking never sees inside a script
Data Loader
N:N tables (teammembership, systemuserroles, custom many-to-many) — loaded by association: pick the intersect table, give one file column per end (a GUID, or a value resolved against a text column of that table — an email for systemuser, a name for team), ASSOCIATE or DISASSOCIATE. Dry run, per-row log (blank, unresolved, ambiguous and duplicate pairs reported), retry of the errors, rollback of what a run added; an association that already exists counts as "already", never as an error.
UPSERT — match on GUID or alternate key: update if found, create otherwise
UPDATE (existing only) — strictly update via the native If-Match: * header: a missing or empty key fails the row, never creates; optional parallelized existence pre-check for orgs that don't honor If-Match on alt-keys
DELETE — remove records matched on GUID or alternate key, typed confirmation required
🔍 Dry run — simulate the entire import (parsing, transforms, lookups, existence checks) with zero writes; per-row would create / update / fail / delete report
↩ Rollback — created GUIDs are captured from the batch responses; one typed confirmation deletes exactly the records a run created
Δ Delta mode — fetch current org values and send only the fields that changed; unchanged rows skipped entirely
Team-aware owner lookups — direct ownerid GUIDs are probed user-vs-team and bound to the right entity set
Smart auto-mapping with metadata-driven lookup detection (auto-skips Lookup-type fields, picks alt-keys over PKs, warns on non-writable fields per mode)
Column transforms: picklist/statecode label→value (OptionSet preloaded; unmatched labels reported, never silently dropped), locale-aware dates (dd/mm/yyyy, US auto-detect, time + AM/PM), locale-aware numbers (1,5, 1.234,56), booleans EN/FR
Mapping templates — save and reload a full configuration (mappings, lookups, key, mode) per entity
Recycle Bin
List & restore deleted records — true server-side restore via Dataverse "keep deleted records" (queried with FetchXML datasource='bin', restored with the platform Restore action)
Detects whether the feature is enabled (retention days shown) and explains how to enable it
Every Microsoft limitation surfaced in plain words (pre-enablement deletes, virtual/elastic/solution tables, >600-column tables, cascade ordering, key conflicts)
Shows who deleted each record (from the audit log, best-effort) plus who created / last modified it; paginates through large bins (page size + Prev/Next) and searches deleted records by name server-side
Record Change History
In Show All Data: the audit timeline of any record (who, when, which action) with click-to-expand field-level diffs (old → new, formatted values)
Reads the audit table directly (the Web API change-history function omits user/date — documented MS limitation)
System Ops
System Jobs monitor — quick filters for failed / waiting / in-progress jobs, bulk Cancel and Resume with the documented state transitions (admin-gated)
Plugin Trace viewer — exceptions highlighted, full trace text, duration warnings, CSV export; enablement and the 24h auto-purge documented in-UI; quick time windows (last 15 min / hour / 6 h) instead of a pointless calendar — the platform purges traces after ~24 h
Cloud Flow Runs — the Power Automate run history of solution cloud flows, read from the org-side flowrun table (~28-day retention): status badges with a Failed filter, duration, trigger, error message, CSV/Excel export; "My flows" outside solutions and older orgs without the table get honest messages
All panels paginate (page size + Load more, no hard cap) with server-side filters; name search on jobs, text + minimum-duration on traces
Schema snapshot & diff
Export the org schema as JSON, load a snapshot from another environment and get a ranked diff (missing tables/columns, type mismatches) with CSV export — deployment prep in two clicks
Relationship Graph
Visual SVG graph: N:1 parents, 1:N children, N:N many-to-many
Business relationships first (alphabetized) — the system plumbing every table carries (createdby/owner/currency/process, async-job children) starts hidden behind an honest "Show N system" toggle
↻ refresh that actually clears the metadata cache (relationships are cached 1h — a relation created minutes ago needs it)
Depth control (1-2 levels), click nodes to drill down
Entity cards with fields, type indicators, FK badges on lookups
Bezier curves connecting lookup fields to target entity cards
Drag cards to rearrange, scroll to zoom, drag canvas to pan
Expand/collapse individual cards or all at once (Tables/Fields toggle)
"Add Related" button (+) to auto-add connected entities
N:N relationships draw as dashed labeled edges between cards (hover = relationship name); a lookup outside the visible field rows anchors to the card header instead of disappearing
40+ component types resolved to display names against Microsoft's official enumeration (Entity, Attribute, OptionSet, View, Web Resource, Security Role, Email Template, Model-driven App, Environment Variable, SLA, Routing/Convert Rule, Plugin Type/Assembly, SDK Step, Canvas App…); each component's name resolved per type instead of a raw GUID
Managed/Unmanaged badges, component counts
⇄ Compare two solutions — component diff of any two solutions of the org: Only in A / In both / Only in B, grouped by type, CSV/Excel export of the full diff, and a warning when two unmanaged solutions share components (the classic layering conflict — whoever publishes last wins)
Cross-org compare (DEV vs PROD drift) — export a solution's component list as a compare file (.json), load it on another org and diff against the counterpart solution: same three buckets plus a version-drift note; two-pass matching stated on screen (GUIDs for solution-transported components, unambiguous type+name for metadata whose MetadataIds are org-local)
Translation Manager
View and edit field labels across multiple languages inline — each language shown with its proper name (full Dataverse language coverage, no raw LCID codes)
Non-renameable fields locked as read-only (🔒 icon)
Export/Import CSV for bulk translation workflows
Save changes + auto-publish entity
User & License Monitor
Load all D365 users with full pagination (no limit)
Filter: Active / Disabled / Non-Interactive, local search by name, email, BU
Sort by Name, Status, CAL Type, Access Mode
User detail: Access Mode, CAL Type, Business Unit, title, creation date
Last login date from audit logs (with "X days ago" indicator)
Security Roles list per user
Access Mode + CAL Type breakdown stats across all users
CSV export of full user list (formula injection protected)
Identify unused licenses: disabled users, users who never logged in
Bulk settings — change a setting for many users at once, with readable values: personal settings (usersettings: email tracking, time zone from the org's own definitions, UI / help language among the provisioned ones, regional format, currency, records per page, send-as, script error reporting, default search) and server-side-sync mailbox options (mailbox: incoming / outgoing / appointments-contacts-tasks delivery methods, email approval). Filter users by search, business unit, security role, status, people vs service accounts, and last login (signed in / never signed in — from the user-access audit, read for everyone at once in time windows, never one request per user, with a column showing each user's date); each row shows the current value and what would change (users already at the value are skipped); production confirmation, 4 writes in parallel with Cancel, per-user result with the server's message, retry of the failures only, CSV/Excel export of the current values
Security Audit
Browse all D365 security roles (filter: Custom / Managed)
Matrix view (by table) — the full make.powerapps-style grid: every table × Create/Read/Write/Delete/Append/Append To/Assign/Share with a depth pie per cell, including what is NOT granted — and the whole grid exports to CSV/Excel
Has privilege filter — pick any privilege (table rights or miscellaneous ones like Export to Excel, Bulk Delete, Publish) and the role list keeps only the roles that hold it, widest depth first, with a minimum-depth filter and CSV/Excel export — one query, not one per role
Org-wide view — "who can do what" across every role at once from ONE read of the role ↔ privilege table: pick an operation + minimum depth, group by role or by table ("which roles can delete Account?"), full export; a failed read is flagged with a retry (never a silently incomplete audit)
Users sub-tab — lists exactly who holds the role (name, email, business unit, status), aggregated across every business-unit copy of the role and deduplicated so members in child BUs are never missed, with service-account flags; CSV export on both privileges and members
Teams sub-tab — the teams holding the role (type, BU, administrator, member count) — the answer when a role shows 0 direct users but is very much in use
Bulk role assignment — paste a list of user emails to assign a role (Colvio matches each user's business-unit copy automatically — the classic trap), or select members and remove it; confirmation on production
Business Units
BU hierarchy as an indented tree (search), each with its direct user count and a disabled badge
🌳 Full-screen org chart — the hierarchy as an actual organigram (boxes + connectors, parents centered over their subtree): opens FOLDED to two levels with ±N chips per branch (a 1,000+-BU org stays readable), Fit/Expand all/Collapse all/hide-disabled controls, user counts per BU, click a box to open that BU, PNG export for docs and decks
Pick a BU to list its direct members — name, email, access mode / CAL type, enabled/disabled — with a filter
CSV export with scope choice: just this BU's members, or this BU + every sub-BU beneath it (the export keeps a Business Unit column); even works when the BU itself has no direct members
➡ Bulk move users to another BU (System Administrators) — tick members, pick the target, per-user results with failures kept selected for a retry; the roles truth is stated before confirming: legacy orgs remove every security role on a BU change, modern orgs retain them — Colvio reads the org setting and says which applies (and points to Security Audit's bulk role assign when needed)
📋 Paste-a-list selection — paste email addresses or UPNs (newlines, commas, Outlook Name <email> format all parse) and every match in the displayed BU is auto-checked for the move; the recap lists unmatched addresses verbatim (typo, not synced yet, other BU) — built for real provisioning waves
↻ Member refresh — reload a BU's member list without leaving the module (freshly provisioned users appear as soon as the Entra sync lands)
Reuses the all-users fetch grouped by _businessunitid_value; admin-gated
Teams
Every team of the org with its type badge — Owner (owns records, carries security roles), Entra security/office group (mirrors an Entra ID group), Access (per-record sharing teams, loaded on demand and capped at 500 — they can number in the thousands)
Pick a team to see its identity card (business unit, administrator, created date — and for Entra teams the group Object ID, copiable for the Entra admin center), its security roles (the second channel of privilege: members inherit them, and an inherited role never appears on the user), and its members (name, email, access mode / CAL, status) with filter and CSV/Excel export
Honest Entra semantics stated in the UI: group membership materializes lazily (a user appears after their next access) and is managed in Entra ID, not Dataverse
Each BU's auto-created default team is badged and sorted last; admin-gated, read-only
Storage
Rows per table for every table — from RetrieveTotalRecordCount, Dataverse's own snapshot (≤ 24 h old): the whole org loads in a few seconds, no scan. Ranked biggest first, chips (Custom / Standard / System growth / File / Log), search, CSV/Excel export
Storage class per table following Microsoft's split: notes, attachments, file/image columns and web resources → File; audit, plug-in traces and elastic tables → Log; the rest → Database. Virtual tables excluded (no Dataverse storage)
Tables that grow silently — system jobs, workflow logs, plug-in traces, audit, emails, import leftovers — each with its count and the cleanup action that applies
File storage by table, in real bytes — sum of notes, file & image columns and email attachments, grouped by owning table. Runs in the background after the table list is on screen; over 50,000 files per source the platform refuses one aggregate, so Colvio bisects by period automatically (progress bar, Stop, partial results flagged)
Honest about the limit: the billed GB (Database / File / Log capacity) are only in the Power Platform admin center, behind an API that needs an app registration — the module links there and says so. Session cache: coming back to the tab is instant; ↻ reloads
Health check
One report on what silently hurts the environment, 12 checks run one after the other: plug-in trace log setting, auditing (and retention), system jobs failed in the last 7 days (grouped by job), suspended system jobs, active cloud flows owned by disabled users, synchronous Update plug-in steps without filtering attributes, real-time classic workflows, connection references without a connection, environment variables with neither a value nor a default, enabled users without a security role, unmanaged solutions in production, log table sizes
Each check is a few reads — FetchXML aggregates, or full lists read page by page (paging cookie) — never capped, never one request per item; one that can't run says why and the others still answer. Every finding says what to do; the items behind it open in place
📋 Copy report (plain text for a ticket), CSV / Excel with one row per item; Stop keeps what's done. Read-only
Adoption
Who's actually using the CRM? Access events, distinct active users, DAU/WAU/MAU + stickiness — over 7/30/90 days or any custom window
Honest by construction: Dataverse logs access at most once per UserAccessAuditingInterval (default 4 h) — the KPI says "access events", an activity proxy, not literal logins; service accounts (non-interactive, S2S application users) are excluded from every number by default (toggle to include)
Exact totals whatever the audit volume — Dataverse aggregates each day server-side (per-user counts, never raw events), so orgs with millions of audit rows hit no fetch cap; a day that fails to load is flagged with a retry, never silently missing
Trend chart (events / distinct users / both), events-by-weekday profile, adoption rate per business unit (active ÷ enabled, with export)
"⇄ vs previous period" — on-demand comparison with the preceding window of the same length, ▲▼ deltas on events and distinct users
Per-user table in two modes: active users, or all in scope with license type and inactivity (days since last access, ≥30/60/90 filter) — the license-cleanup deliverable
Never-signed-in list — enabled human users with zero events in the window; export includes email and license type
Service & application accounts section — Non-Interactive / Support / Delegated Admin / S2S application users listed separately with their own event counts and last access (API access is audited too); zero events highlighted — an integration that silently stopped calling is a finding
Filter everything by security role or business unit — with a "+ child BUs" option widening the BU filter to its whole subtree (parent BUs selectable even without direct users) — instant, client-side; needs "Audit user access" enabled, sees what your audit retention keeps (both stated in the UI)
📊 One-click PowerPoint report — a 5-slide management deck with native editable charts (not images): title, KPI grid with the honesty note, trend, weekday & per-BU adoption charts, findings (never-signed-in by license, inactivity, silent service accounts); the ~370 KB PowerPoint library loads only when you click
Login History
User search, access timeline from the user-access audit — app (web, action 64) vs web services (API, action 65)
Access events per channel, active days, last access, CSV/Excel export — no session durations: Dataverse logs at most one access per interval and has no sign-out event
Help & Onboarding
Built-in Help tab with feature guide
First-launch onboarding tour (5 steps)
Keyboard shortcuts panel (Ctrl+/)
Contextual tooltips on key features
SQL Query Mode — two engines, and UPDATE / DELETE with a preview
UPDATE / DELETE on one table (UPDATE account SET telephone1 = '0102', revenue = 2000000 WHERE statecode = 0, DELETE FROM contact WHERE emailaddress1 IS NULL): Execute becomes Preview — the statement's WHERE runs as a SELECT through the same engine and the grid shows every row it would touch with its current values; Apply writes exactly those rows (update-only PATCH in $batch, or batched DELETE), with a confirmation (two on production), progress, Cancel and the server's reason per failure. Values are constants (text in quotes, numbers, NULL, TRUE/FALSE, a GUID for a lookup), typed and refused BEFORE anything runs by the same code as inline edit. A WHERE is mandatory (to touch every row on purpose: WHERE <primary key> IS NOT NULL); UPDATE … FROM/JOIN and expressions are refused with the reason
Completion as you type (like Salesforce Inspector): after FROM / JOIN, the environment's tables matching what you type; in the SELECT list, WHERE, ON, ORDER BY…, the columns of the table named after FROM (alias. narrows to one table of a join). Nothing is offered while there is no table yet or the table doesn't exist. Tab / Enter inserts, ↑↓ moves, Esc closes.
⚡ Native (default): your SELECT is sent straight to Dataverse via the Web API ?sql= option — the server parses and executes it. Multi-table INNER/LEFT JOIN with table & column aliases, self-joins, DISTINCT, server-side GROUP BY + COUNT/SUM/AVG/MIN/MAX, DATEADD/GETUTCDATE relative dates. Auto-paginated via @odata.nextLink
⇄ Transpiled: Colvio's own SQL→FetchXML converter — still the only engine with HAVING and TOP, and the automatic fallback on environments without ?sql= (detected on first run)
Server limits stated honestly (native): no SELECT *, subqueries, HAVING, TOP, UNION; aggregates capped at 50k; not available on virtual tables
"View FetchXML" toggle shows the transpiler's generated XML
Engine-aware template queries to get started
Global
Sidebar organized in three sections — Data / Develop / Admin, in decreasing frequency of use; a section whose tabs are all permission-hidden disappears entirely
⌘K / Ctrl+K command palette — jump to any module or action
"What's new" popup after each update (per-version, EN/FR)
Session expiration detection with Reconnect button
Memory-saver-proof transport — the D365 org tab (Colvio's API channel) is pinned awake during use; if the browser sleeps or replaces it anyway, the relay wakes it, re-injects and retries before failing — and never sends a request to a tab showing a different environment
Error boundaries per tab (graceful crash recovery)
Colvio has been through a full security audit. Results: 0 critical, 0 high, 0 medium open findings.
Data Protection
Zero data exfiltration — no external servers, no analytics, no telemetry (every fetch targets your own Dataverse org, same-origin credentials)
PII protection — query history strips filter values before persisting; API Tester history redacts secret-bearing headers (Authorization, Cookie, API keys)
CSV formula injection protection — exported CSV cells prefixed to prevent spreadsheet formula execution (XLSX exports keep real typed cells — string cells in .xlsx are inert)
Anti-fingerprinting — content script marker is non-enumerable
Input Validation
Entity/field name validation — all names validated with regex in the content script
OData injection protection — numeric filter values validated, Lookup GUIDs format-checked, control characters stripped from batch key values (CRLF-injection proof)
Content script as modules — src/content/ (core, one module per domain of actions, the dispatcher) bundled by Vite into one readable dist/content.js, not minified, every comment kept: what the store reviewer reads is what the repository holds; the dispatcher runs tests (contentScript.test.js) against a scripted Dataverse
Same-org enforcement — API Tester and Script Console re-validate the final URL host after path assembly; the Script Console also its resolved path (Web API only: dot segments, %2e%2e and backslashes refused before the request is built, /api/data/vX.Y/ re-checked on the final URL)
Script Console sandbox — user scripts run in a Web Worker of a manifest sandbox page (opaque origin, CSP default-src 'none'): no network, no cookies, no extension API; every Web API call is relayed to the panel and checked there
Content Security Policy — explicit CSP on panel.html
Write Operation Safeguards
Every user-typed write goes through one tested typing module — Explorer bulk update, inline edit and Show-All-Data editing share the same metadata-driven coercion: wrong-type values (text in a GUID/lookup, comma decimals, option labels) are refused readably before anything is sent, and a mistyped number can never silently clear a field
Typed confirmation on bulk delete — you must type the entity name to confirm
UPDATE mode never creates — native If-Match: * on every PATCH + empty-key rows rejected client-side (optional existence pre-check as a second layer)
CanBeDeleted pre-check — verifies entity metadata before allowing delete
Confirm dialog on bulk update — shows field name, value, and record count
Client-side rate limiting — max 30 requests/second, plus automatic Retry-After back-off on 429
Cancel is honored end-to-end — a cancelled import stops pending chunks and in-flight retries; nothing is written after cancel
Server-side enforcement — all write operations respect your D365 security roles, Colvio cannot bypass RBAC (Speed boosters are gated on the prvBypassCustomPlugins admin privilege)
Manifest V3 — minimal permissions (scripting, storage, declarativeContent, webRequest — observe only, to list your own saves — and alarms — to revert the trace-log switch —, unlimitedStorage — so a Script Console rollback journal is never cut by the 10 MB quota; 3 host wildcards, dynamics.com / microsoftdynamics.us / dynamics.cn only)
Saved queries — persist across sessions (20 max); the loaded one shows next to ⭐ with a one-click Update that overwrites it, and saving under an existing name says it replaces it
Query History — auto-save last 20 queries, 1-click reload; Builder queries restore into the Builder (columns, condition fields + operators, sort, limit, REL and EXPAND clauses — condition values are never persisted, by privacy design)
Query Templates — 5 pre-built queries for common consultant tasks
Bulk Update — select records and PATCH a field on all, with the same metadata-typed conversion and pre-send refusals as inline edit
Bulk Delete — select and delete with typed confirmation + CanBeDeleted pre-check, on the fast $batch pipeline (chunks × parallel workers, automatic 429 retry) with a shared ✕ Cancel for both bulk operations (honest "X done, Y untouched" feedback)
⧉ Duplicate finder — pick the columns that define a duplicate; groups computed over all loaded rows on raw values (lookups compared by GUID, optional dates-by-day), KEEP/DELETE verdicts per row, one click selects the excess rows for the normal bulk delete, CSV export of the groups as review/undo file
Clickable lookups — opens target record in D365
N:N (intersect) tables — teammembership, systemuserroles and custom many-to-many tables are listed with an N:N badge and query like any table (the Data Loader loads them by association)
Columns in the query's order — in the grid and in every export, whatever the mode (SQL and OData included, not the table's own order)
Copy OData URL — one-click copy for Postman/browser
📑 Solution layers of a column or a table (msdyn_componentlayers, the maker portal's "See solution layers"): every layer top first — solution, publisher, managed / unmanaged / system, time — with the properties each one changes (values set again higher up struck through); an unmanaged "Active" layer sitting on a managed solution is called out, with the properties it overrides (the classic "my deployed change doesn't show"). Read-only; CSV / Excel export
Entity record counts, field type badges, custom field indicators
Multipart OData $batch with per-record changesets — errors don't cascade across the chunk
429-aware: Service Protection throttling retried automatically honoring Retry-After
Alt-key direct bind: when the lookup target field is a registered alternate key, skips the resolve query (no ?$filter=... per unique value) and binds via entity(field='value') syntax; lookup @odata.bind paths use the real EntitySetName (irregular plurals, polymorphic targets)
Column transforms extras: the literal word NULL in a cell clears the field — including lookups (empty cells always leave fields untouched, so a partial file can never wipe data); strip HTML → plain text for rich-text exports landing in plain-text columns; EU/US date-format toggle (day-first vs month-first) so 03/04/2024 never silently becomes the wrong date
Migration mode (opt-in, create-only): map createdon (→ overriddencreatedon), modifiedon, createdby, modifiedby so migrated records keep their original audit values (requires prvOverrideCreatedOnCreatedBy)
Pre-flight checks before the run: values exceeding the target field's max length, empty/duplicate match keys, Salesforce-style IDs where a GUID is needed, unmapped required fields, file-lines vs parsed-records transparency (multiline cells vs a stray unclosed quote — named record)
Honest accounting: a chunk timeout can never silently drop rows — every unsent row becomes an explicit retryable error and totals always sum to your file size; retry transient failures (timeouts, 429, 5xx) at gentler concurrency from the result screen
Speed boosters (System Administrators only), using Microsoft's documented bypass headers on imports and bulk deletes: MSCRM.BypassCustomPluginExecution (sync plug-ins + real-time workflows), MSCRM.BypassBusinessLogicExecution: CustomAsync (async plug-ins + background workflows), MSCRM.SuppressDuplicateDetection
Live per-row import log during the run: every line shown with its CSV columns + Success/Failed status + Dataverse error detail + the exact request sent (method, URL, headers, body)
Cancel mid-import — stops remaining chunks and in-flight 429 retries: no writes are sent after cancel