Skip to content

Add WrapperGenerator: a standalone cmdlet generator that reproduces published MS Graph cmdlet names - #3682

Open
Joywambui-maina wants to merge 2 commits into
powershell-v3from
feature/wrapper-generator-clean
Open

Add WrapperGenerator: a standalone cmdlet generator that reproduces published MS Graph cmdlet names#3682
Joywambui-maina wants to merge 2 commits into
powershell-v3from
feature/wrapper-generator-clean

Conversation

@Joywambui-maina

@Joywambui-maina Joywambui-maina commented Jul 29, 2026

Copy link
Copy Markdown

Changes Proposed

  • Adds tools/WrapperGenerator, a standalone .NET CLI that generates C# cmdlet
    classes (e.g. Get-MgUserMessage) from Graph's OpenAPI description
  • Builds cmdlet nouns from URL paths with per-word singularization instead of
    operationIds, for deterministic naming
  • Reproduces published SDK hand-tuned names as checked-in data, with entries citing their AutoRest directive sources
  • Emits paired list/item GETs as one public dispatcher cmdlet with List/Get
    parameter sets forwarding to internal cmdlets
  • Includes 69 unit tests validated against published Microsoft.Graph cmdlet
    names from MgCommandMetadata.json
  • Adds tools/Compare-WrapperCmdletNames.ps1 for parity validation against the command metadata inventory
  • Documents the naming algorithm rules with shipping cmdlets as evidence, plus identified gaps
  • Updates .azure-pipelines/common-templates/install-tools.yml to install the
    .NET 10 SDK so CI can build the net10.0 generator projects

Why

Customer scripts depend on the exact cmdlet names the SDK ships — Get-MgUserMessage, not Get-MgUsersMessages. When nouns are derived from operationIds, generated names leak whatever plurality the spec author chose, and collisions have occurred. Path-based deterministic naming with singularization rules keeps name parity stable.

Validation

  • All 69 unit tests pass (dotnet test on net10.0).
  • Generated modules were checked against the published cmdlet inventory
    (MgCommandMetadata.json) using tools/Compare-WrapperCmdletNames.ps1: every generated cmdlet whose API call exists in the published SDK matches the published name exactly (e.g. BackupRestore 183/186, Bookings 129/131). The handful of non-matches are endpoints with no published cmdlet to compare against — not naming mismatches.
  • The generated C# compiles alongside the Kiota-generated client; module
    wiring is documented as future work.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new standalone .NET CLI generator (tools/WrapperGenerator) intended to reproduce the published Microsoft.Graph PowerShell cmdlet names deterministically by deriving nouns from URL paths (with per-word singularization), alongside tests and tooling to validate parity against MgCommandMetadata.json. It also updates CI tooling to install a newer .NET SDK required to build the new net10.0 projects.

Changes:

  • Introduces tools/WrapperGenerator (OpenAPI reader + naming + emission) to generate wrapper cmdlet C# sources and a lock file.
  • Adds a dedicated test project covering naming/singularization/schema-property extraction and generation regressions.
  • Adds a parity gate script (tools/Compare-WrapperCmdletNames.ps1) and updates pipeline tooling to install the needed .NET SDK.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/WrapperGenerator/WrapperGenerator.csproj New net10.0 CLI project and package dependencies for OpenAPI reading/logging.
tools/WrapperGenerator/Program.cs CLI entry point: arg parsing, spec loading, include-path filtering, run + lockfile write.
tools/WrapperGenerator/PowerShellWrapperGenerationService.cs Orchestrates operation selection, GET pairing, and writing emitted .g.cs files.
tools/WrapperGenerator/CmdletNaming.cs Implements verb/noun resolution and Kiota builder-expression construction.
tools/WrapperGenerator/Singularizer.cs Path-segment per-word singularization rules to match published cmdlet nouns.
tools/WrapperGenerator/NamingOverrides.cs Data-driven overrides/suppressions to mirror published SDK AutoRest directives.
tools/WrapperGenerator/IncludePathFilter.cs Filters OpenAPI paths/operations based on --include-path patterns.
tools/WrapperGenerator/CmdletEmitter.cs Emits cmdlet C# templates (GET/list, dispatcher, new/update/remove, shared auth helpers).
tools/WrapperGenerator/SchemaProperties.cs Extracts shallow primitive body properties for New/Update parameter flattening.
tools/WrapperGenerator/OperationInfo.cs Operation metadata record used during naming/emission decisions.
tools/WrapperGenerator/EmitContext.cs Carries emitter namespace settings (client namespace + cmdlet namespace).
tools/WrapperGenerator/GeneratorConfig.cs Records generator run configuration (client namespace, output path).
tools/WrapperGenerator/GeneratorExtensions.cs Shared string casing helpers + OpenAPI $ref ID extraction.
tools/WrapperGenerator/README.md Documents naming algorithm, output shapes, build/run/test steps, and known gaps.
tools/WrapperGenerator.Tests/WrapperGenerator.Tests.csproj New net10.0 test project referencing WrapperGenerator.
tools/WrapperGenerator.Tests/NamingTests.cs Golden naming/singularization/builder-expression tests against published cmdlet expectations.
tools/WrapperGenerator.Tests/SchemaPropertiesTests.cs Tests property extraction and passwordProfile detection behavior.
tools/WrapperGenerator.Tests/GenerationServiceRegressionTests.cs Regression tests ensuring generator skips unsupported shapes without throwing.
tools/WrapperGenerator.Tests/EmitterTests.cs Tests emitter escaping of spec-derived string literals (quotes).
tools/Compare-WrapperCmdletNames.ps1 New parity gate: reconstructs Method+URI from generated source and joins to oracle inventory.
.azure-pipelines/common-templates/install-tools.yml Installs an additional .NET SDK to support building net10.0 tooling.
.gitignore Ignores sweep_results.json.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

null,
MyInvocation.BoundParameters, internalCmdletName);
}
{{CatchBlock(TargetId(itemNaming))}}
Comment on lines +156 to +157
$cmdletAttrPattern = '\[Cmdlet\(Verbs\w+\.(\w+),\s*"([^"]+)"'
$callChainPattern = 'client\.([A-Za-z0-9_.\[\]]+)\.(Get|Post|Patch|Put|Delete)Async\('
Comment on lines +185 to +187
$verb = $attrMatch.Groups[1].Value
$generatedNoun = $attrMatch.Groups[2].Value
$publishedNoun = $generatedNoun -replace '_(List|Get)$', ''
Comment on lines +99 to +106
foreach ($token in ($BuilderExpression -split '\.')) {
if ($token -notmatch '^([A-Za-z0-9]+)(\[([A-Za-z0-9]+)\])?$') {
return $null
}
$prop = $Matches[1]
$segments += ($prop.Substring(0, 1).ToLowerInvariant() + $prop.Substring(1))
if ($Matches[3]) { $segments += '{param}' }
}

## The one subtle part: list + item GET become one cmdlet

Graph has two GETs for a resource — the collection (`GET …/messages`) and a single item (`GET …/messages/{message-id}`) — but the published SDK exposes **one** cmdlet, `Get-MgUserMessage`,that does both: no `-MessageId` lists them, a `-MessageId` fetches one.
@Joywambui-maina

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="Microsoft"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants