XRT.PowerApps.CLI 1.6.3

dotnet tool install --global XRT.PowerApps.CLI --version 1.6.3
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local XRT.PowerApps.CLI --version 1.6.3
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=XRT.PowerApps.CLI&version=1.6.3
                    
nuke :add-package XRT.PowerApps.CLI --version 1.6.3
                    

PowerApps.CLI

Note: This project was developed with assistance from Claude Sonnet 4.5 (Anthropic AI).

A .NET command-line tool for extracting and exporting metadata schema from Microsoft Power Platform / Dynamics 365 environments.

Features

Schema Extraction

  • ๐Ÿ” Metadata Export - Extract entity, attribute, and relationship metadata from Dataverse environments
  • ๐ŸŽฏ Solution Filtering - Filter by one or multiple solutions (comma-separated)
  • ๐Ÿ“Š Multiple Export Formats:
    • JSON - Complete schema with full metadata
    • XLSX - Excel workbook with filterable tables and interactive navigation
  • โœ… Audit Information - Includes audit enablement status at entity and attribute levels

Constants Generation

  • ๐ŸŽจ C# Constants - Generate strongly-typed C# constants from Dataverse metadata
  • ๐Ÿ“‹ Tables & Choices - Modern terminology (Tables instead of Entities, Choices instead of OptionSets)
  • ๐Ÿ—‚๏ธ Flexible Output:
    • Single file mode: Tables.cs and Choices.cs
    • Multiple files mode: Tables/.cs and Choices/.cs
  • ๐ŸŽฏ Smart Filtering:
    • Solution-based filtering
    • Entity exclusions
    • Attribute exclusions
    • Prefix-based filtering
  • ๐Ÿ“ Rich Documentation - XML comments and metadata comments in generated code

Reference Data Comparison

  • ๐Ÿ”„ Environment Comparison - Compare reference data tables between source and target environments
  • ๐Ÿ“Š Difference Detection - Identifies new, modified, and deleted records
  • ๐ŸŽฏ Bidirectional Analysis - Compares both ways to find orphaned records

Reference Data Migration

  • ๐Ÿš€ Environment-to-Environment Migration - Migrate reference data from source to target Dataverse environment
  • ๐Ÿ”„ Diff Mode - Only pushes records that have changed (default), with --force to push all
  • ๐Ÿ”— Multi-pass Strategy - Handles self-referential lookups via a two-pass upsert approach
  • โš™๏ธ State Management - Optionally sync record active/inactive state
  • ๐Ÿ”— N:N Relationships - Sync many-to-many relationship associations and disassociations
  • ๐Ÿงช Dry Run Mode - Preview all changes without writing to the target environment
  • ๐Ÿ“Š Excel Reporting - Summary and error report of all migration actions

Process Management

  • โš™๏ธ Process State Control - Activate/deactivate workflows, cloud flows, business rules, actions, business process flows, and duplicate detection rules
  • ๐ŸŽฏ Pattern-based Rules - Use wildcard patterns to define which processes should be inactive
  • ๐Ÿ”„ CI/CD Ready - Run post-deployment to ensure processes are in the correct state
  • ๐Ÿงช Dry Run Mode - Preview changes without modifying any process states
  • ๐Ÿ“Š Excel Reporting - Summary and detailed Excel report of all actions taken

Data Patch

  • ๐Ÿฉน Targeted Record Updates - Apply field-level updates to specific Dataverse records by key lookup
  • ๐Ÿ“ Config File or Inline JSON - Supply config from a file (--config) or as a JSON blob (--config-json) for pipeline use
  • ๐Ÿ” Pipeline-friendly - Designed for Key Vault integration: retrieve a JSON secret and pipe it directly to the command
  • ๐Ÿ” Skip-if-unchanged - Reads the current value first; skips the update if it is already correct
  • ๐Ÿ“Š Excel Reporting - Per-patch outcome report: Updated / Unchanged / Not Found / Error

