--- name: cmdlet-scaffolder description: Generate a new PnP PowerShell cmdlet modelled on an existing sibling - class with the right base class and permission attributes, the documentation page, and the changelog entry. Use when adding a cmdlet for a Graph or CSOM API. Output is a draft needing verification against a real tenant. --- # Playbook: cmdlet-scaffolder Generate a new cmdlet — class, attributes, documentation page and changelog entry — modelled on an existing sibling. > **The output is a draft.** You cannot call the API or run the cmdlet. Everything about the request > shape, the response fields and the permission scopes is inferred. Hand it over labelled as such, > with the inferences listed. A plausible, well-formed, subtly wrong cmdlet is the specific failure > mode this playbook exists to avoid. Conventions live in [`new-cmdlet`](../new-cmdlet/SKILL.md); language rules in [`dotnet-standards`](../dotnet-standards/SKILL.md). This playbook is the procedure. > **Never commit, push, or open a PR.** Leave the work in the tree and hand it over — see > [Human in the loop](../../../AGENTS.md#human-in-the-loop). ## 1. Establish the request Before writing anything, pin down: cmdlet name (`Verb-PnPNoun`, approved verb, singular noun), the API being wrapped, the parameters, and the output shape. If the verb or noun is unsettled, ask — renaming later requires an `[Alias]` and a changelog entry. Check the name is not already taken, including as an alias: ``` grep -rn 'Cmdlet(Verbs[A-Za-z]*\.[A-Za-z]*, "PnPTheNoun")' src/Commands --include=*.cs grep -rn '\[Alias(' src/Commands --include=*.cs ``` ## 2. Choose the sibling **This is the most important step.** Find the closest existing cmdlet: same folder, same base class, same API, same verb. Prefer a recently modified one — helper signatures have evolved and old call shapes survive in the tree. ``` git log --diff-filter=M --name-only -20 -- src/Commands/ ``` Read the sibling's class *and* its `documentation/*.md` page in full. You are matching a house style, not producing generic C#. Say which sibling you used. ## 3. Resolve the API Use the **Microsoft Learn MCP server** for the endpoint, its request/response shape and its least-privilege permissions, delegated and application. Do not answer from memory — this is where generated cmdlets go wrong, and it is exactly what the permission attributes encode. Record the Learn URL for each claim; it goes in the handover. ## 4. Write the class Per [`new-cmdlet`](../new-cmdlet/SKILL.md): correct base class, `[Cmdlet]`, `[OutputType]`, permission attributes, PipeBind parameters with validation attributes, `ExecuteCmdlet()` override. - Reuse existing PipeBinds and models. Only add a new model if nothing fits, one type per file, enums under `src/Commands/Enums/`. - Graph collections: `GetResultCollection`, not `Get`. - CSOM: `ExecuteQueryRetry()`. - Destructive or overwriting: `SupportsShouldProcess` plus an actual `ShouldProcess` call and `-Force`. - Error messages into `Resources.resx`, not string literals. ## 5. Write the documentation page `documentation/.md`, structure copied from the sibling page: - Front matter — `Module Name`, `title`, `schema: 2.0.0`, `applicable`, `external help file`, `online version` slug matching the cmdlet name exactly - `## SYNOPSIS` — a **Required Permissions** block stating the same scopes as the attributes with the same delegated/application split, then a one-line summary. **Omit the block entirely** if the cmdlet carries `ApiPermissionsNotRequired`; adding one there contradicts the attribute and the existing pages - `## SYNTAX` — one ` ```powershell ` block per parameter set - `## DESCRIPTION` - `## EXAMPLES` — at least one, realistic, each followed by a sentence explaining it - `## PARAMETERS` — **alphabetical**, one ` ```yaml ` block per parameter and **nothing else fenced in this section**, including the standard `-Connection` and `-Verbose` blocks copied verbatim from the sibling - `## RELATED LINKS` The YAML fields must agree with the attributes exactly — see [`docs-sync`](../docs-sync/SKILL.md) for the field mapping. ## 6. Changelog One line under `[Current nightly]` → `Added`, cmdlet name in backticks, ending with a link to the PR or issue. Match the surrounding entries' tone: what it does and why someone would use it, not "added new cmdlet". ## 7. Build ``` dotnet build src/PnP.PowerShell.sln ``` Warning-clean. Do not touch `src/Tests`. ## 8. Hand over Report: - Files created or changed - **The sibling you modelled on** - **Inferred, not verified** — every API shape, response field and permission scope, each with the Learn URL it came from - **The invocation a maintainer should run against a tenant to verify**, including which connection type (delegated and app-only both, where the cmdlet supports both) - Anything you could not resolve and what would settle it Do not describe the result as tested, working, or verified. It has been compiled, and that is all.