From dfa19a3e310c2ccce61031f602fdfe4c035c2ced Mon Sep 17 00:00:00 2001 From: Yang An Date: Thu, 16 Jul 2026 17:27:57 +1000 Subject: [PATCH 01/13] Prototype: codegen-owned static Change Safety parameters (alternative to VTable dynamic-parameter delegate) Emit -AcquirePolicyToken (switch) and -ChangeReference (string) as static [Parameter] properties on azure write-verb cmdlets, categorized Azure. No IDynamicParameters, no Module.cs/VTable delegate wiring; the module-level HTTP pipeline step reads the values from BoundParameters by name. --- powershell/cmdlets/class.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index 37a384a468..b41eb88de2 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -460,6 +460,9 @@ export class CmdletClass extends Class { // implement part of the IContext this.implementIContext(); + // Change Safety: emit codegen-owned static parameters on write-verb cmdlets + this.implementChangeSafetyParameters(); + // add constructors this.implementConstructors(); @@ -1622,6 +1625,28 @@ export class CmdletClass extends Class { extensibleParametersProp.get = toExpression(`${extensibleParameters.value} `); this.add(extensibleParametersProp); } + private implementChangeSafetyParameters() { + // Change Safety (codegen-owned static parameters): only azure write-verb cmdlets + // (PUT/POST/DELETE/PATCH) expose the opt-in Change Safety parameters. The parameter + // values are read by the module-level HTTP pipeline step (in Az.Accounts) from the + // cmdlet's BoundParameters, so no runtime-wired delegate is required here. + if (!this.state.project.azure) { + return; + } + const httpMethod = (this.apiCall.requests?.[0]?.protocol.http?.method ?? '').toLowerCase(); + if (!['put', 'post', 'delete', 'patch'].includes(httpMethod)) { + return; + } + + const acquirePolicyToken = this.add(new Property('AcquirePolicyToken', SwitchParameter, { attributes: [], description: 'Acquire a policy evaluation token for this change and include it on the write request.' })); + acquirePolicyToken.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "Acquire a policy evaluation token for this change and include it on the write request."'] })); + acquirePolicyToken.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); + + const changeReference = this.add(new Property('ChangeReference', dotnet.String, { attributes: [], description: 'A caller-supplied reference that correlates this change with an external change-management record.' })); + changeReference.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "A caller-supplied reference that correlates this change with an external change-management record."'] })); + changeReference.add(new Attribute(ValidateNotNull)); + changeReference.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); + } private implementIEventListener() { const $this = this; const cts = this.add(new Field('_cancellationTokenSource', System.Threading.CancellationTokenSource, { From f5b1c782b709d2d667070c8f4b5201c7e7a80847 Mon Sep 17 00:00:00 2001 From: Yang An Date: Fri, 17 Jul 2026 09:57:38 +1000 Subject: [PATCH 02/13] Prototype: exclude data-plane cmdlets from Change Safety static parameters Gate implementChangeSafetyParameters on !endpointResourceIdKeyName (the generator's canonical data-plane signal, matching isDataPlane in module-class.ts), so only management-plane (ARM) write-verb cmdlets get -AcquirePolicyToken/-ChangeReference. --- powershell/cmdlets/class.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index b41eb88de2..b59ce56ac8 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -1626,13 +1626,19 @@ export class CmdletClass extends Class { this.add(extensibleParametersProp); } private implementChangeSafetyParameters() { - // Change Safety (codegen-owned static parameters): only azure write-verb cmdlets - // (PUT/POST/DELETE/PATCH) expose the opt-in Change Safety parameters. The parameter - // values are read by the module-level HTTP pipeline step (in Az.Accounts) from the - // cmdlet's BoundParameters, so no runtime-wired delegate is required here. + // Change Safety (codegen-owned static parameters): only azure management-plane (ARM) + // write-verb cmdlets (PUT/POST/DELETE/PATCH) expose the opt-in Change Safety parameters. + // The parameter values are read by the module-level HTTP pipeline step (in Az.Accounts) + // from the cmdlet's BoundParameters, so no runtime-wired delegate is required here. if (!this.state.project.azure) { return; } + // Change Safety is a management-plane concept; skip data-plane modules, which target a + // custom service endpoint (identified by an endpoint-resource-id-key-name). This matches + // the data-plane detection used in module-class.ts (isDataPlane). + if (this.state.project.endpointResourceIdKeyName) { + return; + } const httpMethod = (this.apiCall.requests?.[0]?.protocol.http?.method ?? '').toLowerCase(); if (!['put', 'post', 'delete', 'patch'].includes(httpMethod)) { return; From fa81926e6f2d0d330596a11ee735b9a6d78f4b23 Mon Sep 17 00:00:00 2001 From: Yang An Date: Fri, 17 Jul 2026 10:32:35 +1000 Subject: [PATCH 03/13] Align Change Safety static param help text with SDK (ChangeSafetyParameters) Use the exact parameter names and help messages defined in azure-powershell-common ChangeSafetyParameters so AutoRest and SDK cmdlets present identically to users. --- powershell/cmdlets/class.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index b59ce56ac8..ef7852b685 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -1644,12 +1644,12 @@ export class CmdletClass extends Class { return; } - const acquirePolicyToken = this.add(new Property('AcquirePolicyToken', SwitchParameter, { attributes: [], description: 'Acquire a policy evaluation token for this change and include it on the write request.' })); - acquirePolicyToken.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "Acquire a policy evaluation token for this change and include it on the write request."'] })); + const acquirePolicyToken = this.add(new Property('AcquirePolicyToken', SwitchParameter, { attributes: [], description: 'Acquire an Azure Policy token automatically for this resource operation.' })); + acquirePolicyToken.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "Acquire an Azure Policy token automatically for this resource operation."'] })); acquirePolicyToken.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); - const changeReference = this.add(new Property('ChangeReference', dotnet.String, { attributes: [], description: 'A caller-supplied reference that correlates this change with an external change-management record.' })); - changeReference.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "A caller-supplied reference that correlates this change with an external change-management record."'] })); + const changeReference = this.add(new Property('ChangeReference', dotnet.String, { attributes: [], description: 'The change reference resource ID for this resource operation.' })); + changeReference.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "The change reference resource ID for this resource operation."'] })); changeReference.add(new Attribute(ValidateNotNull)); changeReference.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); } From ac04dce92af9a2616c819f221040ff4ffad49255 Mon Sep 17 00:00:00 2001 From: Yang An Date: Fri, 17 Jul 2026 13:11:30 +1000 Subject: [PATCH 04/13] Make Change Safety static parameters opt-in via change-safety config flag Add a change-safety project flag (default false) read from the module readme. implementChangeSafetyParameters only emits -AcquirePolicyToken/-ChangeReference when it is true, so the ~180-module rollout is deliberate (a module opts in alongside bumping its Az.Accounts minimum) rather than triggered by any unrelated regeneration. --- powershell/cmdlets/class.ts | 5 +++++ powershell/internal/project.ts | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index ef7852b685..1b190095cc 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -1630,6 +1630,11 @@ export class CmdletClass extends Class { // write-verb cmdlets (PUT/POST/DELETE/PATCH) expose the opt-in Change Safety parameters. // The parameter values are read by the module-level HTTP pipeline step (in Az.Accounts) // from the cmdlet's BoundParameters, so no runtime-wired delegate is required here. + // Opt-in per module via `change-safety: true` in the module readme (default off), so the + // 180+ module rollout is deliberate rather than triggered by any unrelated regeneration. + if (!this.state.project.changeSafety) { + return; + } if (!this.state.project.azure) { return; } diff --git a/powershell/internal/project.ts b/powershell/internal/project.ts index 4d61fa74bf..03c6b71565 100644 --- a/powershell/internal/project.ts +++ b/powershell/internal/project.ts @@ -128,6 +128,7 @@ export class Project extends codeDomProject { public modelCmdletFolder!: string; public endpointResourceIdKeyName!: string; public endpointSuffixKeyName!: string; + public changeSafety!: boolean; public customFolder!: string; public utilsFolder!: string; @@ -334,6 +335,11 @@ export class Project extends codeDomProject { // configuration for whether to use fixed array in generated code of model, default is false this.fixedArray = await this.state.getValue('fixed-array', false); + // Change Safety: opt-in per module. When true, azure management-plane write-verb cmdlets get the + // -AcquirePolicyToken / -ChangeReference parameters. Default false so the rollout is controlled + // (a module opts in, alongside bumping its Az.Accounts minimum), not organic on every regeneration. + this.changeSafety = await this.state.getValue('change-safety', false); + // File paths this.csproj = await this.state.getValue('csproj'); this.dll = await this.state.getValue('dll'); From 754eb050676743935f5826ad7b8e5ce6946cd37e Mon Sep 17 00:00:00 2001 From: Yang An Date: Thu, 23 Jul 2026 14:46:19 +1000 Subject: [PATCH 05/13] Change Safety: verb-based write-cmdlet gating + rename config to enable-change-safety Address review feedback on #1549: - Gate the -AcquirePolicyToken/-ChangeReference emission on the PowerShell verb instead of sniffing the HTTP method off requests[0]. A cmdlet's callGraph can hold multiple operations (e.g. GetPut Update = GET + PUT) and one operation can carry multiple requests, so requests[0] was unreliable. The verb also correctly treats POST list-style operations (surfaced as Get) as reads. - Rename the opt-in config key change-safety -> enable-change-safety (and the Project.changeSafety property -> enableChangeSafety) so it reads as a toggle. --- powershell/cmdlets/class.ts | 23 +++++++++++++++-------- powershell/internal/project.ts | 4 ++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index 1b190095cc..6324332136 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -1627,12 +1627,12 @@ export class CmdletClass extends Class { } private implementChangeSafetyParameters() { // Change Safety (codegen-owned static parameters): only azure management-plane (ARM) - // write-verb cmdlets (PUT/POST/DELETE/PATCH) expose the opt-in Change Safety parameters. - // The parameter values are read by the module-level HTTP pipeline step (in Az.Accounts) - // from the cmdlet's BoundParameters, so no runtime-wired delegate is required here. - // Opt-in per module via `change-safety: true` in the module readme (default off), so the - // 180+ module rollout is deliberate rather than triggered by any unrelated regeneration. - if (!this.state.project.changeSafety) { + // write cmdlets expose the opt-in Change Safety parameters. The parameter values are read + // by the module-level HTTP pipeline step (in Az.Accounts) from the cmdlet's BoundParameters, + // so no runtime-wired delegate is required here. + // Opt-in per module via `enable-change-safety: true` in the module readme (default off), so + // the 180+ module rollout is deliberate rather than triggered by any unrelated regeneration. + if (!this.state.project.enableChangeSafety) { return; } if (!this.state.project.azure) { @@ -1644,8 +1644,15 @@ export class CmdletClass extends Class { if (this.state.project.endpointResourceIdKeyName) { return; } - const httpMethod = (this.apiCall.requests?.[0]?.protocol.http?.method ?? '').toLowerCase(); - if (!['put', 'post', 'delete', 'patch'].includes(httpMethod)) { + // Gate on the PowerShell verb rather than sniffing the HTTP method off requests[0]. A cmdlet's + // callGraph can contain multiple operations (e.g. a GetPut Update = GET + PUT) and a single + // operation can carry multiple requests, so requests[0] is not a reliable signal for whether + // the cmdlet mutates. The verb encodes the mutating intent computed across the whole call graph + // and, unlike the raw HTTP method, correctly treats POST "list"-style operations (surfaced as + // Get) as reads. + const verb = (this.operation.details.csharp.verb ?? '').toLowerCase(); + const readOnlyVerbs = ['get', 'test', 'find', 'search', 'measure', 'show', 'ping', 'trace', 'resolve', 'read']; + if (readOnlyVerbs.includes(verb)) { return; } diff --git a/powershell/internal/project.ts b/powershell/internal/project.ts index 03c6b71565..b0d91956c7 100644 --- a/powershell/internal/project.ts +++ b/powershell/internal/project.ts @@ -128,7 +128,7 @@ export class Project extends codeDomProject { public modelCmdletFolder!: string; public endpointResourceIdKeyName!: string; public endpointSuffixKeyName!: string; - public changeSafety!: boolean; + public enableChangeSafety!: boolean; public customFolder!: string; public utilsFolder!: string; @@ -338,7 +338,7 @@ export class Project extends codeDomProject { // Change Safety: opt-in per module. When true, azure management-plane write-verb cmdlets get the // -AcquirePolicyToken / -ChangeReference parameters. Default false so the rollout is controlled // (a module opts in, alongside bumping its Az.Accounts minimum), not organic on every regeneration. - this.changeSafety = await this.state.getValue('change-safety', false); + this.enableChangeSafety = await this.state.getValue('enable-change-safety', false); // File paths this.csproj = await this.state.getValue('csproj'); From 80acbefa2576f692885d455fc7c358352891b4a4 Mon Sep 17 00:00:00 2001 From: Yang An Date: Wed, 29 Jul 2026 14:09:58 +1000 Subject: [PATCH 06/13] Change Safety: emit inline IDynamicParameters instead of static params (Stage D) Switch the generator from emitting static -AcquirePolicyToken/-ChangeReference [Parameter] properties to an inline IDynamicParameters.GetDynamicParameters() implementation on azure management-plane write-verb cmdlets. This matches the dynamic-parameter mechanism SDK cmdlets use (AzurePSCmdlet/ChangeSafetyParameters), so SDK and AutoRest cmdlets are indistinguishable. The generated method builds the RuntimeDefinedParameterDictionary locally with names + help text mirroring azure-powershell-common's ChangeSafetyParameters (kept in sync by the Accounts.Test contract pin test); no runtime-wired VTable delegate. All gating (opt-in enable-change-safety flag, azure-only, data-plane excluded, verb-based write gating) is unchanged. --- powershell/cmdlets/class.ts | 38 ++++++++++++------- .../internal/powershell-declarations.ts | 1 + 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/powershell/cmdlets/class.ts b/powershell/cmdlets/class.ts index 6324332136..415a828880 100644 --- a/powershell/cmdlets/class.ts +++ b/powershell/cmdlets/class.ts @@ -15,7 +15,7 @@ import { Switch, System, TerminalCase, toExpression, Try, Using, valueOf, Field, IsNull, Or, ExpressionOrLiteral, TerminalDefaultCase, xmlize, TypeDeclaration, And, IsNotNull, PartialMethod, Case, While, LiteralStatement, Not, ElseIf } from '@azure-tools/codegen-csharp'; import { ClientRuntime, EventListener, Schema, ArrayOf, EnumImplementation } from '../llcsharp/exports'; -import { NullableBoolean, Alias, ArgumentCompleterAttribute, PSArgumentCompleterAttribute, AsyncCommandRuntime, AsyncJob, CmdletAttribute, ErrorCategory, ErrorRecord, Events, InvocationInfo, OutputTypeAttribute, ParameterAttribute, PSCmdlet, PSCredential, SwitchParameter, ValidateNotNull, verbEnum, GeneratedAttribute, DescriptionAttribute, ExternalDocsAttribute, CategoryAttribute, ParameterCategory, ProfileAttribute, PSObject, InternalExportAttribute, ExportAsAttribute, DefaultRunspace, RunspaceFactory, AllowEmptyCollectionAttribute, DoNotExportAttribute, HttpPathAttribute, NotSuggestDefaultParameterSetAttribute } from '../internal/powershell-declarations'; +import { NullableBoolean, Alias, ArgumentCompleterAttribute, PSArgumentCompleterAttribute, AsyncCommandRuntime, AsyncJob, CmdletAttribute, ErrorCategory, ErrorRecord, Events, IDynamicParameters, InvocationInfo, OutputTypeAttribute, ParameterAttribute, PSCmdlet, PSCredential, SwitchParameter, ValidateNotNull, verbEnum, GeneratedAttribute, DescriptionAttribute, ExternalDocsAttribute, CategoryAttribute, ParameterCategory, ProfileAttribute, PSObject, InternalExportAttribute, ExportAsAttribute, DefaultRunspace, RunspaceFactory, AllowEmptyCollectionAttribute, DoNotExportAttribute, HttpPathAttribute, NotSuggestDefaultParameterSetAttribute } from '../internal/powershell-declarations'; import { State } from '../internal/state'; import { Channel } from '@autorest/extension-base'; import { IParameter } from '@azure-tools/codemodel-v3/dist/code-model/components'; @@ -460,7 +460,7 @@ export class CmdletClass extends Class { // implement part of the IContext this.implementIContext(); - // Change Safety: emit codegen-owned static parameters on write-verb cmdlets + // Change Safety: emit codegen-owned inline dynamic parameters on write-verb cmdlets this.implementChangeSafetyParameters(); // add constructors @@ -1626,10 +1626,12 @@ export class CmdletClass extends Class { this.add(extensibleParametersProp); } private implementChangeSafetyParameters() { - // Change Safety (codegen-owned static parameters): only azure management-plane (ARM) - // write cmdlets expose the opt-in Change Safety parameters. The parameter values are read - // by the module-level HTTP pipeline step (in Az.Accounts) from the cmdlet's BoundParameters, - // so no runtime-wired delegate is required here. + // Change Safety (codegen-owned inline dynamic parameters): only azure management-plane (ARM) + // write cmdlets expose the opt-in Change Safety parameters. They are surfaced via an inline + // IDynamicParameters implementation (the same dynamic-parameter mechanism SDK cmdlets use), + // emitted directly in the generated cmdlet -- no runtime-wired VTable delegate. PowerShell + // binds the returned parameters into BoundParameters, where the module-level HTTP pipeline + // step (in Az.Accounts) reads them. // Opt-in per module via `enable-change-safety: true` in the module readme (default off), so // the 180+ module rollout is deliberate rather than triggered by any unrelated regeneration. if (!this.state.project.enableChangeSafety) { @@ -1656,14 +1658,22 @@ export class CmdletClass extends Class { return; } - const acquirePolicyToken = this.add(new Property('AcquirePolicyToken', SwitchParameter, { attributes: [], description: 'Acquire an Azure Policy token automatically for this resource operation.' })); - acquirePolicyToken.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "Acquire an Azure Policy token automatically for this resource operation."'] })); - acquirePolicyToken.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); - - const changeReference = this.add(new Property('ChangeReference', dotnet.String, { attributes: [], description: 'The change reference resource ID for this resource operation.' })); - changeReference.add(new Attribute(ParameterAttribute, { parameters: ['Mandatory = false', 'HelpMessage = "The change reference resource ID for this resource operation."'] })); - changeReference.add(new Attribute(ValidateNotNull)); - changeReference.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.Azure`] })); + // Emit an inline IDynamicParameters implementation. GetDynamicParameters builds the + // RuntimeDefinedParameterDictionary locally with names + help text that mirror + // azure-powershell-common's ChangeSafetyParameters (there is no compile-time link across repos; + // a contract pin test in Accounts.Test keeps these literals in sync). This matches how SDK + // cmdlets surface -AcquirePolicyToken / -ChangeReference, so the two are indistinguishable. + this.interfaces.push(IDynamicParameters); + const getDynamicParameters = this.add(new Method('GetDynamicParameters', dotnet.Object, { + description: 'Returns the Change Safety dynamic parameters (-AcquirePolicyToken / -ChangeReference) for this write cmdlet.', + returnsDescription: 'A containing the Change Safety parameters.' + })); + getDynamicParameters.add(function* () { + yield 'var parameters = new global::System.Management.Automation.RuntimeDefinedParameterDictionary();'; + yield 'parameters.Add("AcquirePolicyToken", new global::System.Management.Automation.RuntimeDefinedParameter("AcquirePolicyToken", typeof(global::System.Management.Automation.SwitchParameter), new global::System.Collections.ObjectModel.Collection { new global::System.Management.Automation.ParameterAttribute { HelpMessage = "Acquire an Azure Policy token automatically for this resource operation.", ParameterSetName = global::System.Management.Automation.ParameterAttribute.AllParameterSets } }));'; + yield 'parameters.Add("ChangeReference", new global::System.Management.Automation.RuntimeDefinedParameter("ChangeReference", typeof(string), new global::System.Collections.ObjectModel.Collection { new global::System.Management.Automation.ParameterAttribute { HelpMessage = "The change reference resource ID for this resource operation.", ParameterSetName = global::System.Management.Automation.ParameterAttribute.AllParameterSets } }));'; + yield 'return parameters;'; + }); } private implementIEventListener() { const $this = this; diff --git a/powershell/internal/powershell-declarations.ts b/powershell/internal/powershell-declarations.ts index 0cbb0c67b7..50e1759823 100644 --- a/powershell/internal/powershell-declarations.ts +++ b/powershell/internal/powershell-declarations.ts @@ -32,6 +32,7 @@ export const ErrorRecord: TypeDeclaration = new ClassType(sma, 'ErrorRecord'); export const SwitchParameter: TypeDeclaration = new ClassType(sma, 'SwitchParameter'); export const NullableBoolean: TypeDeclaration = new ClassType(new Namespace('System'), 'Boolean?'); export const IArgumentCompleter: IInterface = { allProperties: [], declaration: 'System.Management.Automation.IArgumentCompleter' }; +export const IDynamicParameters: IInterface = { allProperties: [], declaration: 'System.Management.Automation.IDynamicParameters' }; export const CompletionResult: TypeDeclaration = new ClassType(sma, 'CompletionResult'); export const CommandAst: TypeDeclaration = new ClassType(`${sma}.Language`, 'CommandAst'); export const CompletionResultType: TypeDeclaration = new ClassType(sma, 'CompletionResultType'); From e19eea4c7f5d89c5da2e329714477acc18597b87 Mon Sep 17 00:00:00 2001 From: Yang An Date: Fri, 31 Jul 2026 16:10:11 +1000 Subject: [PATCH 07/13] Change Safety: emit PolicyTokenHandler as a separate delegate after OnNewRequest Adds a dedicated AcquirePolicyTokenDelegate type and a PolicyTokenHandler property on the generated Module, invoked in CreatePipeline right after OnNewRequest (append-only). Emitted and mapped in the .psm1 only when enable-change-safety is set (azure management-plane), decoupling the change-safety step from OnNewRequest instead of composing into it. --- powershell/generators/psm1.ts | 7 +++++++ powershell/module/module-class.ts | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index 01985a80f3..231af0fd49 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -48,6 +48,13 @@ export async function generatePsm1(project: Project) { let requestHandler = ` # Tweaks the pipeline per call $instance.OnNewRequest = $VTable.OnNewRequest`; + if (project.enableChangeSafety) { + // Change Safety: policy-token step, invoked after OnNewRequest + requestHandler += ` + + # Tweaks the pipeline per call (Change Safety policy-token step) + $instance.PolicyTokenHandler = $VTable.PolicyTokenHandler`; + } if (project.endpointResourceIdKeyName) { // for data plane, we should append different functions instead. requestHandler = ` diff --git a/powershell/module/module-class.ts b/powershell/module/module-class.ts index 1c552107e1..47f775966c 100644 --- a/powershell/module/module-class.ts +++ b/powershell/module/module-class.ts @@ -252,6 +252,11 @@ export class NewModuleClass extends Class { pipelineChangeDelegate.fullDefinition, /* prependStep */ pipelineChangeDelegate.fullDefinition)); /* appendStep */ + // Change Safety: dedicated append-only delegate for the policy-token pipeline step. + const acquirePolicyTokenDelegate = new Alias('AcquirePolicyTokenDelegate', System.Action( + InvocationInfo, /* invocationInfo */ + pipelineChangeDelegate.fullDefinition)); /* appendStep */ + const argumentCompleterDelegate = namespace.add(new Alias('ArgumentCompleterDelegate', System.Func( dotnet.String, /* completerName */ InvocationInfo, /* invocationInfo */ @@ -305,6 +310,9 @@ export class NewModuleClass extends Class { } namespace.add(newRequestPipelineDelegate); + if (this.state.project.enableChangeSafety) { + namespace.add(acquirePolicyTokenDelegate); + } const incomingSignalDelegate = namespace.add(new Alias('SignalDelegate', this.incomingSignalFunc)); const eventListenerDelegate = namespace.add(new Alias('EventListenerDelegate', this.eventListenerFunc)); @@ -314,6 +322,7 @@ export class NewModuleClass extends Class { /* AzAccounts VTable properties */ const OnModuleLoad = this.add(new Property('OnModuleLoad', moduleLoadPipelineDelegate, { description: 'The delegate to call when this module is loaded (supporting a commmon module).' })); const OnNewRequest = new Property('OnNewRequest', newRequestPipelineDelegate, { description: 'The delegate to call before each new request (supporting a commmon module).' }); + const PolicyTokenHandler = new Property('PolicyTokenHandler', acquirePolicyTokenDelegate, { description: 'Change Safety: delegate called after OnNewRequest to (conditionally) add the policy-token pipeline step.' }); const AddRequestUserAgentHandler = new Property('AddRequestUserAgentHandler', newRequestPipelineDelegate, { description: 'The delegate to call before each new request to add request user agent.' }); const AddPatchRequestUriHandler = new Property('AddPatchRequestUriHandler', newRequestPipelineDelegate, { description: 'The delegate to call before each new request to patch request uri.' }); const AddAuthorizeRequestHandler = new Property('AddAuthorizeRequestHandler', authorizeRequestDelegate, { description: 'The delegate to call before each new request to add authorization.' }); @@ -329,6 +338,9 @@ export class NewModuleClass extends Class { this.add(AddAuthorizeRequestHandler); } else { this.add(OnNewRequest); + if (this.state.project.enableChangeSafety) { + this.add(PolicyTokenHandler); + } } const GetParameterValue = this.add(new Property('GetParameterValue', getParameterDelegate, { description: 'The delegate to call to get parameter data from a common module.' })); const EventListener = this.add(new Property('EventListener', eventListenerDelegate, { description: 'A delegate that gets called for each signalled event' })); @@ -402,6 +414,9 @@ export class NewModuleClass extends Class { yield `${AddAuthorizeRequestHandler.value}?.Invoke( ${$this.pInvocationInfo.use}, ${fendpointResourceIdKeyName},${fEndpointSuffixKeyName}, (step)=> { ${pip}.Prepend(step); } , (step)=> { ${pip}.Append(step); }, ${fTokenAudienceConverter}, ${$this.pExtensibleParameters} );`; } else { yield `${OnNewRequest.value}?.Invoke( ${$this.pInvocationInfo.use}, ${$this.pCorrelationId},${$this.pProcessRecordId}, (step)=> { ${pip}.Prepend(step); } , (step)=> { ${pip}.Append(step); } );`; + if ($this.state.project.enableChangeSafety) { + yield `${PolicyTokenHandler.value}?.Invoke( ${$this.pInvocationInfo.use}, (step)=> { ${pip}.Append(step); } );`; + } } yield Return(pip); }); From e0e016e3cc7ddbd3091e3f135c74b2a3bc5e17cf Mon Sep 17 00:00:00 2001 From: Yang An Date: Fri, 31 Jul 2026 16:29:26 +1000 Subject: [PATCH 08/13] Change Safety: always emit PolicyTokenHandler plumbing; gate only the invoke The AcquirePolicyTokenDelegate type, the Module PolicyTokenHandler property, and the .psm1 VTable mapping are now emitted for every management-plane module (like the other always-on delegates). Only the CreatePipeline invoke (and the per-cmdlet params) stay gated on enable-change-safety, so the plumbing is inert until a module opts in. --- powershell/generators/psm1.ts | 6 +----- powershell/module/module-class.ts | 6 ++---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index 231af0fd49..4383d6e674 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -47,14 +47,10 @@ export async function generatePsm1(project: Project) { const localModulesPath = relative(project.baseFolder, project.dependencyModuleFolder); let requestHandler = ` # Tweaks the pipeline per call - $instance.OnNewRequest = $VTable.OnNewRequest`; - if (project.enableChangeSafety) { - // Change Safety: policy-token step, invoked after OnNewRequest - requestHandler += ` + $instance.OnNewRequest = $VTable.OnNewRequest # Tweaks the pipeline per call (Change Safety policy-token step) $instance.PolicyTokenHandler = $VTable.PolicyTokenHandler`; - } if (project.endpointResourceIdKeyName) { // for data plane, we should append different functions instead. requestHandler = ` diff --git a/powershell/module/module-class.ts b/powershell/module/module-class.ts index 47f775966c..fbe5f24cbb 100644 --- a/powershell/module/module-class.ts +++ b/powershell/module/module-class.ts @@ -310,7 +310,7 @@ export class NewModuleClass extends Class { } namespace.add(newRequestPipelineDelegate); - if (this.state.project.enableChangeSafety) { + if (!isDataPlane) { namespace.add(acquirePolicyTokenDelegate); } @@ -338,9 +338,7 @@ export class NewModuleClass extends Class { this.add(AddAuthorizeRequestHandler); } else { this.add(OnNewRequest); - if (this.state.project.enableChangeSafety) { - this.add(PolicyTokenHandler); - } + this.add(PolicyTokenHandler); } const GetParameterValue = this.add(new Property('GetParameterValue', getParameterDelegate, { description: 'The delegate to call to get parameter data from a common module.' })); const EventListener = this.add(new Property('EventListener', eventListenerDelegate, { description: 'A delegate that gets called for each signalled event' })); From 87c5059af0db815e99c0f768722fc86218cdf28b Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 3 Aug 2026 11:22:50 +1000 Subject: [PATCH 09/13] Restrict policy token handler wiring to control plane --- powershell/generators/psm1.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index 4383d6e674..66c0e9a25f 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -47,10 +47,7 @@ export async function generatePsm1(project: Project) { const localModulesPath = relative(project.baseFolder, project.dependencyModuleFolder); let requestHandler = ` # Tweaks the pipeline per call - $instance.OnNewRequest = $VTable.OnNewRequest - - # Tweaks the pipeline per call (Change Safety policy-token step) - $instance.PolicyTokenHandler = $VTable.PolicyTokenHandler`; + $instance.OnNewRequest = $VTable.OnNewRequest`; if (project.endpointResourceIdKeyName) { // for data plane, we should append different functions instead. requestHandler = ` @@ -63,6 +60,10 @@ export async function generatePsm1(project: Project) { # Tweaks the pipeline per call $instance.AddAuthorizeRequestHandler = $VTable.AddAuthorizeRequestHandler `; + } else { + requestHandler += ` + # Tweaks the pipeline per call (Change Safety policy-token step) + $instance.PolicyTokenHandler = $VTable.PolicyTokenHandler`; } azureInitialize = ` # ---------------------------------------------------------------------------------- From 4ce7bb596f08423f824400e3ac139b62819fd4d7 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 3 Aug 2026 13:10:56 +1000 Subject: [PATCH 10/13] Rename VTable slot PolicyTokenHandler to AddChangeSafetyPolicyTokenHandler Align the Change Safety pipeline delegate with the existing Add...Handler VTable naming convention and give it a change-safety-qualified name. Delegate type AcquirePolicyTokenDelegate -> ChangeSafetyPolicyTokenDelegate. --- powershell/generators/psm1.ts | 2 +- powershell/module/module-class.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index 66c0e9a25f..66afbeb167 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -63,7 +63,7 @@ export async function generatePsm1(project: Project) { } else { requestHandler += ` # Tweaks the pipeline per call (Change Safety policy-token step) - $instance.PolicyTokenHandler = $VTable.PolicyTokenHandler`; + $instance.AddChangeSafetyPolicyTokenHandler = $VTable.AddChangeSafetyPolicyTokenHandler`; } azureInitialize = ` # ---------------------------------------------------------------------------------- diff --git a/powershell/module/module-class.ts b/powershell/module/module-class.ts index fbe5f24cbb..78bd9cfa8e 100644 --- a/powershell/module/module-class.ts +++ b/powershell/module/module-class.ts @@ -253,7 +253,7 @@ export class NewModuleClass extends Class { pipelineChangeDelegate.fullDefinition)); /* appendStep */ // Change Safety: dedicated append-only delegate for the policy-token pipeline step. - const acquirePolicyTokenDelegate = new Alias('AcquirePolicyTokenDelegate', System.Action( + const changeSafetyPolicyTokenDelegate = new Alias('ChangeSafetyPolicyTokenDelegate', System.Action( InvocationInfo, /* invocationInfo */ pipelineChangeDelegate.fullDefinition)); /* appendStep */ @@ -311,7 +311,7 @@ export class NewModuleClass extends Class { namespace.add(newRequestPipelineDelegate); if (!isDataPlane) { - namespace.add(acquirePolicyTokenDelegate); + namespace.add(changeSafetyPolicyTokenDelegate); } const incomingSignalDelegate = namespace.add(new Alias('SignalDelegate', this.incomingSignalFunc)); @@ -322,7 +322,7 @@ export class NewModuleClass extends Class { /* AzAccounts VTable properties */ const OnModuleLoad = this.add(new Property('OnModuleLoad', moduleLoadPipelineDelegate, { description: 'The delegate to call when this module is loaded (supporting a commmon module).' })); const OnNewRequest = new Property('OnNewRequest', newRequestPipelineDelegate, { description: 'The delegate to call before each new request (supporting a commmon module).' }); - const PolicyTokenHandler = new Property('PolicyTokenHandler', acquirePolicyTokenDelegate, { description: 'Change Safety: delegate called after OnNewRequest to (conditionally) add the policy-token pipeline step.' }); + const AddChangeSafetyPolicyTokenHandler = new Property('AddChangeSafetyPolicyTokenHandler', changeSafetyPolicyTokenDelegate, { description: 'Change Safety: delegate called after OnNewRequest to (conditionally) add the policy-token pipeline step.' }); const AddRequestUserAgentHandler = new Property('AddRequestUserAgentHandler', newRequestPipelineDelegate, { description: 'The delegate to call before each new request to add request user agent.' }); const AddPatchRequestUriHandler = new Property('AddPatchRequestUriHandler', newRequestPipelineDelegate, { description: 'The delegate to call before each new request to patch request uri.' }); const AddAuthorizeRequestHandler = new Property('AddAuthorizeRequestHandler', authorizeRequestDelegate, { description: 'The delegate to call before each new request to add authorization.' }); @@ -338,7 +338,7 @@ export class NewModuleClass extends Class { this.add(AddAuthorizeRequestHandler); } else { this.add(OnNewRequest); - this.add(PolicyTokenHandler); + this.add(AddChangeSafetyPolicyTokenHandler); } const GetParameterValue = this.add(new Property('GetParameterValue', getParameterDelegate, { description: 'The delegate to call to get parameter data from a common module.' })); const EventListener = this.add(new Property('EventListener', eventListenerDelegate, { description: 'A delegate that gets called for each signalled event' })); @@ -413,7 +413,7 @@ export class NewModuleClass extends Class { } else { yield `${OnNewRequest.value}?.Invoke( ${$this.pInvocationInfo.use}, ${$this.pCorrelationId},${$this.pProcessRecordId}, (step)=> { ${pip}.Prepend(step); } , (step)=> { ${pip}.Append(step); } );`; if ($this.state.project.enableChangeSafety) { - yield `${PolicyTokenHandler.value}?.Invoke( ${$this.pInvocationInfo.use}, (step)=> { ${pip}.Append(step); } );`; + yield `${AddChangeSafetyPolicyTokenHandler.value}?.Invoke( ${$this.pInvocationInfo.use}, (step)=> { ${pip}.Append(step); } );`; } } yield Return(pip); From d30ce48fd734eb082f849125c5842bc4ea918d15 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 3 Aug 2026 14:24:19 +1000 Subject: [PATCH 11/13] Change Safety: forward dynamic params through the exported proxy AutoRest proxy functions use a static param() block, so the inline IDynamicParameters emitted on the private cmdlet never surfaced on the public proxy. Emit a dynamicparam block (only when a wrapped cmdlet implements IDynamicParameters) that forwards the private cmdlet's dynamic parameters, mirroring PowerShell's canonical ProxyCommand pattern. Self-gating: cmdlets without dynamic parameters get no block (zero diff). --- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/powershell/resources/psruntime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/powershell/resources/psruntime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index f36346b829..38d7cbe28a 100644 --- a/powershell/resources/psruntime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/powershell/resources/psruntime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -128,6 +128,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs b/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs index 52400e58df..a8c96120c1 100644 --- a/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs +++ b/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); From 0ef7785b25dbff374005bac64b8a6d739367aaa0 Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 3 Aug 2026 16:43:52 +1000 Subject: [PATCH 12/13] Gate Change Safety plumbing on enable-change-safety; refresh emitter baselines Option B: the AddChangeSafetyPolicyTokenHandler VTable delegate/property, its Module.cs alias, and the psm1 mapping are now emitted only when project.enableChangeSafety is set. Non-opted management-plane modules therefore have zero Module.cs/Az.*.psm1 diff. The always-present build-time runtime sources (ExportProxyCmdlet.cs dynamicparam forwarding + PsProxyOutputs.cs DynamicParamOutput) still change in every baseline. This baseline refresh also sweeps up the pre-existing Context.cs comment typo fix (PSBoundParamters -> PSBoundParameters, #1514) whose baselines were last regenerated in #1421. --- powershell/generators/psm1.ts | 2 +- powershell/module/module-class.ts | 6 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../BuildTime/Cmdlets/ExportProxyCmdlet.cs | 1 + .../BuildTime/Models/PsProxyOutputs.cs | 55 +++++++++++++++++++ .../target/generated/runtime/Context.cs | 2 +- 113 files changed, 2438 insertions(+), 28 deletions(-) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index 66afbeb167..c00345c241 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -60,7 +60,7 @@ export async function generatePsm1(project: Project) { # Tweaks the pipeline per call $instance.AddAuthorizeRequestHandler = $VTable.AddAuthorizeRequestHandler `; - } else { + } else if (project.enableChangeSafety) { requestHandler += ` # Tweaks the pipeline per call (Change Safety policy-token step) $instance.AddChangeSafetyPolicyTokenHandler = $VTable.AddChangeSafetyPolicyTokenHandler`; diff --git a/powershell/module/module-class.ts b/powershell/module/module-class.ts index 78bd9cfa8e..e8950fd6d4 100644 --- a/powershell/module/module-class.ts +++ b/powershell/module/module-class.ts @@ -310,7 +310,7 @@ export class NewModuleClass extends Class { } namespace.add(newRequestPipelineDelegate); - if (!isDataPlane) { + if (!isDataPlane && this.state.project.enableChangeSafety) { namespace.add(changeSafetyPolicyTokenDelegate); } @@ -338,7 +338,9 @@ export class NewModuleClass extends Class { this.add(AddAuthorizeRequestHandler); } else { this.add(OnNewRequest); - this.add(AddChangeSafetyPolicyTokenHandler); + if (this.state.project.enableChangeSafety) { + this.add(AddChangeSafetyPolicyTokenHandler); + } } const GetParameterValue = this.add(new Property('GetParameterValue', getParameterDelegate, { description: 'The delegate to call to get parameter data from a common module.' })); const EventListener = this.add(new Property('EventListener', eventListenerDelegate, { description: 'A delegate that gets called for each signalled event' })); diff --git a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 86a8fc5606..8cc034ae94 100644 --- a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 5c6bf7647e..74e85ae5cd 100644 --- a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/Context.cs index 04cd885026..eba90899f4 100644 --- a/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/AppComplianceAutomation.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.AppComplianceAutomation.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index cd21c8a4e3..0b487ee847 100644 --- a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index c4076757d0..25e5a8d0a1 100644 --- a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/Context.cs index 530755c9dc..e848350cbb 100644 --- a/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Astronomer.Astro.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.Astro.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index f3f4d5950c..44d03b6d4f 100644 --- a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 6d5b86ee48..ec9a944ddf 100644 --- a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/Context.cs index 9f187d47a6..03b5f7a595 100644 --- a/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/AzureAI.Assets/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.MachineLearningServices.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 225883f184..89cb4477a5 100644 --- a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 688d13e0d3..841d854aa7 100644 --- a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/Context.cs index c97fab38e1..5313634b42 100644 --- a/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/AzureFleet.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.ComputeFleet.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index fc97ba6168..3c73b28f5b 100644 --- a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 40d94b824d..05d1046499 100644 --- a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/Context.cs index 85f5e07de9..75756f1752 100644 --- a/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/AzureLargeInstance.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.AzureLargeInstance.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 45da2e89bf..81e8252046 100644 --- a/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index ebee2e81a5..2028b076fd 100644 --- a/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Chaos.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 11037706a6..36e0bac503 100644 --- a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 6af759169a..13122ae82b 100644 --- a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/Context.cs index 2bb02dcf8f..5dea3b0a81 100644 --- a/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/CodeSigning.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.CodeSigning.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 274801feab..2c94e6d21e 100644 --- a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index da123eba07..1350d32cb5 100644 --- a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/Context.cs index 6bd0c3e3dd..33ef633abb 100644 --- a/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/ComputeSchedule.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.ComputeSchedule.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index ffa31e7e14..15799f9873 100644 --- a/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index e93d4439f2..87776f8467 100644 --- a/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Dashboard.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 929a6f3553..3b7ec76dcb 100644 --- a/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index f3aa709352..9dc4753e1b 100644 --- a/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DataBox.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 7a38e76c63..a9535ea8be 100644 --- a/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index b62245114b..052a44fc48 100644 --- a/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DataProtection.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 8dc76de510..bdb360e9d8 100644 --- a/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index fa2468a552..8f3d7d60eb 100644 --- a/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DataReplication.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 2f03fa914b..f66de7715c 100644 --- a/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index de8d7f6ccb..77ad1a7b1a 100644 --- a/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DeviceProvisioningServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index d786435d4c..3b7f15cdcd 100644 --- a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index e91f5c16a1..ffe9eab60f 100644 --- a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/Context.cs index 78fee63f52..e0533d3c91 100644 --- a/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/DeviceRegistry.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.DeviceRegistry.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 8346546be2..c1d970a66a 100644 --- a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index e1dbc585b0..7e3b3351b0 100644 --- a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/Context.cs index 681b15d10c..e140484a14 100644 --- a/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/DocumentDB.MongoCluster.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.MongoCluster.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index ca3991e754..a1aa544daf 100644 --- a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index ed2e7ca410..e1d96a16cf 100644 --- a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/Context.cs index 3f1cfb62c9..627807a7c7 100644 --- a/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/EdgeZones.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.EdgeZones.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 671557b98f..e15a31bba0 100644 --- a/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index c114540da6..5f988dbfca 100644 --- a/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/ElasticSan.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index feebc93456..d9a37cc99d 100644 --- a/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 17861883c8..fc0304cfdb 100644 --- a/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Fleet.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index e9d7d1895e..bf3c1225c3 100644 --- a/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 12f9dfe715..770d0ac366 100644 --- a/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/HardwareSecurityModules.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index efbd9cb2b7..421dd80fd2 100644 --- a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 5e484a2c6c..f4c2cee574 100644 --- a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/Context.cs index a3d4937fae..f59d9da03b 100644 --- a/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/HealthDataAIServices.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.HealthDataAIServices.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index ecc1a44b82..aab08d6852 100644 --- a/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 5fae0d9caf..f5f1127bad 100644 --- a/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Help.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 11d0861e06..cd489ee3b6 100644 --- a/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 634e19a244..dd5894604d 100644 --- a/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/HybridKubernetes.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index d9296de871..a4d3c8a51f 100644 --- a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 01aaf2f8f8..fb8b9e2ed6 100644 --- a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/Context.cs index 3a060ab488..80e8f0a7db 100644 --- a/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Informatica.DataManagement.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.Informatica.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 22aaa204b2..06d21d0e64 100644 --- a/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index c8dd17bf5a..b12d04e2a0 100644 --- a/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/KeyVault.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 7a9e23683a..4a3650f801 100644 --- a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 80d6dc6c38..bc86056927 100644 --- a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/Context.cs index 232414c805..ac87b2ddb7 100644 --- a/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/KubernetesRuntime.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.ContainerOrchestratorRuntime.Runtim /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 8354079954..ef5182ff2d 100644 --- a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 80323decb8..43ab621fe3 100644 --- a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/Context.cs index b1de630657..ae90b69e70 100644 --- a/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/LambdaTest.HyperExecute.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.LambdaTest.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 0e44d7aae4..7eadbe542e 100644 --- a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 7e52a8404e..7640a8a992 100644 --- a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/Context.cs index 35b70bc885..8d802fa12a 100644 --- a/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Liftr.WeightsAndBiases.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.WeightsBiases.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 9f00efc3be..d0f1f82048 100644 --- a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 7537c5cfd5..91ef3e35e7 100644 --- a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/Context.cs index 21ec09e7e9..30319ddf62 100644 --- a/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Microsoft.AVS.Management.brown/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.VMware.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index a1a6a674d4..5bcfe8a3ec 100644 --- a/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 39196da4b3..980498c734 100644 --- a/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Microsoft.DBforMySQL.FlexibleServers.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index ad3e9deed9..bf3baa3318 100644 --- a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 0a441f74f4..6c0ddaa169 100644 --- a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/Context.cs index 471d476b1c..8c1d2f38d9 100644 --- a/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Microsoft.DevOpsInfrastructure.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.DevOpsInfrastructure.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index c1fd04a197..f55e7251db 100644 --- a/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index c4ae827506..509d45f814 100644 --- a/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Microsoft.RecoveryServices.RecoveryServicesBackup.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 7142b68af2..4f4096f2ae 100644 --- a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index a9a14cc5d6..27462153f7 100644 --- a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/Context.cs index 8935ee6a22..e20ebe7515 100644 --- a/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Neon.Postgres.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.NeonPostgres.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index f44c616511..7c4bf34cb6 100644 --- a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 346132492d..f1957b1e82 100644 --- a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/Context.cs index af0194d9eb..a46adcf67c 100644 --- a/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/NetworkAnalytics.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.NetworkAnalytics.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index d392ddc9b6..64cd0a79c9 100644 --- a/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 58df7e4cea..b38e14c228 100644 --- a/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Oracle.Database.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 0528064fb9..e22fdbe63d 100644 --- a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 98848d094c..392d097bc4 100644 --- a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/Context.cs index 2c7189e040..dcb6553720 100644 --- a/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Pinecone.VectorDb.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.Pinecone.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 7428cabb6e..8a9beef4e9 100644 --- a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index a785e0c152..9b48204de1 100644 --- a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/Context.cs index bc8bbff686..7ba7085caa 100644 --- a/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Qumulo.Storage.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.Qumulo.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 34b6f9d11e..661d98be31 100644 --- a/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 7bc24ee52b..7baa209efc 100644 --- a/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/RecoveryServices.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index fb11e3d761..4f425f7cdd 100644 --- a/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 4333ee0b06..3eabb627b4 100644 --- a/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/ServiceFabricManagedClusters.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 9c435a45fc..fb0f7521d3 100644 --- a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index e18a63be3e..fae7c94b31 100644 --- a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/Context.cs index 6307b17a66..e781cce98b 100644 --- a/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Sphere.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.Sphere.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 381858d327..f320ce2006 100644 --- a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 34d07afd1d..ebe3e9c367 100644 --- a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/Context.cs index d0544a1ad0..464960b773 100644 --- a/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/StandbyPool.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.StandbyPool.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index 190fc2f2ff..634214ac70 100644 --- a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index ec08cda6ce..51211184f7 100644 --- a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/Context.cs index 572f8a828a..25e4d8a453 100644 --- a/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/StorageAction.Management.brown/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.StorageAction.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { diff --git a/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index bed38bb65b..529c26b6b9 100644 --- a/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index dcd7f28fdd..b08e05e0fc 100644 --- a/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/StorageMover.Management.brown/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs index d7eb35f946..1b144b6634 100644 --- a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs +++ b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Cmdlets/ExportProxyCmdlet.cs @@ -139,6 +139,7 @@ protected override void ProcessRecord() } sb.Append($"){Environment.NewLine}{Environment.NewLine}"); + sb.Append(variantGroup.ToDynamicParamOutput()); sb.Append(variantGroup.ToBeginOutput()); sb.Append(variantGroup.ToProcessOutput()); sb.Append(variantGroup.ToEndOutput()); diff --git a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs index 627ca81b0b..660f9516a3 100644 --- a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs +++ b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/BuildTime/Models/PsProxyOutputs.cs @@ -199,6 +199,59 @@ public string ClearTelemetryContext() } } + internal class DynamicParamOutput : BaseOutput + { + public DynamicParamOutput(VariantGroup variantGroup) : base(variantGroup) + { + } + + // Change Safety: only emit a dynamicparam block when a wrapped (private) cmdlet actually declares + // dynamic parameters via IDynamicParameters. For every other cmdlet this emits nothing (zero diff), + // so it is a no-op that just forwards the private cmdlet's runtime parameters through the proxy. + private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => + { + var implementingType = (v.Info as CmdletInfo)?.ImplementingType; + return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); + }); + + private string GetParameterSetToCmdletMapping() + { + var sb = new StringBuilder(); + sb.AppendLine($"{Indent}$mapping = @{{"); + foreach (var variant in VariantGroup.Variants) + { + sb.AppendLine($@"{Indent}{Indent}{variant.VariantName} = '{variant.PrivateModuleName}\{variant.PrivateCmdletName}';"); + } + sb.Append($"{Indent}}}"); + return sb.ToString(); + } + + public override string ToString() => !HasDynamicParameters() ? String.Empty : $@"dynamicparam {{ +{Indent}$parameterSet = $PSCmdlet.ParameterSetName +{GetParameterSetToCmdletMapping()} +{Indent}if (-not $mapping.ContainsKey($parameterSet)) {{ $parameterSet = @($mapping.Keys)[0] }} +{Indent}try {{ +{Indent}{Indent}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) +{Indent}{Indent}$dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {{ $_.Value.IsDynamic }}) +{Indent}{Indent}if ($dynamicParams.Length -gt 0) {{ +{Indent}{Indent}{Indent}$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() +{Indent}{Indent}{Indent}foreach ($param in $dynamicParams) {{ +{Indent}{Indent}{Indent}{Indent}$param = $param.Value +{Indent}{Indent}{Indent}{Indent}if (-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) {{ +{Indent}{Indent}{Indent}{Indent}{Indent}$dynParam = [System.Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) +{Indent}{Indent}{Indent}{Indent}{Indent}$paramDictionary.Add($param.Name, $dynParam) +{Indent}{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}}} +{Indent}{Indent}{Indent}return $paramDictionary +{Indent}{Indent}}} +{Indent}}} catch {{ +{Indent}{Indent}throw +{Indent}}} +}} + +"; + } + internal class BeginOutput : BaseOutput { public BeginOutput(VariantGroup variantGroup) : base(variantGroup) @@ -640,6 +693,8 @@ public static string ToSyntaxTypeName(this Type type) public static ParameterNameOutput ToParameterNameOutput(this string parameterName, bool isLast) => new ParameterNameOutput(parameterName, isLast); + public static DynamicParamOutput ToDynamicParamOutput(this VariantGroup variantGroup) => new DynamicParamOutput(variantGroup); + public static BeginOutput ToBeginOutput(this VariantGroup variantGroup) => new BeginOutput(variantGroup); public static ProcessOutput ToProcessOutput(this VariantGroup variantGroup) => new ProcessOutput(variantGroup); diff --git a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/Context.cs b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/Context.cs index 70817b9e63..5d5b1e331f 100644 --- a/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/Context.cs +++ b/tests-upgrade/tests-emitter/Workloads.SAPVirtualInstance.Management/target/generated/runtime/Context.cs @@ -20,7 +20,7 @@ namespace Microsoft.Azure.PowerShell.Cmdlets.SAPVirtualInstance.Runtime /// The IContext Interface defines the communication mechanism for input customization. /// /// - /// In the context, we will have client, pipeline, PSBoundParamters, default EventListener, Cancellation. + /// In the context, we will have client, pipeline, PSBoundParameters, default EventListener, Cancellation. /// public interface IContext { From 8ca5de9cb867c2ebaa7f8740688616a596a6182c Mon Sep 17 00:00:00 2001 From: Yang An Date: Mon, 10 Aug 2026 15:43:22 +1000 Subject: [PATCH 13/13] Change Safety: fold psm1 policy-token handler into control-plane block (address review) Move the AddChangeSafetyPolicyTokenHandler append out of the data-plane else-if and into the control-plane default requestHandler build, gated on enableChangeSafety; the data-plane branch stays a clean override. Output is byte-identical. --- powershell/generators/psm1.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/powershell/generators/psm1.ts b/powershell/generators/psm1.ts index c00345c241..23b66a586f 100644 --- a/powershell/generators/psm1.ts +++ b/powershell/generators/psm1.ts @@ -48,6 +48,11 @@ export async function generatePsm1(project: Project) { let requestHandler = ` # Tweaks the pipeline per call $instance.OnNewRequest = $VTable.OnNewRequest`; + if (project.enableChangeSafety) { + requestHandler += ` + # Tweaks the pipeline per call (Change Safety policy-token step) + $instance.AddChangeSafetyPolicyTokenHandler = $VTable.AddChangeSafetyPolicyTokenHandler`; + } if (project.endpointResourceIdKeyName) { // for data plane, we should append different functions instead. requestHandler = ` @@ -60,10 +65,6 @@ export async function generatePsm1(project: Project) { # Tweaks the pipeline per call $instance.AddAuthorizeRequestHandler = $VTable.AddAuthorizeRequestHandler `; - } else if (project.enableChangeSafety) { - requestHandler += ` - # Tweaks the pipeline per call (Change Safety policy-token step) - $instance.AddChangeSafetyPolicyTokenHandler = $VTable.AddChangeSafetyPolicyTokenHandler`; } azureInitialize = ` # ----------------------------------------------------------------------------------