diff --git a/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs b/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs index a8c96120c1..8004f5c588 100644 --- a/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs +++ b/powershell/resources/psruntime/BuildTime/Models/PsProxyOutputs.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Rest.ClientRuntime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 74e85ae5cd..608cef530b 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.AppComplianceAutomation.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 25e5a8d0a1..5f393a5431 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Astro.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 ec9a944ddf..16a4e52746 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.MachineLearningServices.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 841d854aa7..909ae822a8 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ComputeFleet.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 05d1046499..816412af6c 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.AzureLargeInstance.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 2028b076fd..e7e859dd1c 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Chaos.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 13122ae82b..56b03410f3 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.CodeSigning.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 1350d32cb5..ebbafeccf3 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ComputeSchedule.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 87776f8467..b31696014a 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Dashboard.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 9dc4753e1b..64d1a17002 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.DataBox.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 052a44fc48..7f80ba3fb6 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.DataProtection.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 8f3d7d60eb..5837a66c71 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.RecoveryServicesDataReplication.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 77ad1a7b1a..aa027924d8 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.DeviceProvisioningServices.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 ffe9eab60f..fb34b5148d 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.DeviceRegistry.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 7e3b3351b0..2497cdaf89 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.MongoCluster.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 e1d96a16cf..3ec1b7e09d 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.EdgeZones.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 5f988dbfca..16fddc44eb 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ElasticSan.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 fc0304cfdb..2cd22f4055 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ContainerServiceFleet.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 770d0ac366..4562ddb404 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Hsm.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 f4c2cee574..ec5a72ee00 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.HealthDataAIServices.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 f5f1127bad..60a2b84e52 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Help.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 dd5894604d..f67a893b6c 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.HybridKubernetes.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 fb8b9e2ed6..33909cc973 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Informatica.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 b12d04e2a0..421e1ff221 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.KeyVault.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 bc86056927..afad61c045 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ContainerOrchestratorRuntime.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 43ab621fe3..9005eb2718 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.LambdaTest.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 7640a8a992..ecabaf5890 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.WeightsBiases.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 91ef3e35e7..f3a5cdca8b 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.VMware.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 980498c734..ceff57b7e8 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.MySql.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 6c0ddaa169..dd5bd164c3 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.DevOpsInfrastructure.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 509d45f814..043c186281 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.RecoveryServicesBackup.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 27462153f7..9242c3dc66 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.NeonPostgres.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 f1957b1e82..95d8271eda 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.NetworkAnalytics.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 b38e14c228..fd63c403cb 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.OracleDatabase.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 392d097bc4..6fb8cfba79 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Pinecone.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 9b48204de1..5418a89791 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Qumulo.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 7baa209efc..9c97de4a8c 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.RecoveryServices.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 3eabb627b4..6d618fad87 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.ServiceFabricManagedClusters.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 fae7c94b31..8652c2ce4b 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.Sphere.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 ebe3e9c367..e6f7e5b481 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.StandbyPool.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 51211184f7..7028f36508 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.StorageAction.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 b08e05e0fc..a86bca6eb8 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.StorageMover.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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() 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 660f9516a3..0010c60353 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 @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Management.Automation; +using System.Management.Automation.Language; using System.Text; using System.Text.RegularExpressions; using static Microsoft.Azure.PowerShell.Cmdlets.SAPVirtualInstance.Runtime.PowerShell.PsProxyOutputExtensions; @@ -205,11 +206,21 @@ 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. + // Change Safety: only emit a dynamicparam block when the wrapped command actually declares dynamic + // parameters, either via IDynamicParameters (compiled private cmdlets) or via its own `dynamicparam` + // block (custom-fronted cmdlets, which wrap a hand-written function in custom/ instead of a private + // cmdlet). For every other cmdlet this emits nothing (zero diff), so it is a no-op that just forwards + // the wrapped command's runtime parameters through the proxy. private bool HasDynamicParameters() => VariantGroup.Variants.Any(v => { + if (v.IsFunction) + { + // FunctionInfo.ScriptBlock.Ast is a FunctionDefinitionAst (the `function Name { ... }` wrapper); + // its Body (a ScriptBlockAst) is what actually exposes the DynamicParamBlock property. + var ast = (v.Info as FunctionInfo)?.ScriptBlock?.Ast; + var scriptBlockAst = ast as ScriptBlockAst ?? (ast as FunctionDefinitionAst)?.Body; + return scriptBlockAst?.DynamicParamBlock != null; + } var implementingType = (v.Info as CmdletInfo)?.ImplementingType; return implementingType != null && typeof(IDynamicParameters).IsAssignableFrom(implementingType); }); @@ -231,7 +242,7 @@ public override string ToString() => !HasDynamicParameters() ? String.Empty : $@ {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}$targetCmd = $ExecutionContext.InvokeCommand.GetCommand(($mapping[$parameterSet]), [System.Management.Automation.CommandTypes]::Cmdlet -bor [System.Management.Automation.CommandTypes]::Function, $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()