Solution Layer Analysis

  • ๐Ÿ” Unmanaged Layer Detection - Identifies solution components where an unmanaged layer sits above the managed solution layer, preventing deployment changes from taking effect
  • ๐Ÿ“Š Excel Report - Summary and detail sheets listing affected components by type and name with full layer stack
  • ๐Ÿš€ Post-deployment Use - Run after a solution import to confirm changes will take effect

Installation

Prerequisites

  • .NET 8.0 SDK or later
  • Access to a Power Platform / Dynamics 365 environment

Build from Source

git clone https://github.com/yourusername/PowerApps.CLI.git
cd PowerApps.CLI
dotnet build -c Release

Usage

Schema Export

Extract metadata schema from Dataverse environments.

After building or downloading a release, run directly:

# Windows
.\powerapps-cli.exe schema-export --url "https://yourorg.crm.dynamics.com" --output "schema.xlsx"

# Linux/macOS
./powerapps-cli schema-export --url "https://yourorg.crm.dynamics.com" --output "schema.xlsx"
Using dotnet run (Development)

When developing or if you prefer to run from source:

dotnet run --project src/PowerApps.CLI -- schema-export --url "https://yourorg.crm.dynamics.com" --output "schema.xlsx"
With Service Principal Authentication
powerapps-cli schema-export \
  --url "https://yourorg.crm.dynamics.com" \
  --client-id "your-client-id" \
  --client-secret "your-client-secret" \
  --solution "YourSolution" \
  --output "schema.xlsx" \
  --format xlsx
Multiple Solutions
powerapps-cli schema-export \
  --url "https://yourorg.crm.dynamics.com" \
  --solution "Solution1,Solution2,Solution3" \
  --output "multi-solution-schema.json" \
  --format json

Constants Generation

Generate C# constants from Dataverse metadata.

Basic Usage
powerapps-cli constants-generate \
  --url "https://yourorg.crm.dynamics.com" \
  --solution "YourSolution" \
  --namespace "MyCompany.Model" \
  --output "./Generated"
Using Connection String
powerapps-cli constants-generate \
  --connection-string "AuthType=ClientSecret;Url=https://yourorg.crm.dynamics.com;ClientId=...;ClientSecret=..." \
  --solution "YourSolution" \
  --namespace "MyCompany.Model" \
  --output "./Generated"
Single File Mode
powerapps-cli constants-generate \
  --url "https://yourorg.crm.dynamics.com" \
  --solution "YourSolution" \
  --namespace "MyCompany.Model" \
  --output "./Generated" \
  --single-file
With Filtering
powerapps-cli constants-generate \
  --url "https://yourorg.crm.dynamics.com" \
  --solution "YourSolution" \
  --namespace "MyCompany.Model" \
  --output "./Generated" \
  --exclude-entities "systemuser,team" \
  --exclude-attributes "createdon,modifiedon,createdby,modifiedby" \
  --attribute-prefix "rob_"
Using Configuration File
powerapps-cli constants-generate \
  --url "https://yourorg.crm.dynamics.com" \
  --solution "YourSolution" \
  --config "./constants-config.json"

Example configuration file:

{
  "SingleFile": false,
  "IncludeEntities": true,
  "IncludeGlobalOptionSets": true,
  "IncludeComments": true,
  "IncludeRelationships": true,
  "PascalCaseConversion": true,
  "AttributePrefix": "rob_",
  "ExcludeAttributes": ["createdon", "modifiedon", "createdby", "modifiedby"],
  "ExcludeEntities": ["systemuser", "team"]
}

Reference Data Comparison

Compare reference data between source and target environments.

Basic Usage
powerapps-cli refdata-compare \
  --config refdata-config.json \
  --source-url "https://dev.crm.dynamics.com" \
  --target-url "https://test.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET" \
  --output dev-vs-test.xlsx
Using Connection Strings
powerapps-cli refdata-compare \
  --config refdata-config.json \
  --source-connection "$DEV_CONNECTION_STRING" \
  --target-connection "$TEST_CONNECTION_STRING" \
  --output dev-vs-test.xlsx
