-
Notifications
You must be signed in to change notification settings - Fork 14
Id Generator CLI
Use the Id Generator CLI (xrm-id-gen) to generate Id<T> definitions for XrmUnitTest from the command line or from AI coding assistants such as Cursor.
This complements the Id Generator WinForms tool and reuses the same parsing and output logic.
| Tool | Best for |
|---|---|
WinForms app (IdGenerator/) |
Interactive use, visual settings, parse/regenerate from output |
CLI (IdGenerator.Cli/) |
Scripts, CI, terminal workflows, AI assistants |
Cursor skill (.cursor/skills/generate-xrm-ids/) |
In-repo guidance for Cursor agents |
The CLI and WinForms app share the same core library (IdGenerator.Core/).
From the repository root:
dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --input "Account 2|Contact"dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --input "Account 2|Contact"dotnet pack IdGenerator.Cli/IdGenerator.Cli.csproj -c Release
dotnet tool install -g --add-source IdGenerator.Cli/bin/Release XrmUnitTest.IdGenerator.CliThen run anywhere:
xrm-id-gen --settings-file .cursor/IdGeneratorSettings.json --input "Account 2|Contact"Releases may also include a pre-built tool package (IdGenerator.Cli.zip) from GitHub Actions.
xrm-id-gen [input] [options]
| Option | Description |
|---|---|
[input] |
Entity definitions as a positional argument. Use | instead of newlines on the command line. |
-i, --input <text>
|
Entity input text. Preferred on PowerShell when quoting complex input. |
-f, --input-file <path>
|
Read entity input from a file. |
If no input option is provided and stdin is redirected, entity input is read from stdin.
| Option | Description |
|---|---|
--from-csharp <path|-> |
Parse existing C# Id<T> definitions, preserve structure, regenerate GUIDs. Use - for stdin. |
| Option | Description |
|---|---|
--seed [int] |
Use deterministic GUIDs. Default seed is 1 when the flag is used without a value. |
--settings-file <path> |
Load options from IdGeneratorSettings.json. |
--use-class-ids |
Generate nested *Ids classes (default). |
--use-struct-ids |
Generate struct-based IDs. |
--use-target-typed-new |
Use new("GUID") syntax (default). |
--use-explicit-new |
Use new Id<T>("GUID") syntax. |
-h, --help
|
Show help. |
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (invalid input, parse failure, etc.) |
2 |
Help displayed |
Each non-empty line defines IDs for one Early Bound entity/table. See Id Generator for full background on the WinForms tool.
On the command line, | is treated the same as a newline. This makes multi-entity input easier to type:
Account 2|Contact,Partners,Jim,Bob
is equivalent to:
Account 2
Contact,Partners,Jim,Bob
In input files (--input-file), use normal newlines. Pipes are optional.
<EntityType> [Count]
-
Countis optional; if omitted, one ID is generated. - If
Countis greater than1, a collection is generated with auto namesA,B,C, ...
Examples:
Account
Account 2
<EntityType>,<NameOrCollection>[,<IdName1>,<IdName2>...]
- If there are exactly 2 comma-separated values, the second value is either a single ID/property name or a collection name (if followed by a count, e.g.
Contact,Employees 2). - If there are 3+ comma-separated values, the second value is the collection name and remaining values are explicit ID names.
- Do not put spaces after commas inside comma-based tokens.
Examples:
Acme_ProjectTask,Task
Contact,Partners,Jim,Bob
Contact,Employees 2
Acme_Project 2
Acme_ProjectTask,Task
Contact,Partners,Jim,Bob
Account 2
Or on one CLI line:
Acme_Project 2|Acme_ProjectTask,Task|Contact,Partners,Jim,Bob|Account 2
public Id<Acme_ProjectTask> Task { get; } = new("C9E8361B-AC23-4134-B242-C52BDFD56A9F");
public AccountIds Accounts { get; } = new();
public PartnerIds Partners { get; } = new();
public ProjectIds Projects { get; } = new();
public class AccountIds
{
public Id<Account> A { get; } = new("9B046FDF-94AF-4F4A-85C4-CD7F7F984367");
public Id<Account> B { get; } = new("4CA2375F-5287-494D-8E30-4DFD1CF2F9E7");
}
public class PartnerIds
{
public Id<Contact> Bob { get; } = new("C46E99ED-F28E-48FF-9EFB-6B7516CDB99D");
public Id<Contact> Jim { get; } = new("C7F251B1-6D2A-4A28-BA07-8D3F781A1D6A");
}
public class ProjectIds
{
public Id<Acme_Project> A { get; } = new("4D67154A-0A50-4C3E-8D55-0FE93BE4F3DC");
public Id<Acme_Project> B { get; } = new("E804C340-1C9D-41D7-930F-64B730B3373E");
}- Output entries are ordered by container name; single IDs (no container) are emitted first.
- Names inside each generated collection are ordered alphabetically.
- Entity names with
_use the part after_when generating default property names (e.g.Acme_Project→Project,Projects).
- Identify the Early Bound entity types needed.
- Build entity input (one line with
|is fine for CLI use). - Run the CLI and capture stdout.
- Paste the generated properties/classes into a nested helper class in your test.
dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --input "Account|Contact 2|SystemUser"Use this when you want new GUIDs but the same property/class structure:
xrm-id-gen --settings-file .cursor/IdGeneratorSettings.json --from-csharp path/to/MyTest.csFrom stdin (PowerShell):
Get-Content path/to/snippet.cs | dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --from-csharp -From stdin (bash):
dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --from-csharp - < snippet.csUse --seed when you need reproducible GUIDs:
xrm-id-gen --seed 42 --settings-file .cursor/IdGeneratorSettings.json --input "Account 2"Without --seed, GUIDs are random (normal test usage).
xrm-id-gen --settings-file .cursor/IdGeneratorSettings.json --input-file entities.txtExample entities.txt:
Account 2
Contact,Partners,Jim,Bob
SystemUser
Settings can be loaded from a JSON file:
{
"useTargetTypedNew": true,
"useClassIds": true
}The repository includes a default file at .cursor/IdGeneratorSettings.json.
| Setting | Default | Description |
|---|---|---|
useClassIds |
true |
Generate class-based nested *Ids types instead of structs. |
useTargetTypedNew |
true |
Use target-typed new("GUID") instead of new Id<T>("GUID"). |
entities |
(sample) | Used by the WinForms app; ignored by CLI unless you reuse the same file. |
CLI flags override settings file values for the current run.
AI assistants should run the CLI rather than inventing GUIDs or naming rules by hand.
From the repository root:
dotnet run --project IdGenerator.Cli -- --settings-file .cursor/IdGeneratorSettings.json --input "Account 2|Contact"If the global tool is installed:
xrm-id-gen --settings-file .cursor/IdGeneratorSettings.json --input "Account 2|Contact"This repository includes a Cursor skill at:
.cursor/skills/generate-xrm-ids/SKILL.md
That skill tells Cursor agents:
- When to generate test IDs
- Which command to run
- How to format entity input
- How to use
--from-csharpand--seed
Clone or copy that skill into other projects if needed.
- Determine required entity types and counts from the test being written.
- Build entity input using the formats above.
- Run
xrm-id-gen(ordotnet run --project IdGenerator.Cli). - Paste stdout into the test's nested IDs helper class.
- Do not manually create GUIDs or guess container/property naming.
Match patterns used elsewhere in the test project, such as nested TestIdsClass / *Ids containers.
Input:
Contact 4
Output:
public ContactIds Contacts { get; } = new();
public class ContactIds
{
public Id<Contact> A { get; } = new("...");
public Id<Contact> B { get; } = new("...");
public Id<Contact> C { get; } = new("...");
public Id<Contact> D { get; } = new("...");
}xrm-id-gen --input "Account|Contact 4|SystemUser 2"xrm-id-gen --use-struct-ids --input "Contact 2"xrm-id-gen --use-explicit-new --input "Account"Inside double quotes, | is a literal character. Prefer --input for clarity:
xrm-id-gen --input "Account 2|Contact"Avoid unquoted input containing |, which PowerShell may interpret as the pipeline operator.
Provide one of:
- positional input
--input--input-file--from-csharp- redirected stdin
The --from-csharp input must contain parseable Id<T> properties or fields in the supported formats (class properties, nested classes, structs, or top-level properties).
The WinForms app saves settings next to its executable (IdGeneratorSettings.json). The CLI uses the path from --settings-file, or defaults next to the CLI executable if no file is specified.
- Id Generator — WinForms tool and input format reference
- Repository:
IdGenerator/,IdGenerator.Core/,IdGenerator.Cli/ - GitHub releases — WinForms zip and CLI tool package