EntraExportRestore
Selective Microsoft Entra ID attribute backup and recovery using Microsoft Graph. This guide describes the product at a high level, how to use the desktop apps and command-line interface, and important security and platform constraints.
1. Overview
EntraExportRestore is a precision instrument: you choose which object types and which attributes to capture. Exports produce versioned snapshots stored in a local SQLite database. Restore operations write selected, restorable attributes back to Entra through Microsoft Graph, matched primarily by each object’s immutable id.
This is not a whole-tenant disaster-recovery appliance. It is designed for deliberate, attribute-level backup and recovery with minimal data capture beyond your selections.
2. Release notes
This section summarizes notable changes by product version. Your installed build version appears in each desktop app’s About dialog and in CLI help output. When upgrading, existing backup databases and settings under %AppData%\EntraExportRestore\ are preserved unless you remove them manually.
2.1 Version 1.3.0 (June 2026)
Upgrade from: 1.0.x–1.2.x (supported installer range: 1.0.0 through 1.2.9). Version 1.3 adds Conditional Access policy and named location export/restore, and persistent delegated credential caching for the desktop apps.
Conditional Access and named locations
Catalog v1.1.0 introduces two opt-in object types backed by Microsoft Graph identity/conditionalAccess/ endpoints:
| Object type | Attributes (examples) | Restore behaviour |
|---|---|---|
| Named Location | displayName (label/filter); locationDocument (full IP or country location definition) |
locationDocument is restorable and sensitive. Restore PATCHes the live object by Graph id (with display-name fallback when the object was recreated). |
| Conditional Access policy | displayName, state (filter aid); policyDocument (full policy definition) |
policyDocument is restorable and sensitive. Restore updates conditions, grant controls, and session controls from the snapshot document. |
Object-level restore. Select the object types in Export and Restore, include the document attributes, and run restore. By default only existing objects are updated. To POST missing named locations or policies, enable Recreate missing named locations and policies in Restore Preview, pass --create-missing on the CLI, or set allowCreateMissingObjects in config.json.
Ordering and ID remap. Named locations restore before policies in the same operation. Named-location IDs embedded in policy includeLocations / excludeLocations are remapped to live IDs within the same tenant. User, group, role, and application IDs inside policy conditions are not remapped.
Preview and difference reports. Restore preview and exported HTML/JSON/CSV reports show human-readable summaries for location and policy documents (display name, state, locations, grant controls, and so on) instead of raw Graph JSON. After a successful restore, a new preview resolves live objects by display name when snapshot IDs changed, so rows should show Same when the tenant matches the backup.
Requires Policy.Read.All and Policy.ReadWrite.ConditionalAccess plus an appropriate Entra administrator role. See section 10.
Desktop credential caching
EntraExportUI and EntraRestoreUI now persist delegated sign-in state for each Windows user profile:
- Token cache — Refresh and access tokens are stored in an encrypted file at
%LocalAppData%\Madriam\EntraExportRestore\msal.cache(Windows DPAPI). Both desktop apps share this cache. - Silent sign-in — After the first interactive sign-in, later sessions use silent token acquisition when tokens are still valid, avoiding repeated browser prompts for the same scopes.
- Saved preferences — Custom Client ID and tenant hint choices are stored in
auth-settings.jsonin the same folder (not secrets). - Sign out — Clears cached MSAL accounts for the active registration on that profile. Does not remove snapshot databases under
%AppData%\EntraExportRestore\.
The CLI does not use this cache; unattended automation continues to require your tenant’s app registration and client certificate (see section 6.3).
2.2 Version 1.2.0
Upgrade from: 1.0.x–1.1.x (supported installer range: 1.0.0 through 1.2.9). Version 1.2 adds difference report export (CSV, JSON, HTML) for snapshot-vs-live comparisons in the Restore Preview UI and CLI.
Difference report export
After building a restore preview (snapshot backup values compared with live Microsoft Graph), you can export a difference report:
- Restore UI — On the Restore Preview screen, choose Export report… to save HTML, JSON, or CSV. HTML reports include light/dark theme and in-page filters (All, Has differences, Restorable only). CSV export matches the preview filter and search box.
- CLI —
restore preview <snapshotId> [--format text|json|csv|html] [--output <path>] [--filter all|differences|restorable] [--include-raw-values]. CSV and HTML require--output. Use global--output(not--output-json, which remains export-only). - JSON shape change (breaking) —
restore preview --format jsonnow writes a structured report document instead of a bare array of preview rows. Update automation that consumed the previous stdout format.
Difference report JSON fields: reportVersion (currently 1), generatedAtUtc, optional productVersion, snapshot (id, completedAtUtc, catalogVersion, totalObjectsExported), summary (row and object counts, difference counts), and rows (per-attribute backup/live values, formatted display values, isDifferent, isRestorable, isSensitive, diffState, restoreState). JSON files always include the full row set; filter in your pipeline using the row flags.
| Format | Typical use | Notes |
|---|---|---|
| HTML | Human review, audit evidence | Self-contained file; theme toggle and filters run in the browser. Always includes all rows. |
| JSON | Automation, SIEM/orchestration | Structured document to stdout or --output. Raw and formatted values per row. |
| CSV | Spreadsheet analysis | Requires --output. CLI respects --filter; optional --include-raw-values. UI export matches the current preview filter. |
See section 12 and section 13.1.
2.3 Version 1.1.1
Upgrade from: 1.0.x–1.1.0 (supported installer range: 1.0.0 through 1.1.9). Version 1.1.1 formalizes CLI exit codes for automation and adds structured export result output for backup pipelines.
CLI exit codes and export JSON
The command-line tool uses a documented set of process exit codes. Run EntraExportRestore --help to print the table inline.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Usage error (invalid arguments or unknown command) |
2 |
Licence verification failed |
3 |
Configuration error |
4 |
Authentication failed |
5 |
Export failed |
6 |
Restore failed or was cancelled |
7 |
Restore completed with partial failure (some attribute writes failed) |
For scheduled export followed by off-host database copy, exit code 0 indicates the snapshot was committed and the process has released the SQLite connection. Use the database path from startup output, config, or the export JSON result below.
The export command accepts --output-json <path>, which writes a JSON result file on completion (success or failure). When --output-json is set, informational stdout is suppressed automatically; export progress remains on stderr. Use --quiet to suppress informational stdout for any command without writing JSON.
Successful export JSON fields: status (completed), snapshotId, databasePath, totalObjectsExported, totalAttributeValuesExported, completedAt (UTC ISO 8601). On failure: status (failed), databasePath, and errorMessage.
See section 12 for the full command reference.
2.4 Version 1.1.0
Upgrade from: 1.0.x (supported installer range: 1.0.0 through 1.1.9). Version 1.1.0 extends automation through the CLI, records product version metadata in SQLite, and ships a Windows installer with explicit upgrade and silent-install behaviour.
CLI enhancements
The command-line tool (EntraExportRestore.exe) adds commands and options for scripted export, restore, and discovery. All commands use the same SQLite database and engines as the desktop apps. See section 12 for the full reference.
| Command | Purpose |
|---|---|
snapshots [--format text|json] |
List snapshots in the configured database so automation can discover snapshot GUIDs without querying SQLite directly. Text output includes object and attribute counts, catalog version, and application version. JSON output includes full snapshot metadata. |
restore preview <snapshotId> [--format text|json] |
Compare snapshot values with live Microsoft Graph values and print a summary or JSON rows without writing changes to Microsoft Entra. |
permissions restore |
Print required Graph write permission names for restore scope (plus read permissions used by preview), based on RestoreSelectionByObjectType in config.json or restore defaults when none is saved. No Microsoft sign-in required (licence still validated). |
restore <snapshotId> [--force] |
Run restore using config-driven scope. Prompts before writing sensitive values; pass --force for unattended runs. |
- JSON output —
--format jsononsnapshotsandrestore previewproduces structured output for pipelines and orchestration tools. - Version in help — Running the CLI with no arguments or
--helpshows the running CLI version. - Restore scope from config — CLI restore and preview honour
RestoreSelectionByObjectTypein the sharedconfig.json(same as the Restore desktop app). - Clearer auth errors — Certificate-based sign-in reports simplified MSAL/AADSTS messages and guidance when the private key cannot be used.
Database version stamps
SQLite databases now record which product version initialized the file and which version produced each snapshot, supporting audit, troubleshooting, and future compatibility checks. No manual migration is required—schema updates run automatically the first time any 1.1.0 component opens an existing database.
Database-level metadata — On first open after upgrade, a DatabaseMetadata row is created if missing:
| Field | Description |
|---|---|
CreatedAt |
UTC timestamp when the database file was first initialized by a version-aware build |
CreatedByProductVersion |
Product semver that created the metadata (for example 1.1.0) |
CreatedByBuildNumber |
Optional build identifier from the release pipeline, when present |
Databases created under 1.0.x receive this row automatically on first open with 1.1.0. The stamp reflects the upgrading product version, not the original 1.0.x install date.
Per-snapshot fields — Each new export stores ApplicationVersion and optional BuildNumber on the snapshot, alongside the existing CatalogVersion (attribute catalog revision). These appear in CLI snapshots output. Snapshots taken before 1.1.0 leave the new fields empty; CLI text output shows unknown for application version in that case.
Capture-only attribute export and restore selection
Capture-only attributes (for example user or group proxyAddresses, group mail, device compliance fields, and all org-contact properties) are now handled consistently across the Export and Restore apps:
- Export app — You can select capture-only attributes explicitly when you need them in a snapshot for reference or auditing. They are not included when you choose Default recommended (that set is restorable attributes only).
- Restore app — Capture-only attributes remain visible for context but their checkboxes are disabled; restore never writes them.
- CLI — Default export scope (when
ExportSelectionByObjectTypeis empty) follows the same Default recommended rule: restorable attributes only. Add capture-only property names to your config when you want them in automated exports.
Windows installer
Version 1.1.0 introduces a Windows NSIS setup executable with explicit fresh install, in-place upgrade, repair, and unattended deployment behaviour. New command-line switches—/S (silent), /ALLOWUPGRADE=1 (silent upgrade or reinstall), and optional /D=... (install directory on fresh install)—support scripted deployment. See section 3 (Installation) for full documentation.
3. Installation
EntraExportRestore is distributed as a Windows NSIS setup executable (EntraExportRestore-{version}-Setup-x64.exe) and as a portable ZIP. The installer places binaries under %ProgramFiles%\Madriam\EntraExportRestore, adds the CLI to the machine Path, and registers the product in Add/Remove Programs. User settings and backup databases under %AppData%\EntraExportRestore\ are preserved across upgrades unless you remove them manually.
For download integrity verification before you run the installer, see section 4.2.
3.1 Install and upgrade modes
The setup executable supports fresh install, in-place upgrade, same-version reinstall (repair), and blocks downgrade to an older semver.
| Mode | When | Behaviour |
|---|---|---|
| Fresh install | No prior entry in Add/Remove Programs | Installs to %ProgramFiles%\Madriam\EntraExportRestore; adds CLI to machine Path |
| Upgrade | Installed version is in the supported range and older than the installer | Prompts for confirmation (interactive) or requires /ALLOWUPGRADE=1 (silent); replaces binaries; retains %AppData%\EntraExportRestore\ |
| Reinstall (repair) | Same semver already registered | Same confirmation rules as upgrade; refreshes installed files |
| Downgrade blocked | A newer semver is already installed | Setup aborts with an error |
Supported upgrade range: 1.0.0 through 1.2.9 (semver segments only; build numbers are not compared).
Running-process checks — Upgrade and reinstall refuse to continue while Entra Export, Entra Restore, or the CLI is running. Interactive setup offers Retry/Cancel; silent setup (/S) aborts with a non-zero exit code.
3.2 Silent installation switches
The following switches apply to the NSIS setup executable. They were introduced in version 1.1.0.
| Switch | Purpose |
|---|---|
/S |
Silent install with no UI. For upgrade or reinstall, you must also pass /ALLOWUPGRADE=1. |
/ALLOWUPGRADE=1 |
Required for silent upgrade or same-version reinstall. Without it, silent setup fails when a prior version is registered. |
/D=... |
Optional install directory on fresh install only. Must be the last argument on the command line. |
Examples:
EntraExportRestore-1.1.0-Setup-x64.exe /S
EntraExportRestore-1.1.0-Setup-x64.exe /S /ALLOWUPGRADE=1
Uninstall — Run Uninstall.exe /S from the install folder for silent removal. Uninstall removes program files but does not delete user settings under %AppData%\EntraExportRestore\.
Install log: %ProgramData%\Madriam\EntraExportRestore\install.log
Upgrade checklist. Close all Entra Export, Entra Restore, and CLI sessions; run the installer (or deploy silently with /S /ALLOWUPGRADE=1); open the apps or CLI so existing SQLite databases upgrade on first use; run EntraExportRestore snapshots after the next export to confirm application version stamps.
4. Applications and database
| Component | Role |
|---|---|
| EntraExportUI | Interactive export: sign in, configure catalog selections, filters, and run exports into the local database. |
| EntraRestoreUI | Interactive restore against a chosen snapshot, subject to catalog rules and sensitive-attribute confirmation. |
| EntraExportRestore CLI | Scripted export and restore using your tenant’s app registration, a client certificate, and application permissions (not delegated). permissions lists required Graph read permission names from the embedded catalog without signing in to Microsoft. Same database and engines as the UIs. See section 12 for full command reference. |
| SQLite database | Default file name entra-export-restore.db (path may vary by host configuration). Holds snapshots, captured objects, and attribute values. |
4.1 Supported platforms and host requirements
EntraExportRestore is a Windows product. Distribution packages are built for 64-bit Windows (win-x64) and include a self-contained .NET 8 runtime unless your distributor ships a framework-dependent build. The product does not pin a specific Windows 10 or Windows 11 feature update; host requirements follow .NET 8 and WPF platform support (broadly Windows 10 version 1607 and later, and Windows Server 2016 and later on supported SKUs).
| Host environment | EntraExportUI / EntraRestoreUI | CLI | Notes |
|---|---|---|---|
| Windows client (Windows 10 / 11) | Supported | Supported | Interactive sign-in for the desktop apps uses the system browser. CLI automation uses a client certificate in the Windows Personal (My) certificate store. |
| Windows Server with Desktop Experience | Supported | Supported | Suitable for an administrator jump box or admin server with a GUI. Same certificate-store and config paths as client Windows (%AppData%\EntraExportRestore). |
| Windows Server Core (no GUI) | Not supported | Supported | WPF requires a desktop shell. The CLI is a console application and is the intended path for scheduled tasks on headless servers when you import the service-principal certificate into LocalMachine\My (or CurrentUser\My). |
| Linux / macOS | Not supported | Not supported | CLI certificate authentication relies on the Windows certificate store; unattended automation is designed for Windows scheduled tasks. |
| 32-bit Windows or Windows on ARM | Not in default package | Not in default package | Standard distribution targets win-x64 only. Other CPU architectures require a rebuild with a different runtime identifier. |
Runtime and dependencies. Desktop applications target net8.0-windows with WPF and therefore require Windows with a GUI stack. The CLI targets .NET 8 and, for Graph access, a certificate in the Windows store—there is no device-code or client-secret sign-in path. SQLite snapshots use a native Windows x64 library bundled with the published package. Outbound HTTPS to Microsoft Entra ID and Microsoft Graph is required on every host.
Choosing a host. Use a Windows workstation or GUI-enabled admin server for interactive export and restore. Use Windows Server Core (or any Windows host without a GUI) only for unattended CLI jobs, with your own app registration, application permissions, and a certificate installed for the account that runs the task.
4.2 Verifying distribution downloads
Official builds are published with a SHA-256 checksum file so you can confirm that a ZIP or installer was not altered in transit. The file is named EntraExportRestore-{version}-CHECKSUMS.txt and is provided on the same download page as the packages (or included in your distribution media). Each line lists a lowercase hex hash followed by the file name, for example:
a1b2c3d4e5f6... EntraExportRestore-1.0.0-Setup-x64.exe
Windows PowerShell. After downloading, compare the hash of the file on disk to the value in the checksum file:
# Replace paths and expected hash from your CHECKSUMS.txt
$expected = "paste-expected-sha256-from-checksums-file"
$actual = (Get-FileHash -Algorithm SHA256 -LiteralPath "C:\Downloads\EntraExportRestore-1.0.0-Setup-x64.exe").Hash.ToLowerInvariant()
if ($actual -eq $expected) { "SHA-256 match" } else { "SHA-256 mismatch" }
Windows Command Prompt (built-in on recent Windows 10/11):
certutil -hashfile "C:\Downloads\EntraExportRestore-1.0.0-Setup-x64.exe" SHA256
Compare the output (ignore spaces and letter case) to the checksum file. Lines beginning with # in the checksum file are comments.
Authenticode. The Windows installer and binaries are also Authenticode-signed by the publisher. Right-click the .exe → Properties → Digital Signatures to view the signature. Checksum verification and code signing answer different questions: checksums detect any bit change in the file; signatures prove publisher identity when the certificate chain is trusted.
5. Licensing
Each host checks a valid product licence before the UI or CLI runs. If verification fails, the application exits with an error message.
Default licence file path: %AppData%\EntraExportRestore\licence.json (the signed-in user’s AppData folder). Place your issued licence file there unless you override the location.
Overrides (CLI checks these in order after the command line; desktop apps use the default path and environment variable only):
- CLI:
--licence <path> - Environment variable:
ENTRAEXPORTRESTORE_LICENCE_PATH— full path to the licence file - Config file:
LicencePathin%AppData%\EntraExportRestore\config.json(see section 12 for CLI config precedence)
6. Madriam-supplied app vs. your own tenant (security)
EntraExportRestore uses Microsoft Entra ID and Microsoft Graph. You will authenticate with an application registration—either one supplied by Madriam (multi-tenant) or one you create and configure in your own tenant (single-tenant, “self-supplied”). The choice affects who controls the app identity and what your organisation must trust.
Which should you use? For the desktop export and restore applications, either model can work. Many organisations choose Madriam’s multi-tenant app when they want the fastest path to interactive use—admin consent and sign-in, without creating certificates or maintaining a dedicated app registration. Others register the application in their own tenant when policy requires full control of the Client ID, redirect URIs, and permission set. Unattended automation via the CLI always requires your own registration (see section 6.3).
6.1 Madriam-supplied multi-tenant application
Madriam’s app is the default path for EntraExportUI and EntraRestoreUI. It is a practical choice when you want to minimise Entra administration before running backups: you consent to a known, published application, users sign in interactively, and the tool uses delegated permissions so access is limited to what each signed-in user could do in the directory. You do not need to issue client certificates, grant broad application permissions, or operate a separate app registration lifecycle for desktop use—overhead that matters for scripted CLI work but is often unnecessary when administrators export and restore on demand.
This path suits pilots, smaller teams, or any environment where third-party app consent is acceptable under your security policy. You still accept trust in Madriam as the app publisher; the points below describe what that trust means in practice.
When a customer consents to Madriam’s multi-tenant app, they are trusting that:
- The Client ID will not be misused. The app registration lives in Madriam’s tenant. Madriam controls redirect URIs, requested permissions, and overall app behaviour. In theory, a compromised registration could reuse that same Client ID in different software to obtain tokens for customers who have already consented.
- Madriam’s tenant stays secure. If Madriam’s Azure tenant is compromised and an attacker gains control of the app registration, they could abuse the trust relationship with customer tenants that consented.
- Permissions will not expand without notice. If Madriam adds new permissions to the registration, customers normally see a new consent prompt when the app requests those scopes—you cannot silently widen access without a new consent event. (What actually gets requested at runtime still depends on the software you run.)
6.2 Self-supplied application in your tenant
When you register the application yourself:
- You control the Client ID and configuration—redirect URIs, certificates or secrets, and API permissions are under your administrators’ governance.
- Trust shifts to your own change management—you are not depending on a third-party tenant to protect the registration, but you must operate it securely.
- Consent is internal—typically only users in your tenant (or guests you allow) interact with your registration; you align permissions with your security standards.
Organizations with strict third-party risk programs often prefer a self-supplied registration for tools that access directory data, even when the software binaries come from Madriam.
6.3 CLI vs. desktop UI (app registration and permissions)
Key rule for CLI use. The export and restore commands require your own app registration in your tenant, configured with a client certificate and Application (not delegated) permissions with admin consent. You cannot use Madriam’s multi-tenant app registration for this purpose.
Desktop apps (EntraExportUI and EntraRestoreUI) are designed for interactive sign-in. They can use Madriam’s multi-tenant application: after your organisation consents, that app appears as an Enterprise application in your tenant. Sign-in uses delegated permissions—the tool acts in the context of the signed-in user, within that user’s directory rights. No client certificate is required for this path.
The CLI is designed for unattended and scripted use. It authenticates using the client credentials flow with a client certificate you install on the host. Certificate credentials must be configured on an app registration your organisation controls—you upload the public key in Entra and hold the private key locally. You cannot assign your certificate to Madriam’s application registration, which lives in Madriam’s directory; your tenant’s Enterprise application entry for a consented Madriam app is a service principal, not an app registration you can extend with your own certificate for this automation pattern. Therefore the CLI requires you to create and use your own app registration (single-tenant / tenant-owned).
On that registration, configure Application permissions (for example User.Read.All as type Application) and Grant admin consent. Delegated permissions are not suitable: they require an interactive signed-in user, and the CLI does not implement an interactive delegated sign-in path. Application permissions keep scheduled jobs and automation non-interactive.
The CLI permissions command lists the read permission names that match your export configuration—use it as a checklist when configuring read access on your app registration. Write permissions needed for CLI restore are not included; consult the catalog attribute definitions and current Microsoft Graph documentation to determine the write permissions your restore scope requires.
6.4 Desktop credential caching
Export UI and Restore UI use the Microsoft Authentication Library (MSAL) with a persistent token cache so administrators are not prompted on every launch when refresh tokens remain valid.
- Location —
%LocalAppData%\Madriam\EntraExportRestore\containsmsal.cache(encrypted token material) andauth-settings.json(custom Client ID and tenant hint only). - Behaviour — The first sign-in for a Windows user profile is interactive (browser). Later sign-in attempts and Graph calls use silent acquisition when possible. If refresh tokens expire or conditional access requires re-authentication, the app falls back to an interactive prompt.
- Shared across apps — EntraExportUI and EntraRestoreUI on the same profile share the same cache file for a given app registration Client ID.
- Sign out — Removes MSAL accounts from the cache for that registration. Use sign out on shared workstations or when rotating delegated access.
- Revocation — Entra administrators can revoke refresh tokens or disable the user or enterprise application in the tenant; the cache cannot override tenant-side revocation.
Credential caching applies to delegated desktop sign-in only. The CLI continues to use certificate-based application permissions and does not read msal.cache. See also release notes 2.1.
7. What Microsoft’s platform protects
OAuth 2.0 and Entra ID’s design limit blast radius in important ways:
- Tokens are tenant-scoped. A token issued for one tenant cannot be used against another; each customer’s data remains behind its own tenant boundary.
- Consent is per tenant. Consent in one customer tenant does not grant access to any other tenant.
- Tokens are time-limited. Access tokens typically expire within roughly 60–90 minutes. Refresh tokens can be revoked by the customer’s administrator.
- Customers can revoke access. An administrator can open Enterprise applications in their tenant, find the service principal for the app, and revoke consent or delete the assignment—cutting off access immediately.
- Delegated vs. application permissions matter. With delegated permissions (interactive or device-code style flows), the token’s power is bounded by the signed-in user’s own directory rights—the app cannot exceed what that user could do interactively.
8. Risk profile for this tool
Desktop UI (interactive). EntraExportRestore’s export and restore UIs are intended to use delegated permissions with interactive sign-in—often via Madriam’s multi-tenant Enterprise application after consent. In that mode, risk is relatively contained:
- The tool acts on behalf of users who actively sign in—there is no Madriam-operated background service in the product model described here.
- The interactive UI path does not use application-only permissions that would imply unattended directory access without a user.
- The customer’s IT administrators control who may sign in and who may consent.
CLI (certificate / application permissions). When you use export or restore with your own app registration and certificate, the service principal can access directory data under application permissions with admin consent, without a user present. That is appropriate for automation but is a higher-privilege pattern than interactive delegated use: protect the certificate, restrict who can run the CLI, and review granted application permissions regularly.
The main residual risk for the UI path is reputational trust: the organisation relies on Madriam’s integrity and on the software behaving as described—the same class of trust as for many third-party tools, though this product runs on-premises and does not require Madriam to hold your tokens on a shared cloud service.
Bottom line. The multi-tenant consent model is mature and widely used. Interactive delegated use is bounded by the signed-in user. Application-permission CLI use is powerful by design; scope it deliberately with your own registration and least-privilege Graph roles.
9. Building Trust
Trusting any third-party application is a risk. Madriam hopes to earn your trust by:
- Publishing the Client ID and exact API permission list so customers can verify the consent screen before approving.
- Requesting only the permissions the product truly needs—for example, preferring narrower directory read scopes over broad read/write where possible.
- Consider Microsoft Verified Publisher. Verification shows your company name on the consent screen and often increases customer confidence.
10. Object types, contacts, and devices
The catalog covers Entra object types such as users, groups, devices, organisational contacts, named locations, and Conditional Access policies. Not every captured attribute can be written back; the catalog marks each attribute as restorable or capture-only.
Contacts are read-only in Microsoft Graph for the scenarios this tool targets. EntraExportRestore can still back up contact attributes for documentation and comparison, but those backups are provided exclusively for reference during a manual restoration procedure (for example, recreating or correcting data outside this tool). Do not rely on automated restore for contacts.
Device attribute writes in Graph depend on permissions that are exposed as application permissions (for example Device.ReadWrite.All) rather than an equivalent delegated device write scope suitable for ordinary interactive user sign-in. For that reason, the restore UI intentionally excludes device restore, while the CLI restore path can be used when your deployment is configured for the permission model your administrator approves. Plan device recovery with the CLI if automated device write-back is required; validate results in your environment.
These object types are opt-in in the catalog (not part of the default recommended export). Restore requires Policy.Read.All and Policy.ReadWrite.ConditionalAccess, and an Entra role such as Conditional Access Administrator or Security Administrator. Changes can block or allow sign-in; the restore preview prompts for confirmation.
Object and attribute scope. Export and restore work at two levels: select the Named Location and/or Conditional Access policy object types, then choose attributes. Scalar attributes such as displayName and state support labelling and OData export filters; the restorable payloads are the document attributes locationDocument and policyDocument, which capture the full Graph resource (IP ranges, countries, policy conditions, grant controls, and session controls).
By default, restore updates existing policies and named locations (matched by Graph id, with display-name resolution when an object was recreated with a new id). To recreate missing objects, enable Recreate missing named locations and policies in the restore preview window, or pass --create-missing on the CLI (or set allowCreateMissingObjects in config.json). Named locations are restored before policies; named-location IDs referenced in policies are remapped within the same tenant. User, group, role, and application IDs inside policy conditions are not remapped.
Restore preview and difference reports show human-readable summaries for document attributes (for example display name, state, included locations, and grant controls) rather than raw JSON.
10.1 Mail and proxy addresses (Graph read-only vs. Exchange)
Users. Microsoft Graph documents the proxyAddresses collection on user objects as read-only; you cannot update that collection through Graph (Microsoft documents using tools such as the Microsoft 365 admin center for mailbox / proxy address management). The catalog still includes proxyAddresses for export and comparison, but it is not restorable through this product. By contrast, the mail property on users can often be updated via Graph’s Update user API (with documented caveats); see the catalog’s restorable flag for mail and current Microsoft documentation.
Groups. Microsoft Graph documents mail and proxyAddresses on group objects as read-only. The catalog lists them for export only; they are not restorable here because Graph does not support updating them with the same PATCH-style updates used for writable directory attributes.
In practice, changing a recipient’s primary SMTP address, secondary addresses, or full proxy address set for mail-enabled users or groups is usually done with Microsoft Exchange administrator tools—for example the Exchange admin center or Exchange Online PowerShell—or, for directory-synchronised objects, in on-premises Active Directory as your identity design requires. Use snapshot values as a reference when reconciling or rebuilding that configuration outside this tool.
Other attributes (such as group mailNickname where Graph allows updates) may still be restorable according to the catalog; always check each attribute’s restorable flag and current Microsoft documentation.
10.2 Catalog restorability and Microsoft Graph
In this product, restorable means the restore engine can write the value back using the same Microsoft Graph patterns the tool implements today—primarily property updates on the directory object where Graph documents those properties on Update user, Update group, or Update device, plus a small set of documented exceptions (for example, group members and owners via membership $ref APIs, and user assigned licences via the assignLicense action rather than PATCH on the user).
Attributes are marked capture-only (not restorable) when Graph does not support updating them through those paths, when they require a different API the tool does not call, or when they are effectively creation-time or platform-managed for your scenario. Examples called out in the embedded catalog include:
- Licences. User
assignedLicensesis restorable when explicitly selected: restore calls Graph assignLicense so the live assignments match the snapshot (SKU adds/removes and disabled service plans). It is marked sensitive—confirm before restore. Adding paid SKUs typically requires a validusageLocationon the user; Graph may reject the operation if prerequisites are not met. - Manager. The manager relationship is updated through Graph’s manager navigation endpoint, not as a scalar on Update user in the way this restore path applies.
- Some group and user properties. Properties that appear on objects for read or hybrid scenarios but are not listed as updatable on the Update group or Update user reference—for example certain
mailEnabled/groupTypes-style surface areas,onPremises*identifiers where Graph treats them as read-only, orprofileTypeon devices—remain in the catalog for export and auditing but are not written by restore.
You can export capture-only attributes by selecting them explicitly in the Export app (they are not part of the Default recommended set). Restore will skip them—the Restore app does not let you select capture-only attributes for write-back. Use snapshot values as a reference if you need to reconcile those values in Exchange, licence tools, or other administrators’ workflows.
Microsoft changes Graph over time. Validate behaviour against the Microsoft Graph API documentation for your tenant and object types.
11. Typical workflows
- Prepare Entra ID. For the desktop apps, use Madriam’s Enterprise application (or your policy) with delegated permissions and interactive sign-in. For the CLI, create your own app registration, add a certificate credential, grant application permissions (not delegated—the CLI does not perform interactive user sign-in), and admin consent. Use the CLI
permissionscommand or in-product permission summaries as a checklist. - Export. Sign in, select object types and attributes (and optional filters), then run an export. Record the snapshot identifier if you need it later.
- Restore. Choose a snapshot, run Restore Preview to compare backup values with live Graph, optionally Export report… (HTML, JSON, or CSV) for audit or manual reconciliation, then run restore when ready. Confirm sensitive operations if prompted. Review operation results for skipped or failed attributes.
- Catalog version. Snapshots record the catalog version in use at export time. If the product catalog has changed since the snapshot, you may see warnings—review attribute definitions before relying on restore behaviour.
12. Command-line reference
After a successful licence check, the CLI accepts one of the following forms:
EntraExportRestore permissions
EntraExportRestore permissions restore
EntraExportRestore snapshots [--format text|json]
EntraExportRestore export
EntraExportRestore export --output-json C:\backup\last-export.json
EntraExportRestore restore preview <snapshotId> [--format text|json|csv|html] [--output <path>] [--filter all|differences|restorable]
EntraExportRestore restore preview <snapshotId> --format html --output C:\reports\diff.html
EntraExportRestore restore <snapshotId> [--force]
EntraExportRestore --licence <path> export
| Command | Description |
|---|---|
permissions |
Prints required read permission names as application permissions for certificate-based CLI use, matching the export defined in config.json (or catalog defaults if no selection is saved). Embedded catalog only—no Microsoft Entra sign-in (licence still validated). |
permissions restore |
Prints required write permission names for restore scope, plus read permissions used by restore preview/live comparison, based on RestoreSelectionByObjectType in config.json (or restore defaults when no restore selection is saved). Embedded catalog only—no Microsoft Entra sign-in (licence still validated). |
snapshots [--format text|json] |
Lists snapshots from the configured SQLite database so automation can discover snapshot GUIDs without querying the database directly. |
export [--output-json <path>] |
Runs an export using the same object types and attribute selection as the Export desktop app (config.json), or catalog defaults when no selection is stored; prints snapshot ID and counts when finished. With --output-json, writes a structured result file and suppresses informational stdout (see exit codes). |
restore preview <snapshotId> [--format text|json|csv|html] [--output <path>] [--filter all|differences|restorable] [--include-raw-values] |
Builds restore preview by comparing snapshot values with live directory values, then prints summary text, writes a structured JSON report, or exports CSV/HTML to --output. JSON to stdout uses the structured report document (see 2.1). This command does not write changes to Microsoft Entra. |
restore <snapshotId> [--force] [--create-missing] |
Restores attributes for the given snapshot GUID using restore scope from RestoreSelectionByObjectType in config.json (or restore defaults when empty). Sensitive values that differ from the directory require confirmation; the confirmation can be suppressed by supplying --force for unattended runs. --create-missing (or allowCreateMissingObjects in config) allows POST of missing named locations and Conditional Access policies. |
CLI restore scope. Restore scope is driven by RestoreSelectionByObjectType in shared config.json. This enables scripted, attribute-scoped restore workflows using the same database and engines as the desktop apps.
Exit codes
Automation and scheduled tasks should check the process exit code. The CLI also prints this table from --help.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Usage error (invalid arguments or unknown command) |
2 |
Licence verification failed |
3 |
Configuration error (missing certificate settings, invalid Graph URL, etc.) |
4 |
Authentication failed (certificate or Microsoft Graph sign-in) |
5 |
Export failed |
6 |
Restore failed or was cancelled before completion |
7 |
Restore finished but one or more attribute writes failed |
After a successful export (exit code 0), the snapshot is committed to SQLite and the process releases the database connection—suitable for copying the database file to encrypted or immutable storage in a follow-on step.
Export result JSON (--output-json)
Pass --output-json <path> with export to write a JSON result file when the export completes. Informational stdout is suppressed automatically for that run; export progress remains on stderr. Use --quiet to suppress informational stdout for other commands.
Example:
EntraExportRestore --client-id <appId> --tenant-id <tenantId> --client-certificate-thumbprint <thumbprint> export --output-json C:\backup\last-export.json
Successful export JSON:
{
"status": "completed",
"snapshotId": "11111111-2222-3333-4444-555555555555",
"databasePath": "C:\\Users\\you\\AppData\\Roaming\\EntraExportRestore\\entra-export-restore.db",
"totalObjectsExported": 1200,
"totalAttributeValuesExported": 48000,
"completedAt": "2026-06-10T14:30:00Z"
}
On failure, status is failed, errorMessage describes the error, and count/snapshot fields are omitted. The process exit code is 5.
The CLI permission lists use the same Graph names you add in Entra (for example User.Read.All) as Application permissions. Use permissions for export-read requirements, and permissions restore for restore-write plus preview-read requirements.
Contacts remain capture-only in the current catalog (IsRestorable=false), so restore will skip contact attributes even when contact keys are present in config. Device restore is supported in CLI workflows when application permissions (for example Device.ReadWrite.All) are granted.
Optional argument: --licence <path> overrides the default licence path (%AppData%\EntraExportRestore\licence.json). You can also set ENTRAEXPORTRESTORE_LICENCE_PATH or LicencePath in config; see section 5.
CLI sign-in (service principal + certificate)
The CLI export and restore commands require your own app registration in your tenant (see section 6.3): Microsoft Graph application permissions only—not delegated permissions, because delegated flows require interactive user authentication, which the CLI does not provide. Grant admin consent on the application permissions, and configure a certificate credential on that registration (no client secret; device code is not supported). Upload the public certificate in Entra; import the certificate (with private key) into the Windows Personal (My) store on the machine running the task—typically LocalMachine\My for a service account.
Pass all of the following (or set the equivalent environment variables):
--client-id/ENTRAEXPORTRESTORE_CLIENT_ID--tenant-id/ENTRAEXPORTRESTORE_TENANT_ID--client-certificate-thumbprint <thumbprint>/ENTRAEXPORTRESTORE_CLIENT_CERTIFICATE_THUMBPRINT- Optional:
--client-certificate-store LocalMachine(default) orCurrentUser/ENTRAEXPORTRESTORE_CLIENT_CERTIFICATE_STORE
EntraExportRestore --client-id <appId> --tenant-id <tenantId> --client-certificate-thumbprint <thumbprint> --client-certificate-store LocalMachine export
Configuration file. The CLI shares %AppData%\EntraExportRestore\config.json with the desktop apps. Override the path with --config <file-or-folder> (a folder is treated as containing config.json).
Database. The connection is derived from BackupDatabasePath in the config file, resolved the same way as the UIs. Override it entirely with --sqlite-connection <s> or ENTRAEXPORTRESTORE_SQLITE_CONNECTION_STRING; those take precedence over the config-file path.
Supported config-file keys (used by the CLI when not set on the command line or via environment variable): LicencePath, ClientId, TenantId, ClientCertificateThumbprint, ClientCertificateStore, GraphBaseUrl, ExportSelectionByObjectType, RestoreSelectionByObjectType, ExportFiltersByObjectType, RestorePreviewMaxConcurrency, RestorePreviewDisplayPropertyByObjectType, SnapshotRetentionMaxCount, SnapshotRetentionMaxAgeDays. Precedence order: command-line argument → environment variable → config file.
Automation switches: --output-json <path> (export only; see export result JSON), --output <path> (restore preview CSV/HTML/JSON file export), --quiet (suppress informational stdout).
13. Use cases and protecting snapshots at rest
This section describes how EntraExportRestore was envisioned to play a modest, supporting role in several identity-protection scenarios, and how to harden the snapshots it produces. EntraExportRestore is not a security platform, a SIEM, or a whole-tenant disaster-recovery appliance. It captures selected attributes of selected object types as point-in-time snapshots (see section 1). In the scenarios below it is one supporting instrument among the controls your organisation already operates—useful precisely because its snapshots can document and selectively reverse changes to the attributes you chose to capture.
Reality check. A snapshot is only as trustworthy as the storage that holds it. If snapshots live inside the same blast radius as the directory and credentials being protected, a malicious or compromised administrator could alter or delete them. The hardening guidance in 13.2 and 13.3 is therefore central to—not optional for—the use cases in 13.1.
13.1 Envisioned use cases
Each scenario below assumes you have been taking regular, scoped exports before the event, so a known-good reference exists.
- Malicious or compromised admin activity. A snapshot taken before an incident provides a known-good reference for the attributes you capture. You can compare current directory values against the snapshot (for example with
restore preview) and selectively reverse unauthorised changes to in-scope, restorable attributes, rather than guessing what was altered. - Post-incident reconstruction. After a breach or accidental bulk change, snapshots help you reconstruct what selected attributes looked like at a known point in time and reapply known-good values where Microsoft Graph allows write-back, leaving capture-only attributes as documented reference for manual reconciliation (see section 10.2).
- Identity recovery sequencing. Because restore scope is attribute- and object-type-driven (
RestoreSelectionByObjectType), you can stage recovery deliberately—for example, restoring foundational user attributes before group memberships or licence assignments—running discrete CLI restore steps in a controlled order rather than a single all-at-once operation. - Audit and compliance evidence. Versioned snapshots, each stamped with catalog and application version and export timestamp, can serve as point-in-time documentation of the directory state for the attributes you track—useful as supporting evidence during audits, change reviews, or investigations. Exported difference reports (HTML, JSON, CSV) from restore preview document backup-vs-live comparisons for retention outside the SQLite database.
In every case the tool’s contribution is bounded by what you exported: it covers your selected attributes on User, Group, Device, Contact, Named Location, and Conditional Access policy objects, not the entire tenant, and capture-only attributes are reference material rather than automated restore targets.
13.2 Encryption at rest (storage level)
EntraExportRestore stores snapshots in a local SQLite database and does not encrypt that database itself. If you are deploying the tool in support of any of the use cases above, you are encouraged to provide encryption at rest at the storage level, so that snapshot contents are protected if the database file or its backups are lost or copied. Options your organisation may already operate include:
- BitLocker on the admin workstation/server hosting the database and any local copies.
- Encrypted enterprise backup storage for any backup or archive that includes the database file.
- Azure Storage encryption when the database or its copies are kept in Azure (for example in a storage account or file share).
- Encrypted replication target when the database is replicated to another host, site, or cloud location.
These are storage-layer controls deployed and managed by the customer; EntraExportRestore does not configure them. Point the database at an encrypted location using BackupDatabasePath in config.json or the --sqlite-connection override (see section 13.4).
13.3 Immutability (storage level)
Encryption protects confidentiality, but the use cases in 13.1 also depend on snapshots being tamper-resistant: a compromised administrator who can edit or delete your snapshots can undermine both reconstruction and audit value. Immutability is likewise introduced at the storage level, typically by copying or replicating each committed snapshot database to write-once / protected storage. Options include:
- Azure Blob immutable storage (time-based or legal-hold WORM policies).
- AWS S3 Object Lock (governance or compliance retention).
- Immutable backup appliance with hardened/locked retention.
- WORM-capable NAS (write-once, read-many volumes or shares).
- Enterprise backup vault with immutability and deletion protection.
- Separate tenant / subscription / account so the snapshot store sits in a different trust and identity boundary from the directory being protected.
- Offline or air-gapped copies that cannot be reached or altered from the production environment.
For the malicious/compromised-admin and audit-evidence scenarios in particular, combine immutability with separation of duties: store snapshots under credentials and in an account/subscription/tenant that the administrators of the protected directory cannot modify. Otherwise the same actor who can change the directory can also rewrite the evidence and the recovery baseline.
13.4 Leveraging the CLI for hardened workflows
The command-line tool (section 12) is the building block for unattended, hardened snapshot workflows. The relevant capabilities are:
- Scheduled exports. Run
exportas a scheduled task (Windows Task Scheduler or your orchestrator) under a dedicated service account so fresh snapshots are produced on a regular cadence before any incident. - Encrypted database location. Point the database at storage you have encrypted at rest using
BackupDatabasePathinconfig.jsonor the--sqlite-connection "Data Source=..."override—for example a BitLocker-protected volume or an encrypted file share. - Deterministic completion for copy/replication. Exit code
0means the snapshot is committed and the SQLite connection has been released, so a follow-on step can safely copy or replicate the database file to immutable or off-host storage (see exit codes). - Machine-readable result.
export --output-json <path>writes the committeddatabasePath,snapshotId, counts, andcompletedAt, so the copy/replication step knows exactly which file to push to your WORM target (see export result JSON). - Read-only verification during recovery.
snapshotsandrestore preview <snapshotId>let recovery and audit work inspect snapshots and compare them with live values without writing changes to Microsoft Entra. - Scoped, sequenced restore.
restore <snapshotId>honoursRestoreSelectionByObjectType, enabling the staged, attribute-scoped recovery described in 13.1; use--forceonly for vetted unattended runs.
A typical hardened pipeline exports to encrypted storage and then pushes the committed, immutable copy to a separate boundary:
# 1) Export a fresh snapshot to a database on encrypted-at-rest storage (e.g. BitLocker volume)
EntraExportRestore --client-id <appId> --tenant-id <tenantId> `
--client-certificate-thumbprint <thumbprint> `
--sqlite-connection "Data Source=D:\Encrypted\entra-export-restore.db" `
export --output-json "D:\Encrypted\last-export.json"
# 2) Only on success (exit code 0) is the snapshot committed and the database handle released
if ($LASTEXITCODE -eq 0) {
$result = Get-Content "D:\Encrypted\last-export.json" | ConvertFrom-Json
# 3) Copy/replicate the committed database to immutable, write-once storage in a
# separate trust boundary (Azure immutable blob, AWS S3 Object Lock, WORM NAS,
# separate account/subscription/tenant, or an offline/air-gapped copy).
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
Copy-Item $result.databasePath "\\worm-nas\entra-snapshots\entra-$stamp.db"
}
Encryption at rest and immutability are customer-deployed storage controls; EntraExportRestore neither configures nor depends on a specific provider. The CLI’s role is to produce committed, well-identified snapshots and to signal completion cleanly so your existing encryption, replication, and immutability tooling can take it from there.