Example Config File
{
  "excludeSystemFields": true,
  "globalExcludeFields": ["custom_ignorefield"],
  "tables": [
    {
      "logicalName": "rob_category",
      "primaryIdField": "rob_categoryid",
      "primaryNameField": "rob_name",
      "filter": "<filter><condition attribute='statecode' operator='eq' value='0'/></filter>",
      "excludeFields": []
    },
    {
      "logicalName": "rob_priority",
      "primaryIdField": "rob_priorityid",
      "primaryNameField": "rob_priorityname",
      "filter": "<filter><condition attribute='statecode' operator='eq' value='0'/></filter>",
      "excludeFields": ["rob_temporaryfield"],
      "includeFields": []
    },
    {
      "logicalName": "rob_item",
      "includeFields": ["rob_name", "rob_categoryid", "rob_priorityid"]
    }
  ],
  "relationships": [
    {
      "relationshipName": "rob_category_priority",
      "displayName": "Category to Priority",
      "entity1NameField": "rob_name",
      "entity2NameField": "rob_priorityname"
    }
  ]
}

Tip: The relationships config is compatible with refdata-migrate โ€” you can use the same JSON file for both tools. See Shared Config below.

Behaviour:

  • includeFields restricts comparison to only the specified fields (acts as an allowlist per table)
  • excludeFields removes specific fields from comparison
  • Relationship details are resolved automatically via metadata lookup โ€” only relationshipName is required
  • displayName, entity1NameField, entity2NameField are optional overrides for report display

Output: Excel workbook with:

  • Summary sheet showing all tables and relationship difference counts
  • Detail sheets for each table with differences (NEW/MODIFIED/DELETED records)
  • Detail sheets for each N:N relationship with differences (NEW/DELETED associations)
  • Field-level comparison using formatted values (human-readable lookups and option sets)
  • GUIDs resolved to display names for relationship associations

Reference Data Migration

Migrate reference data from a source Dataverse environment to a target environment.

Basic Usage
powerapps-cli refdata-migrate \
  --config refdata-migrate-config.json \
  --source-url "https://dev.crm.dynamics.com" \
  --target-url "https://test.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET" \
  --output migration-report.xlsx
Dry Run (Preview Changes)
powerapps-cli refdata-migrate \
  --config refdata-migrate-config.json \
  --source-url "https://dev.crm.dynamics.com" \
  --target-url "https://test.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET" \
  --dry-run \
  --output migration-preview.xlsx
Using Connection Strings
powerapps-cli refdata-migrate \
  --config refdata-migrate-config.json \
  --source-connection "$DEV_CONNECTION_STRING" \
  --target-connection "$TEST_CONNECTION_STRING" \
  --output migration-report.xlsx
Force Full Sync
powerapps-cli refdata-migrate \
  --config refdata-migrate-config.json \
  --source-connection "$DEV_CONNECTION_STRING" \
  --target-connection "$TEST_CONNECTION_STRING" \
  --force \
  --output migration-report.xlsx
Example Config File
{
  "batchSize": 1000,
  "tables": [
    {
      "logicalName": "rob_category",
      "manageState": true
    },
    {
      "logicalName": "rob_priority",
      "filter": "<filter><condition attribute='statecode' operator='eq' value='0'/></filter>",
      "excludeFields": ["rob_legacycode"],
      "manageState": false
    },
    {
      "logicalName": "rob_item",
      "includeFields": ["rob_name", "rob_categoryid", "rob_priorityid"]
    }
  ],
  "relationships": [
    {
      "relationshipName": "rob_category_priority"
    }
  ]
}

Behaviour:

  • By default, only records that differ from the target are migrated (diff mode)
  • Use --force to push all records regardless of whether they have changed
  • Lookups are applied in a second pass to handle self-referential relationships
  • manageState: true will sync the active/inactive state of records
  • includeFields restricts migration to only the specified fields (system fields always excluded)
  • excludeFields removes specific fields from migration
  • Relationship details are resolved automatically via metadata lookup โ€” only relationshipName is required

Output: Excel report with:

  • Summary sheet showing environment info, totals, and per-table results
  • Errors sheet (if any failures occurred) with table, record ID, phase, and error message

Shared Config

