You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This PR fixes two Change Safety parameter-forwarding issues in custom cmdlets that read a resource before writing it.
Issue 1: write-only parameters were forwarded to the preliminary GET
A custom update/remove cmdlet receives Change Safety parameters dynamically. The wrapper previously splatted the same $PSBoundParameters dictionary into both its preliminary GET and its final write.
Simple example:
Set-AzEventHub ... -ChangeReference <change-id>
-> Get-AzEventHub ... -ChangeReference <change-id> # GET does not support this parameter
-> parameter binding fails; the write is never reached
The fix builds $readParameters from the exact GET command's metadata and uses it only for the preliminary read. The original $PSBoundParameters dictionary is preserved for the write, so current and future write-only dynamic parameters continue to flow without hard-coded parameter names.
This pattern is applied to 11 EventHub, 11 Service Bus, 4 Network Security Perimeter, and 4 CDN wrappers.
Issue 2: GeoDR identity paths dropped parameters before the write
The EventHub and Service Bus GeoDR BreakViaIdentity and FailViaIdentity paths rebuild EnvPSBoundParameters before invoking a private write command. That reconstructed dictionary contained identity and runtime parameters but omitted Change Safety dynamic parameters.
Simple example:
Set-AzEventHubGeoDRConfigurationFailOver -InputObject <alias> -ChangeReference <change-id>
-> preliminary GET succeeds
-> EnvPSBoundParameters is rebuilt
-> Invoke-AzEventHubFailDisasterRecoveryConfigOver runs without ChangeReference
The fix inspects the exact generated Break/Fail target's dynamic parameter metadata and copies supported, bound dynamic parameters into EnvPSBoundParameters. Explicit identity/path parameters remain excluded because the wrapper supplies them directly. ContainsKey() is used so this works with both hashtables and the real PSBoundParametersDictionary used during cmdlet invocation.
This applies to the EventHub and Service Bus Break/Fail via-identity paths.
Upcoming Release entries document the fix in Az.Cdn, Az.EventHub, Az.Network, and Az.ServiceBus.
Validation
Offline
All 36 changed PowerShell files parsed successfully.
All four generation metadata files contain valid JSON.
git diff --check passed.
Live-test method
The changed modules were generated and built from this branch, and temporary resources were provisioned in Azure. Each tested command was invoked through both its expanded and via-identity parameter sets with:
-ChangeReference '/subscriptions/change-ref'
This is deliberately not a valid Change Safety resource ID. The expected safe result is InvalidPolicyTokenRequest during policy-token acquisition.
Reaching that error proves both sides of the forwarding flow:
The preliminary GET did not receive the write-only parameter and successfully found the resource.
The final write did receive ChangeReference and attempted Change Safety token acquisition.
The invalid reference stopped execution before the destructive request.
The harness also verified that the target resource remained present after every invocation. Generated commands can emit this as a non-terminating error, so the harness inspected the PowerShell error collection rather than treating a normal return as success.
Live-test results
All 52 executed parameter-set paths reached the expected InvalidPolicyTokenRequest, and every target resource remained present.
Live testing also exposed the Contains() incompatibility with PSBoundParametersDictionary; the ContainsKey() fix is included and was verified by rerunning the EventHub and Service Bus GeoDR live paths.
Paths not exercised live
These paths could not be run in the available subscription:
Command
Parameter-set paths
Reason
Set-AzEventHubCluster
2
Requires a dedicated Event Hub cluster; the repository's shared test-cluster subscription was not accessible to the test account.
Azure blocked the preliminary GET because the tenant is not allowlisted and the required EnableServiceTagsInNsp AFEC flag is unavailable.
Update-AzCdnProfile, Remove-AzCdnProfile for classic CDN
4
Azure no longer permits creating new Microsoft classic CDN profiles, and the test subscription has no existing classic profile.
All temporary Azure resource groups created for live testing were deleted and verified absent afterward.
Scope
The separate two-write Start-AzFrontDoorCdnProfilePrepareMigration forwarding case is deferred to a follow-up. Direct-write namespace failover wrappers remain unchanged because they do not perform a preliminary GET.
Keep target command parameters separate from metadata-filtered read parameters so dynamic write parameters are not passed to preliminary GET operations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the module-specific helper functions and filter read parameters directly at each preliminary read site while preserving the independent target parameter dictionary.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In the BreakViaIdentity path, the Change Safety entries remain in $targetParameters but are not copied into $EnvPSBoundParameters; the final invocation at line 190 therefore drops -AcquirePolicyToken/-ChangeReference even though the wrapped Break cmdlet exposes both dynamic parameters. Please forward the target's write-only dynamic entries into this invocation without duplicating the explicitly supplied path parameters.
Forward Change Safety parameters in FailViaIdentity
In the FailViaIdentity path, the Change Safety entries remain in $targetParameters but are not copied into $EnvPSBoundParameters; the final invocation at line 190 therefore drops -AcquirePolicyToken/-ChangeReference even though the wrapped Fail cmdlet exposes both dynamic parameters. Please forward the target's write-only dynamic entries into this invocation without duplicating the explicitly supplied path parameters.
Forward Change Safety parameters in BreakViaIdentity
In the BreakViaIdentity path, the Change Safety entries remain in $targetParameters but are not copied into $EnvPSBoundParameters; the final invocation at line 190 therefore drops -AcquirePolicyToken/-ChangeReference even though the wrapped Break cmdlet exposes both dynamic parameters. Please forward the target's write-only dynamic entries into this invocation without duplicating the explicitly supplied path parameters.
Forward Change Safety parameters in FailViaIdentity
In the FailViaIdentity path, the Change Safety entries remain in $targetParameters but are not copied into $EnvPSBoundParameters; the final invocation at line 190 therefore drops -AcquirePolicyToken/-ChangeReference even though the wrapped FailExpanded cmdlet exposes both dynamic parameters. Please forward the target's write-only dynamic entries into this invocation without duplicating the explicitly supplied path parameters.
Centralize command-metadata filtering per module to avoid duplicating the same read-parameter intersection at every read-modify-write call site.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The forwarding fix will ship with the existing unreleased Change Safety enablement, so keep a single release note for the feature.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ViaIdentity path still rebuilds $EnvPSBoundParameters from only the transport fields and invokes the write with that dictionary, so the dynamic parameters preserved in $targetParameters (-AcquirePolicyToken, -ChangeReference, and future write parameters) are silently dropped for this parameter set. Build this dictionary from $targetParameters after removing the path parameters supplied explicitly to the private cmdlet.
The ViaIdentity path still rebuilds $EnvPSBoundParameters from only the transport fields and invokes the write with that dictionary, so the dynamic parameters preserved in $targetParameters (-AcquirePolicyToken, -ChangeReference, and future write parameters) are silently dropped for this parameter set. Build this dictionary from $targetParameters after removing the path parameters supplied explicitly to the private cmdlet.
The ViaIdentity path still rebuilds $EnvPSBoundParameters from only the transport fields and invokes the write with that dictionary, so the dynamic parameters preserved in $targetParameters (-AcquirePolicyToken, -ChangeReference, and future write parameters) are silently dropped for this parameter set. Build this dictionary from $targetParameters after removing the path parameters supplied explicitly to the private cmdlet.
The ViaIdentity path still rebuilds $EnvPSBoundParameters from only the transport fields and invokes the write with that dictionary, so the dynamic parameters preserved in $targetParameters (-AcquirePolicyToken, -ChangeReference, and future write parameters) are silently dropped for this parameter set. Build this dictionary from $targetParameters after removing the path parameters supplied explicitly to the private cmdlet.
Keep target writes on the original PSBoundParameters dictionary and introduce only helper-filtered read parameters for preliminary GET operations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The BreakViaIdentity branch still rebuilds $EnvPSBoundParameters with only the common pipeline/proxy values, so -AcquirePolicyToken and -ChangeReference remain in $targetParameters but are never passed to the private via-identity write cmdlet. That cmdlet exposes these dynamic parameters, so construct the write splat from the target dictionary (removing only the explicitly supplied path arguments) to preserve Change Safety and other runtime parameters in this branch.
The FailViaIdentity branch still rebuilds $EnvPSBoundParameters with only the common pipeline/proxy values, so -AcquirePolicyToken and -ChangeReference remain in $targetParameters but are never passed to the private via-identity write cmdlet. That cmdlet exposes these dynamic parameters, so construct the write splat from the target dictionary (removing only the explicitly supplied path arguments) to preserve Change Safety and other runtime parameters in this branch.
The BreakViaIdentity branch still rebuilds $EnvPSBoundParameters with only the common pipeline/proxy values, so -AcquirePolicyToken and -ChangeReference remain in $targetParameters but are never passed to the private via-identity write cmdlet. That cmdlet exposes these dynamic parameters, so construct the write splat from the target dictionary (removing only the explicitly supplied path arguments) to preserve Change Safety and other runtime parameters in this branch.
The FailViaIdentity branch still rebuilds $EnvPSBoundParameters with only the common pipeline/proxy values, so -AcquirePolicyToken and -ChangeReference remain in $targetParameters but are never passed to the private via-identity write cmdlet. That cmdlet exposes these dynamic parameters, so construct the write splat from the target dictionary (removing only the explicitly supplied path arguments) to preserve Change Safety and other runtime parameters in this branch.
Copy all bound dynamic parameters supported by the generated Break and Fail actions into the existing via-identity environment splats without hard-coding Change Safety parameter names.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.
Resolve the Network Security Perimeter generation ID conflict with a fresh ID for the merged source state.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep artifact-level helper packaging assertions, but remove source-only generate-info checks because generation metadata is not included in built module artifacts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document the Change Safety forwarding fixes in all affected modules and remove the PR-specific test files.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes two Change Safety parameter-forwarding issues in custom cmdlets that read a resource before writing it.
Issue 1: write-only parameters were forwarded to the preliminary GET
A custom update/remove cmdlet receives Change Safety parameters dynamically. The wrapper previously splatted the same
$PSBoundParametersdictionary into both its preliminary GET and its final write.Simple example:
The fix builds
$readParametersfrom the exact GET command's metadata and uses it only for the preliminary read. The original$PSBoundParametersdictionary is preserved for the write, so current and future write-only dynamic parameters continue to flow without hard-coded parameter names.This pattern is applied to 11 EventHub, 11 Service Bus, 4 Network Security Perimeter, and 4 CDN wrappers.
Issue 2: GeoDR identity paths dropped parameters before the write
The EventHub and Service Bus GeoDR
BreakViaIdentityandFailViaIdentitypaths rebuildEnvPSBoundParametersbefore invoking a private write command. That reconstructed dictionary contained identity and runtime parameters but omitted Change Safety dynamic parameters.Simple example:
The fix inspects the exact generated Break/Fail target's dynamic parameter metadata and copies supported, bound dynamic parameters into
EnvPSBoundParameters. Explicit identity/path parameters remain excluded because the wrapper supplies them directly.ContainsKey()is used so this works with both hashtables and the realPSBoundParametersDictionaryused during cmdlet invocation.This applies to the EventHub and Service Bus Break/Fail via-identity paths.
Upcoming Release entries document the fix in Az.Cdn, Az.EventHub, Az.Network, and Az.ServiceBus.
Validation
Offline
git diff --checkpassed.Live-test method
The changed modules were generated and built from this branch, and temporary resources were provisioned in Azure. Each tested command was invoked through both its expanded and via-identity parameter sets with:
This is deliberately not a valid Change Safety resource ID. The expected safe result is
InvalidPolicyTokenRequestduring policy-token acquisition.Reaching that error proves both sides of the forwarding flow:
ChangeReferenceand attempted Change Safety token acquisition.The harness also verified that the target resource remained present after every invocation. Generated commands can emit this as a non-terminating error, so the harness inspected the PowerShell error collection rather than treating a normal return as success.
Live-test results
All 52 executed parameter-set paths reached the expected
InvalidPolicyTokenRequest, and every target resource remained present.Set-AzEventHub,Set-AzEventHubConsumerGroup,Set-AzEventHubAuthorizationRule,Set-AzEventHubNamespace,Set-AzEventHubNetworkRuleSet,Set-AzEventHubApplicationGroup,Approve-AzEventHubPrivateEndpointConnection,Deny-AzEventHubPrivateEndpointConnection,Set-AzEventHubGeoDRConfigurationBreakPair,Set-AzEventHubGeoDRConfigurationFailOverSet-AzServiceBusQueue,Set-AzServiceBusTopic,Set-AzServiceBusSubscription,Set-AzServiceBusRule,Set-AzServiceBusAuthorizationRule,Set-AzServiceBusNamespace,Set-AzServiceBusNetworkRuleSet,Approve-AzServiceBusPrivateEndpointConnection,Deny-AzServiceBusPrivateEndpointConnection,Set-AzServiceBusGeoDRConfigurationBreakPair,Set-AzServiceBusGeoDRConfigurationFailOverUpdate-AzNetworkSecurityPerimeterAccessRule,Update-AzNetworkSecurityPerimeterAssociation,Update-AzNetworkSecurityPerimeterLinkUpdate-AzFrontDoorCdnProfile,Remove-AzFrontDoorCdnProfileLive testing also exposed the
Contains()incompatibility withPSBoundParametersDictionary; theContainsKey()fix is included and was verified by rerunning the EventHub and Service Bus GeoDR live paths.Paths not exercised live
These paths could not be run in the available subscription:
Set-AzEventHubClusterUpdate-AzNetworkSecurityPerimeterLoggingConfigurationEnableServiceTagsInNspAFEC flag is unavailable.Update-AzCdnProfile,Remove-AzCdnProfilefor classic CDNAll temporary Azure resource groups created for live testing were deleted and verified absent afterward.
Scope
The separate two-write
Start-AzFrontDoorCdnProfilePrepareMigrationforwarding case is deferred to a follow-up. Direct-write namespace failover wrappers remain unchanged because they do not perform a preliminary GET.