PanopticonAuditHistorySearch 0.1.0.4

dotnet add package PanopticonAuditHistorySearch --version 0.1.0.4
                    
NuGet\Install-Package PanopticonAuditHistorySearch -Version 0.1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PanopticonAuditHistorySearch" Version="0.1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PanopticonAuditHistorySearch" Version="0.1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="PanopticonAuditHistorySearch" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PanopticonAuditHistorySearch --version 0.1.0.4
                    
#r "nuget: PanopticonAuditHistorySearch, 0.1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PanopticonAuditHistorySearch@0.1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PanopticonAuditHistorySearch&version=0.1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=PanopticonAuditHistorySearch&version=0.1.0.4
                    
Install as a Cake Tool

An XrmToolBox plugin for searching Dataverse audit history across many tables at once.

0.1.0.4. Pre-1.0: the cache format may change between releases, so purge and re-sync after upgrading.

Dataverse makes audit data hard to interrogate. The Audit Summary view only sorts by Changed Date, its Record filter does not work, and Microsoft does not support exporting audit logs at all - the SDK is the only way out. Answering "who set this field to X, and when?" across a table normally means hand-writing FetchXML and a detail-fetch loop.

Panopticon syncs audit metadata into a local SQLite cache, then searches it instantly, pulling old and new values on demand.

Features

  • Multi-table search - select any number of audit-enabled tables and get one merged result grid.
  • Filter by changed field - "show me every change to statecode" resolved locally, without a single value-fetch call.
  • Preflight cost estimate - see row count, disk size and expected duration before syncing, with automatic sampling when the range is too large to count exactly.
  • Record timeline - double-click any row for that record's full change history.
  • CSV export - metadata-only, or with old/new values behind a cost gate. Opens straight into Excel.
  • Resumable sync - cancel any time; completed monthly windows are kept and skipped on the next run.
  • Service protection aware - honours Retry-After on 429 and backs off rather than failing.

How it works

Dataverse exposes audit data through two very different doors, and the split drives the whole design:

Audit table query RetrieveAuditDetails
Returns who, when, which table, which record, which fields changed old and new values
Cost 5,000 rows per request one request per audit row
Practical throughput ~1-5 min per million rows ~1-2k rows per minute

So Panopticon caches the first tier and never bulk-caches the second. The attributemask column - a CSV of AttributeMetadata.ColumnNumber - is exploded into an indexed table at sync time, which is what makes field-level filtering an index seek instead of a table scan.

Cache

One SQLite database per environment, under:

%APPDATA%\MscrmTools\XrmToolBox\Panopticon\<organization>.db

Roughly 400 bytes per audit row, so ~400 MB per million rows. Its size is shown in the toolbar and Purge cache deletes it.

Panopticon defaults to the last 30 days and refuses an open-ended range. Widening past 90 days prompts you to estimate first; past 365 days requires explicit confirmation.

Requirements

  • Windows, XrmToolBox, .NET Framework 4.8
  • Dataverse privileges: View Audit Summary (prvReadAuditSummary) and View Audit History (prvReadRecordAuditHistory). Panopticon probes for both on connect and tells you which one is missing.

No native SQLite binary is deployed - the plugin binds to winsqlite3.dll, which ships with Windows.

Installation

Not published to the XrmToolBox Tool Library yet, so build and deploy it yourself:

git clone https://github.com/HurleySk/PanopticonAuditHistorySearch.git
cd PanopticonAuditHistorySearch
dotnet build --configuration Release
.\deploy.ps1 -Force

deploy.ps1 closes XrmToolBox, builds, copies the plugin to %APPDATA%\MscrmTools\XrmToolBox\Plugins, clears the manifest cache so the tool is rescanned, and relaunches.

Usage

  1. Connect to an environment. Panopticon checks audit access and loads the audit-enabled tables.
  2. Check the tables you care about. The range starts at the last 30 days.
  3. Estimate cost if you widened the range, then Sync audit data.
  4. Filter by user, event, operation, record name, or changed field, and hit Search cache.
  5. Select a row to load its old and new values; double-click for the record's full timeline.
  6. Export CSV when you have what you need.

Re-syncing the same scope is cheap - completed monthly windows are skipped. Tick Force refresh to re-pull them.

Known limits

These are Dataverse constraints, not plugin bugs:

  • Audit data is not available through the TDS/SQL endpoint, so SQL 4 CDS cannot query it directly.
  • The audit table joins only to systemuser, so record and table names are resolved client-side, lazily, for visible rows.
  • Values over 5 KB are truncated by the platform. Panopticon flags truncated values rather than presenting them as complete.
  • Exact row counts fail above the 50,000 aggregate limit; the estimate falls back to sampling and says so.
  • attributemask is documented as internal. Panopticon validates the mapping against a real audit row on connect and disables field filtering with a clear message if it does not line up.
  • Results are capped at 250,000 rows in the grid. The full match count is still reported.

Packaging

dotnet pack --configuration Release

The main DLL packs to Plugins/; SQLite dependencies pack to Plugins/Dependencies/. Both the NuGet package and deploy.ps1 must keep dependencies in that subfolder: XrmToolBox treats every DLL at the root of Plugins/ as a candidate tool, so a dependency left there is reported under "Tools not loaded" at startup, and the Tool Store validator separately rejects it for not matching the package version.

The icon ships as a deprecated PackageIconUrl only, with no embedded PackageIcon. When a package embeds an icon, nuget.org serves it from /v3-flatcontainer/<id>/<version>/icon as application/octet-stream with X-Content-Type-Options: nosniff, and the Tool Library registration rejects it with "Logo Url is not valid". With iconUrl alone, nuget.org proxies the image and serves it as image/png, which is what every tool already in the library does. NU5048 is suppressed for this reason - do not "fix" it by switching to PackageIcon.

XrmToolBox applies no binding redirects to plugin assemblies, so SQLitePCLRaw.bundle_winsqlite3 is pinned to the exact version Microsoft.Data.Sqlite references (2.1.6.2060 for 8.0.10). A newer bundle builds and passes tests - the test host generates redirects - then fails at runtime inside XrmToolBox with a FileNotFoundException on SQLitePCLRaw.core. Bump both together or not at all.

Releasing

Publishing runs from .github/workflows/release.yml and uses trusted publishing, so there is no API key to store or rotate. The job requests a GitHub OIDC token, NuGet/login@v1 exchanges it with nuget.org for a key that lives one hour, and that key pushes the package.

The trust lives on nuget.org, not here: under your username > Trusted Publishing, add a policy with repository owner HurleySk, repository PanopticonAuditHistorySearch, workflow file release.yml (file name only) and no environment. A policy is scoped to a nuget.org owner, so it authorises every package that owner holds, not just this one.

Then bump <Version> in the csproj and AssemblyVersion/AssemblyFileVersion in Properties/AssemblyInfo.cs to the same 4-part value, and tag:

git tag v0.1.0.4 && git push --tags

The workflow refuses to publish unless the tag, the csproj version and the built assembly version all agree, and unless exactly one DLL sits at the root of Plugins/. Run it from the Actions tab with dry run ticked to build and inspect the package without pushing.

License

MIT - see LICENSE.

Author

Samuel Hurley - HurleySk

Built on XrmToolBox by Tanguy Touzard.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0.4 211 8/31/2026
0.1.0.3 124 8/26/2026
0.1.0.2 103 8/26/2026
0.1.0.1 109 8/26/2026

Quick date ranges now select exactly 30, 90 or 365 days. Sync progress names the table and window being processed. Purging the cache no longer fails with the file in use.