refdata-compare and refdata-migrate share the same config schema. A single JSON file can drive both tools โ€” each tool reads what it needs and silently ignores the rest.

{
  "batchSize": 1000,
  "excludeSystemFields": true,
  "tables": [
    {
      "logicalName": "rob_category",
      "primaryIdField": "rob_categoryid",
      "primaryNameField": "rob_name",
      "filter": "<filter><condition attribute='statecode' operator='eq' value='0'/></filter>",
      "excludeFields": [],
      "includeFields": [],
      "manageState": true
    }
  ],
  "relationships": [
    {
      "relationshipName": "rob_category_priority",
      "displayName": "Category to Priority",
      "entity1NameField": "rob_name",
      "entity2NameField": "rob_priorityname"
    }
  ]
}
Property Compare Migrate
tables[].logicalName โœ“ โœ“
tables[].filter โœ“ โœ“
tables[].excludeFields โœ“ โœ“
tables[].includeFields โœ“ (allowlist) โœ“ (allowlist)
tables[].manageState ignored โœ“
tables[].primaryIdField / primaryNameField / displayName โœ“ ignored
relationships[].relationshipName โœ“ (metadata lookup) โœ“ (metadata lookup)
relationships[].displayName โœ“ (report tab name) โœ“ (report tab name)
relationships[].entity1NameField / entity2NameField โœ“ (display names) ignored
batchSize ignored โœ“
excludeSystemFields / globalExcludeFields โœ“ ignored

Process Management

Manage Dataverse process states (workflows, cloud flows, business rules, actions) to ensure correct activation/deactivation post-deployment.

Basic Usage
powerapps-cli process-manage \
  --config process-config.json \
  --url "https://prod.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET" \
  --output process-report.xlsx
Dry Run (Preview Changes)
powerapps-cli process-manage \
  --config process-config.json \
  --url "https://prod.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET" \
  --dry-run \
  --output process-preview.xlsx
Using Connection String
powerapps-cli process-manage \
  --config process-config.json \
  --connection-string "$PROD_CONNECTION_STRING" \
  --output process-report.xlsx
Example Config File
{
  "solutions": ["Solution1", "Solution2"],
  "inactivePatterns": [
    "ZZ*",
    "Test - *",
    "Specific Process Name"
  ],
  "maxRetries": 3
}

Behavior:

  • Processes matching inactivePatterns are deactivated
  • All other processes are activated
  • Retry logic handles parent-child dependencies
  • Wildcards supported in patterns (* matches any characters)

Output: Excel report with:

  • Summary showing total, activated, deactivated, unchanged, and failed processes
  • Detailed list of all processes with name, type, expected state, actual state, and action taken

Use Case: Run in CI/CD pipelines after deployment to ensure processes are in the correct state.

Data Patch

Apply targeted field-level updates to specific Dataverse records, driven by a config file or inline JSON blob. Designed for post-deployment pipelines where environment-specific values need patching (e.g. Power Pages authentication settings).

From a config file
powerapps-cli data-patch \
  --config patch.json \
  --connection-string "$SIT_CONNECTION_STRING" \
  --output data-patch-report.xlsx
From an inline JSON blob (e.g. from Key Vault in a pipeline)
# Azure DevOps / bash pipeline step
JSON=$(az keyvault secret show --name "data-patch-sit" --vault-name "myvault" --query "value" -o tsv)
powerapps-cli data-patch \
  --config-json "$JSON" \
  --connection-string "$SIT_CONNECTION_STRING" \
  --output data-patch-report.xlsx
Example Config File
{
  "patches": [
    {
      "entity": "mspp_sitesetting",
      "keyField": "mspp_name",
      "key": "Authentication/OpenIdConnect/AzureADB2C/Authority",
      "valueField": "mspp_value",
      "value": "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/B2C_1A_Policy"
    },
    {
      "entity": "mspp_sitesetting",
      "keyField": "mspp_name",
      "key": "Authentication/OpenIdConnect/AzureADB2C/ClientId",
      "valueField": "mspp_value",
      "value": "00000000-0000-0000-0000-000000000000"
    }
  ]
}

