[AzNetwork] Add Ip Preservation Cmdlets#29373
[AzNetwork] Add Ip Preservation Cmdlets#29373VeryEarly merged 3 commits intoAzure:release-network-2025-07-01from
Conversation
| Thanks for your contribution! The pull request validation has started. Please revisit this comment for updated status. |
|
/azp run |
|
Commenter does not have sufficient privileges for PR 29373 in repo Azure/azure-powershell |
There was a problem hiding this comment.
Pull request overview
Adds new Az.Network cmdlets to manage cloud service public IP address reservation/rollback and to disassociate a standalone reserved public IP, along with help/manifest updates and initial scenario tests.
Changes:
- Added 2 new
Invoke-AzPublicIpAddress*cmdlets for cloud service IP reservation and reserved IP disassociation. - Added help markdown and updated module cmdlet index/export list.
- Added scenario tests (currently focused on missing-resource error handling).
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Network/Network/PublicIpAddress/InvokeAzurePublicIpAddressCloudServiceReservationCommand.cs | New cmdlet implementation to reserve or roll back cloud service public IP allocation. |
| src/Network/Network/PublicIpAddress/InvokeAzurePublicIpAddressDisassociateCloudServiceReservedIpCommand.cs | New cmdlet implementation to disassociate a standalone reserved public IP from a cloud service public IP. |
| src/Network/Network/help/Invoke-AzPublicIpAddressCloudServiceReservation.md | New reference help for reservation/rollback cmdlet. |
| src/Network/Network/help/Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp.md | New reference help for disassociate cmdlet. |
| src/Network/Network/help/Az.Network.md | Added both cmdlets to the module help index. |
| src/Network/Network/ChangeLog.md | Added upcoming release notes for the new cmdlets. |
| src/Network/Network/Az.Network.psd1 | Exported the two new cmdlets from the module manifest. |
| src/Network/Network.Test/ScenarioTests/PublicIpAddressTests.ps1 | Added scenario tests for error handling when the target public IP does not exist. |
| src/Network/Network.Test/ScenarioTests/PublicIpAddressTests.cs | Wired new scenario tests into the xUnit test runner. |
|
|
||
| if (!this.IsPublicIpAddressPresent(this.ResourceGroupName, this.Name)) | ||
| { | ||
| throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound); |
There was a problem hiding this comment.
Resources.ResourceNotFound includes a format placeholder ("Resource '{0}' not found"), but this throws it without formatting, so users will see the literal {0}. Format the message with the public IP name (and/or resource group) before throwing, or use a non-formatted resource string.
| throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound); | |
| throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound, this.Name)); |
|
|
||
| if (!this.IsPublicIpAddressPresent(this.ResourceGroupName, this.Name)) | ||
| { | ||
| throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound); |
There was a problem hiding this comment.
Resources.ResourceNotFound is a formatted string ("Resource '{0}' not found"), but it’s thrown without string.Format, so the {0} placeholder will show up in the error text. Please format the message with the cloud service public IP name (and/or resource group) before throwing.
| throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound); | |
| throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound, this.Name)); |
| ``` | ||
|
|
||
| ## DESCRIPTION | ||
| The **Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp** cmdlet invokes the **DisassociateCloudServiceReservedPublicIp** operation. Use **PublicIpArmId** to specify the ARM resource ID of the standalone public IP to disassociate from the cloud service public IP identified by **Name** and **ResourceGroupName**, **ResourceId**, or **InputObject**. |
There was a problem hiding this comment.
The help text refers to an "ARM resource ID"; consider expanding this on first use to "Azure Resource Manager (ARM) resource ID" to avoid assuming familiarity with the acronym.
| The **Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp** cmdlet invokes the **DisassociateCloudServiceReservedPublicIp** operation. Use **PublicIpArmId** to specify the ARM resource ID of the standalone public IP to disassociate from the cloud service public IP identified by **Name** and **ResourceGroupName**, **ResourceId**, or **InputObject**. | |
| The **Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp** cmdlet invokes the **DisassociateCloudServiceReservedPublicIp** operation. Use **PublicIpArmId** to specify the Azure Resource Manager (ARM) resource ID of the standalone public IP to disassociate from the cloud service public IP identified by **Name** and **ResourceGroupName**, **ResourceId**, or **InputObject**. |
| ## Upcoming Release | ||
| * Added cmdlets for cloud service public IP address operations: | ||
| - `Invoke-AzPublicIpAddressCloudServiceReservation`: reserve a cloud service public IP or roll back to dynamic allocation (`-IsRollback`). | ||
| - `Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp`: disassociate a standalone reserved public IP from a cloud service public IP (`-PublicIpArmId`). |
There was a problem hiding this comment.
The changelog entry includes the parameter name -PublicIpArmId, which introduces the less-obvious acronym "ARM". Please expand it on first use in this release section (for example, "Azure Resource Manager (ARM) resource ID").
| - `Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp`: disassociate a standalone reserved public IP from a cloud service public IP (`-PublicIpArmId`). | |
| - `Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp`: disassociate a standalone reserved public IP from a cloud service public IP by using the Azure Resource Manager (ARM) resource ID parameter (`-PublicIpArmId`). |
| $subId = (Get-AzContext).Subscription.Id | ||
| $resourceId = "/subscriptions/$subId/resourceGroups/$rgname/providers/Microsoft.Network/publicIPAddresses/$fakePipName" | ||
|
|
||
| Assert-ThrowsContains { Invoke-AzPublicIpAddressCloudServiceReservation -ResourceGroupName $rgname -Name $fakePipName } "not found" | ||
| Assert-ThrowsContains { Invoke-AzPublicIpAddressCloudServiceReservation -ResourceId $resourceId } "not found" |
There was a problem hiding this comment.
These new tests only validate the "not found" error path for the new cmdlets. Please add a happy-path test (or an alternative test approach if provisioning a cloud service public IP is required) so the end-to-end behavior is covered.
|
|
||
| Assert-ThrowsContains { | ||
| Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -ResourceGroupName $rgname -Name $fakeCloudServicePip -PublicIpArmId $standaloneArmId | ||
| } "not found" | ||
|
|
There was a problem hiding this comment.
This new test only exercises the missing-resource error path for Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp. Please add a happy-path validation (or an alternative test approach if this operation requires specific cloud service public IP prerequisites) to cover the real behavior.
| Disassociates the standalone public IP **standalonePip** from the cloud service public IP **myCloudServicePublicIp**. | ||
|
|
||
| ### Example 2: Pipe the cloud service public IP | ||
| ```powershell |
There was a problem hiding this comment.
Example 2 references $standaloneId but doesn’t define it within the example, so it isn’t self-contained. Define the variable in this example (or inline the resource ID) so users can copy/paste it as-is.
| ```powershell | |
| ```powershell | |
| $standaloneId = '/subscriptions/{subId}/resourceGroups/myRg/providers/Microsoft.Network/publicIPAddresses/standalonePip' |
| ### Example 2: Pipe the cloud service public IP | ||
| ```powershell | ||
| $cloudPip = Get-AzPublicIpAddress -ResourceGroupName 'myResourceGroup' -Name 'myCloudServicePublicIp' | ||
| Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -InputObject $cloudPip -PublicIpArmId $standaloneId |
There was a problem hiding this comment.
Example 2 is titled "Pipe the cloud service public IP", but the snippet uses -InputObject $cloudPip rather than piping ($cloudPip | ...). Either change the example to actually use the pipeline or adjust the title/description to match the shown usage.
| Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -InputObject $cloudPip -PublicIpArmId $standaloneId | |
| $cloudPip | Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -PublicIpArmId $standaloneId |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
Head branch was pushed to by a user without write access
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| Mandatory = true, | ||
| ParameterSetName = ParameterSetNames.ByName, | ||
| ValueFromPipelineByPropertyName = true, | ||
| HelpMessage = "The public IP address name.")] |
There was a problem hiding this comment.
The HelpMessage text for -Name says "The public IP address name." but this cmdlet is explicitly scoped to cloud service public IPs (per cmdlet name/synopsis). Updating the parameter HelpMessage to consistently say "cloud service public IP address" would avoid confusing users and keep it aligned with the generated help markdown.
| HelpMessage = "The public IP address name.")] | |
| HelpMessage = "The cloud service public IP address name.")] |
| [Parameter( | ||
| ParameterSetName = ParameterSetNames.ByInputObject, | ||
| Mandatory = true, | ||
| ValueFromPipeline = true, | ||
| HelpMessage = "The public IP address object.")] | ||
| [ValidateNotNullOrEmpty] | ||
| public PSPublicIpAddress InputObject { get; set; } | ||
|
|
||
| [Parameter( | ||
| ParameterSetName = ParameterSetNames.ByResourceId, | ||
| Mandatory = true, | ||
| ValueFromPipelineByPropertyName = true, | ||
| HelpMessage = "The public IP address resource ID.")] | ||
| [ValidateNotNullOrEmpty] | ||
| [ResourceIdCompleter("Microsoft.Network/publicIPAddresses")] | ||
| public string ResourceId { get; set; } |
There was a problem hiding this comment.
The HelpMessage text for -InputObject says "The public IP address object." but this cmdlet targets cloud service public IPs. Please update this HelpMessage (and similarly -ResourceId) so the parameter descriptions match the cmdlet purpose and the synopsis/description in the help file.
| ### -InputObject | ||
| The public IP address object. | ||
|
|
||
| ```yaml | ||
| Type: PSPublicIpAddress | ||
| Parameter Sets: ByInputObject | ||
| Aliases: | ||
|
|
||
| Required: True | ||
| Position: Named | ||
| Default value: None | ||
| Accept pipeline input: True (ByValue) | ||
| Accept wildcard characters: False | ||
| ``` |
There was a problem hiding this comment.
Parameter description for -InputObject says "The public IP address object." but the cmdlet synopsis/description describe a cloud service public IP address. Please align the parameter description with the cmdlet scope to avoid ambiguity for users.
| ### -Name | ||
| The public IP address name. | ||
|
|
||
| ```yaml | ||
| Type: String | ||
| Parameter Sets: ByName | ||
| Aliases: ResourceName | ||
|
|
||
| Required: True | ||
| Position: Named | ||
| Default value: None | ||
| Accept pipeline input: True (ByPropertyName) | ||
| Accept wildcard characters: False | ||
| ``` |
There was a problem hiding this comment.
Parameter description for -Name currently says "The public IP address name." but this cmdlet is specific to cloud service public IP addresses. Please update the parameter description to be consistent with the synopsis/description.
| ### -ResourceId | ||
| The public IP address resource ID. | ||
|
|
||
| ```yaml | ||
| Type: String | ||
| Parameter Sets: ByResourceId | ||
| Aliases: | ||
|
|
||
| Required: True | ||
| Position: Named | ||
| Default value: None | ||
| Accept pipeline input: True (ByPropertyName) | ||
| Accept wildcard characters: False | ||
| ``` |
There was a problem hiding this comment.
Parameter description for -ResourceId says "The public IP address resource ID." but the cmdlet targets cloud service public IPs. Please clarify this is the cloud service public IP resource ID (or otherwise adjust the cmdlet description if it is intended to work for any Public IP).
| try | ||
| { | ||
| New-AzResourceGroup -Name $rgname -Location $rglocation | Out-Null | ||
| $subId = (Get-AzContext).Subscription.Id | ||
| $resourceId = "/subscriptions/$subId/resourceGroups/$rgname/providers/Microsoft.Network/publicIPAddresses/$fakePipName" | ||
|
|
||
| Assert-ThrowsContains { Invoke-AzPublicIpAddressCloudServiceReservation -ResourceGroupName $rgname -Name $fakePipName } "not found" | ||
| Assert-ThrowsContains { Invoke-AzPublicIpAddressCloudServiceReservation -ResourceId $resourceId } "not found" | ||
| } |
There was a problem hiding this comment.
The new scenario tests only validate the "resource not found" path (the cmdlet exits before calling the Reserve/Disassociate operations). This doesn't exercise the actual service operation call, request construction (e.g., -IsRollback / -PublicIpArmId), output mapping, or the ByInputObject parameter set. Please add at least one test that reaches the SDK operation (even if it validates an expected service-side error for a non-cloud-service Public IP), so the cmdlet implementation beyond the existence check is covered.
47e2acf
into
Azure:release-network-2025-07-01
Description
Mandatory Checklist
Please choose the target release of Azure PowerShell. (⚠️ Target release is a different concept from API readiness. Please click below links for details.)
Check this box to confirm: I have read the Submitting Changes section of
CONTRIBUTING.mdand reviewed the following information:ChangeLog.mdfile(s) appropriatelysrc/{{SERVICE}}/{{SERVICE}}/ChangeLog.md.## Upcoming Releaseheader in the past tense.ChangeLog.mdif no new release is required, such as fixing test case only.