Behaviour:

  • Looks up each record by keyField / key; errors if not found or if multiple records match
  • Reads the current valueField value and skips the update if it already matches
  • value supports JSON strings, numbers, and booleans โ€” type is inferred automatically
  • Use "type" for fields that need explicit conversion: "date", "datetime", "guid", "optionset" (wraps in OptionSetValue), "lookup" (value must be { "logicalName": "...", "id": "..." })
  • --config and --config-json are mutually exclusive

Output: Excel report with one row per patch entry showing Entity, Key, Field, Old Value, New Value, and Status (Updated / Unchanged / Not Found / Ambiguous Match / Error).

Pipeline pattern:

1. Install solution
2. Retrieve JSON blob from Key Vault
3. powerapps-cli data-patch --config-json $json --connection-string $conn

One Key Vault secret per target environment, each containing the full JSON for that environment.

Solution Layers

Check for unmanaged layers on a solution's components post-deployment. Unmanaged layers prevent managed solution changes from taking effect.

Basic Usage
powerapps-cli solution-layers \
  --solution "YourSolutionUniqueName" \
  --url "https://yourorg.crm.dynamics.com" \
  --client-id "$CLIENT_ID" \
  --client-secret "$CLIENT_SECRET"
With Connection String
powerapps-cli solution-layers \
  --solution "YourSolutionUniqueName" \
  --connection-string "$PROD_CONNECTION_STRING" \
  --output solution-layers.xlsx

Behaviour:

  • Queries msdyn_componentlayer for all components belonging to the specified solution
  • A component is flagged when the topmost layer is Active (the unmanaged customisations bucket)
  • Reports all affected components with their type, name, and full layer stack

Output: Excel workbook with:

  • Summary sheet showing solution name, environment, date, and count of affected components
  • Unmanaged Layers sheet with Component Type, Component Name, Unmanaged Layer, and full layer stack (bottom to top)
  • Clean result message if no unmanaged layers are found

Pipeline pattern:

1. Install managed solution
2. powerapps-cli solution-layers --solution $solutionName --connection-string $conn
3. Review report โ€” any rows = someone has unmanaged customisations blocking your changes

Command Reference

schema-export

Extracts metadata schema from PowerApps/Dataverse environments.

Options
Option Description Required Default
-u, --url PowerApps environment URL Yes* -
-s, --solution Solution unique name(s) (comma-separated) No All entities
-o, --output Output file path No powerapp-schema.json
-f, --format Output format: json or xlsx No json
-c, --connection-string Dataverse connection string No -
--client-id Azure AD Application Client ID No -
--client-secret Azure AD Application Client Secret No -
-v, --verbose Enable verbose output No false
--attribute-prefix Only include attributes with this prefix No -
--exclude-attributes Comma-separated attribute names to exclude No -

* Either --url or --connection-string must be provided.

constants-generate

Generates C# constants from Dataverse metadata.

Options
Option Description Required Default
-u, --url PowerApps environment URL Yes* -
-s, --solution Solution unique name(s) to filter by No All entities
-o, --output Output directory path No ./Generated
-n, --namespace Root namespace for generated code Yes -
--single-file Generate single Tables.cs and Choices.cs files No false
--config Path to JSON configuration file No -
-c, --connection-string Dataverse connection string No -
--client-id Azure AD Application Client ID No -
--client-secret Azure AD Application Client Secret No -
-v, --verbose Enable verbose output No false
--include-entities Include entity constants (Tables) No true
--include-optionsets Include option set constants (Choices) No true
--exclude-entities Comma-separated entity logical names to exclude No -
--exclude-attributes Comma-separated attribute logical names to exclude No -
--attribute-prefix Only include attributes with this prefix No -
--pascal-case Convert identifiers to PascalCase No true

* Either --url or --connection-string must be provided.

refdata-compare

Compares reference data between source and target Dataverse environments.

Options
Option Description Required Default
--config Path to JSON configuration file Yes -
--source-url Source environment URL Yes* -
--target-url Target environment URL Yes* -
--source-connection Source environment connection string No -
--target-connection Target environment connection string No -
--client-id Azure AD Client ID (for both environments) No -
--client-secret Azure AD Client Secret (for both environments) No -
-o, --output Output Excel file path No refdata-comparison.xlsx
-v, --verbose Enable verbose output No false

* Either --source-url/--target-url or --source-connection/--target-connection must be provided.

refdata-migrate

Migrates reference data from a source to a target Dataverse environment.

Options
Option Description Required Default
--config Path to JSON configuration file Yes -
--source-url Source environment URL Yes* -
--target-url Target environment URL Yes* -
--source-connection Source environment connection string No -
--target-connection Target environment connection string No -
--client-id Azure AD Client ID (for both environments) No -
--client-secret Azure AD Client Secret (for both environments) No -
--dry-run Preview mode โ€” no changes made to target No false
--force Push all records regardless of whether they have changed No false
-o, --output Output Excel report file path No migration-report.xlsx
-v, --verbose Enable verbose output No false

* Either --source-url/--target-url or --source-connection/--target-connection must be provided.

process-manage

Manages Dataverse process states (workflows, cloud flows, business rules, actions).

Options
Option Description Required Default
--config Path to JSON configuration file Yes -
--url Environment URL Yes* -
--connection-string Environment connection string No -
--client-id Azure AD Application Client ID No -
--client-secret Azure AD Application Client Secret No -
--dry-run Preview changes without modifying states No false
-o, --output Output Excel report file path No process-report.xlsx
-v, --verbose Enable verbose output No false

* Either --url or --connection-string must be provided.

solution-layers

Reports unmanaged layers on a solution's components post-deployment.

Options
Option Description Required Default
-s, --solution Unique name of the solution to inspect Yes -
--url, -u Environment URL Yes* -
--connection-string Environment connection string No -
--client-id Azure AD Application Client ID No -
--client-secret Azure AD Application Client Secret No -
-o, --output Output Excel report file path No solution-layers.xlsx
-v, --verbose Enable verbose output No false

* Either --url or --connection-string must be provided.

Output Formats

Schema Export

JSON

Complete schema export with all metadata including:

  • Entity definitions with audit settings
  • Attribute metadata with types, constraints, and audit settings
  • Relationships (1:N and N:N)
  • OptionSets with all options
  • Solution provenance information
XLSX (Excel)

Interactive Excel workbook featuring:

  • Summary Sheet:
    • Environment and solution metadata
    • Filterable table of all entities
    • Clickable hyperlinks to entity detail sheets
  • Entity Detail Sheets: One per entity with:
    • Entity properties and audit settings
    • Filterable table of attributes
  • Attributes Sheet: Complete list of all attributes across all entities
  • Relationships Sheet: All entity relationships

The XLSX export includes:

  • โœ… Excel Tables with filter dropdowns on all data sheets
  • ๐Ÿ”— Interactive Navigation - Click entity names to jump to detail sheets
  • ๐Ÿ“Š Statistics - Entity, attribute, and relationship counts
  • ๐ŸŽจ Professional Formatting - Color-coded headers and styled tables
  • ๐Ÿ” Audit Information - "Is Audit Enabled" columns for entities and attributes

Constants Generation

Multiple Files Mode (Default)

Generated structure:

Generated/
โ”œโ”€โ”€ Tables/
โ”‚   โ”œโ”€โ”€ Account.cs
โ”‚   โ”œโ”€โ”€ Contact.cs
โ”‚   โ””โ”€โ”€ ... (one file per entity)
โ””โ”€โ”€ Choices/
    โ”œโ”€โ”€ AccountType.cs
    โ”œโ”€โ”€ StatusCode.cs
    โ””โ”€โ”€ ... (one file per global option set)

Example generated file:

namespace MyCompany.Model.Tables
{
    /// <summary>
    /// Constants for the Account entity.
    /// </summary>
    public static class Account
    {
        /// <summary>
        /// Logical name of the entity.
        /// </summary>
        public const string EntityLogicalName = "account";

        /// <summary>
        /// Primary ID attribute.
        /// </summary>
        public const string PrimaryIdAttribute = "accountid";

        /// <summary>
        /// name (String) - MaxLength: 160
        /// </summary>
        public const string Name = "name";

        /// <summary>
        /// accountcategorycode (Picklist) - Uses local option set
        /// </summary>
        public const string Category = "accountcategorycode";

        /// <summary>
        /// Category option set values.
        /// </summary>
        public static class CategoryOptions
        {
            /// <summary>
            /// Preferred Customer
            /// </summary>
            public const int PreferredCustomer = 1;

            /// <summary>
            /// Standard
            /// </summary>
            public const int Standard = 2;
        }
    }
}
Single File Mode

Generates two files:

  • Tables.cs - All entity constants in one file
  • Choices.cs - All global option set constants in one file

Architecture

Commands/
  โ”œโ”€โ”€ SchemaCommand.cs          # Schema export CLI command
  โ”œโ”€โ”€ ConstantsCommand.cs       # Constants generation CLI command
  โ”œโ”€โ”€ RefDataCompareCommand.cs  # Reference data comparison CLI command
  โ”œโ”€โ”€ RefDataMigrateCommand.cs  # Reference data migration CLI command
  โ”œโ”€โ”€ ProcessManageCommand.cs   # Process management CLI command
  โ”œโ”€โ”€ DataPatchCommand.cs       # Data patch CLI command
  โ””โ”€โ”€ SolutionLayersCommand.cs  # Solution layer analysis CLI command
Services/
  โ”œโ”€โ”€ SchemaService.cs          # Schema export orchestration
  โ”œโ”€โ”€ SchemaExtractor.cs        # Metadata extraction with solution filtering
  โ”œโ”€โ”€ SchemaExporter.cs         # Export to JSON/XLSX formats
  โ”œโ”€โ”€ ConstantsGenerator.cs     # Constants generation orchestration
  โ”œโ”€โ”€ CodeTemplateGenerator.cs  # C# code template generation
  โ”œโ”€โ”€ ConstantsFilter.cs        # Entity/attribute filtering logic
  โ”œโ”€โ”€ IdentifierFormatter.cs    # C# identifier formatting (PascalCase, sanitization)
  โ”œโ”€โ”€ MetadataMapper.cs         # SDK to model mapping
  โ”œโ”€โ”€ IRecordComparer.cs        # Record comparison interface
  โ”œโ”€โ”€ RecordComparer.cs         # Record and association comparison logic
  โ”œโ”€โ”€ IComparisonReporter.cs    # Comparison report interface
  โ”œโ”€โ”€ ComparisonReporter.cs     # Comparison report Excel generation
  โ”œโ”€โ”€ IRefDataMigrator.cs       # Reference data migrator interface
  โ”œโ”€โ”€ RefDataMigrator.cs        # Reference data migration logic
  โ”œโ”€โ”€ IMigrationReporter.cs     # Migration reporter interface
  โ”œโ”€โ”€ MigrationReporter.cs      # Migration report Excel generation
  โ”œโ”€โ”€ IProcessManager.cs        # Process management interface
  โ”œโ”€โ”€ ProcessManager.cs         # Process state management logic
  โ”œโ”€โ”€ ProcessReporter.cs        # Process report Excel generation
  โ”œโ”€โ”€ IDataPatchReporter.cs     # Data patch reporter interface
  โ”œโ”€โ”€ DataPatchReporter.cs      # Data patch report Excel generation
  โ”œโ”€โ”€ ISolutionLayerService.cs  # Solution layer service interface
  โ”œโ”€โ”€ SolutionLayerService.cs   # Solution layer querying and unmanaged layer detection
  โ”œโ”€โ”€ ISolutionLayerReporter.cs # Solution layer reporter interface
  โ””โ”€โ”€ SolutionLayerReporter.cs  # Solution layer report Excel generation
Infrastructure/
  โ”œโ”€โ”€ DataverseClient.cs        # Dataverse connection management
  โ”œโ”€โ”€ FileWriter.cs             # File I/O abstraction
  โ””โ”€โ”€ ConsoleLogger.cs          # Logging implementation
Models/
  โ”œโ”€โ”€ PowerAppsSchema.cs        # Root schema model
  โ”œโ”€โ”€ EntitySchema.cs           # Entity metadata
  โ”œโ”€โ”€ AttributeSchema.cs        # Attribute metadata
  โ”œโ”€โ”€ RelationshipSchema.cs     # Relationship metadata
  โ”œโ”€โ”€ OptionSetSchema.cs        # OptionSet metadata
  โ”œโ”€โ”€ ConstantsConfig.cs        # Constants generation configuration
  โ”œโ”€โ”€ ConstantsOutputConfig.cs  # Constants output settings
  โ”œโ”€โ”€ RefDataCompareConfig.cs   # Reference data comparison configuration
  โ”œโ”€โ”€ ComparisonResult.cs       # Table comparison result models
  โ”œโ”€โ”€ RelationshipComparisonResult.cs # N:N relationship comparison models
  โ”œโ”€โ”€ RefDataMigrateConfig.cs   # Reference data migration configuration
  โ”œโ”€โ”€ RefDataMigrateModels.cs   # Migration result models
  โ”œโ”€โ”€ ProcessManageConfig.cs    # Process management configuration
  โ”œโ”€โ”€ ProcessManageModels.cs    # Process state models
  โ”œโ”€โ”€ DataPatchConfig.cs        # Data patch configuration
  โ”œโ”€โ”€ DataPatchModels.cs        # Data patch result models
  โ””โ”€โ”€ SolutionLayerResult.cs    # Solution layer analysis result models

Testing

The project includes unit tests covering schema extraction, constants generation, reference data comparison, and process management.

Run Tests

dotnet test

Run Tests with Coverage

# Using test-scripts helper
.\tests\scripts\run-coverage.ps1

# Or manually
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura
reportgenerator -reports:"tests/PowerApps.CLI.Tests/TestResults/coverage.cobertura.xml" \
  -targetdir:"TestResults/CoverageReport" -reporttypes:"Html;TextSummary"

Current test coverage:

  • 330+ passing tests (100% pass rate)
  • Line coverage: 60%+
  • Branch coverage: 55%+

Test coverage includes:

  • โœ… Schema extraction and export (JSON/XLSX)
  • โœ… Constants generation (single/multiple file modes)
  • โœ… Code template generation
  • โœ… Identifier formatting and sanitization
  • โœ… Entity/attribute filtering
  • โœ… Metadata mapping
  • โœ… Model validation
  • โœ… Command orchestration (all 7 commands)
  • โœ… Reference data comparison (table records, N:N relationships, name resolution)
  • โœ… Reference data migration (all 4 passes, diff/force modes, column filtering, N:N sync)
  • โœ… Process management (pattern matching, retry logic, state determination)
  • โœ… Data patch (lookup, skip-if-unchanged, update, error handling)
  • โœ… Solution layer analysis (unmanaged layer detection, component type mapping, clean result handling)

Development

Project Structure

  • src/PowerApps.CLI/ - Main application code
    • Commands/ - CLI command definitions
    • Services/ - Business logic and orchestration
    • Infrastructure/ - External integrations and utilities
    • Models/ - Data models and schemas
  • tests/PowerApps.CLI.Tests/ - Unit tests
  • tests/scripts/ - Local test scripts with sample usage (credentials not committed)

Dependencies

  • Microsoft.PowerPlatform.Dataverse.Client - Dataverse SDK
  • ClosedXML - Excel file generation
  • System.CommandLine - CLI framework
  • xUnit - Testing framework
  • Moq - Mocking library

Contributing

Contributions are welcome! Please ensure:

  • All tests pass
  • New features include unit tests
  • Code follows existing patterns and conventions

License

MIT License - see LICENSE file for details.

This project is provided as-is with no warranties. Feel free to use, modify, and distribute as needed.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
1.6.3 222 4/13/2026
1.6.2 105 4/13/2026
1.6.1 182 3/6/2026
1.6.0 103 3/5/2026
1.5.0 128 2/21/2026
1.4.0 106 2/20/2026
1.3.0 115 2/14/2026
1.2.0 134 2/8/2026
1.1.0 113 2/8/2026
1.0.0 117 2/7/2026