Skip to content

[AzNetwork] Add Ip Preservation Cmdlets#29373

Merged
VeryEarly merged 3 commits intoAzure:release-network-2025-07-01from
pribansa:add-ip-preservation-cmdlets
Apr 13, 2026
Merged

[AzNetwork] Add Ip Preservation Cmdlets#29373
VeryEarly merged 3 commits intoAzure:release-network-2025-07-01from
pribansa:add-ip-preservation-cmdlets

Conversation

@pribansa
Copy link
Copy Markdown

@pribansa pribansa commented Apr 8, 2026

Description

Mandatory Checklist

  • SHOULD update ChangeLog.md file(s) appropriately
    • Update src/{{SERVICE}}/{{SERVICE}}/ChangeLog.md.
      • A snippet outlining the change(s) made in the PR should be written under the ## Upcoming Release header in the past tense.
    • Should not change ChangeLog.md if no new release is required, such as fixing test case only.
  • SHOULD regenerate markdown help files if there is cmdlet API change. Instruction
  • SHOULD have proper test coverage for changes in pull request.
  • SHOULD NOT adjust version of module manually in pull request

@azure-client-tools-bot-prd
Copy link
Copy Markdown

Thanks for your contribution! The pull request validation has started. Please revisit this comment for updated status.

@pribansa
Copy link
Copy Markdown
Author

pribansa commented Apr 8, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown
Contributor

Commenter does not have sufficient privileges for PR 29373 in repo Azure/azure-powershell

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound);
throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound, this.Name));

Copilot uses AI. Check for mistakes.

if (!this.IsPublicIpAddressPresent(this.ResourceGroupName, this.Name))
{
throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
throw new ArgumentException(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound);
throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Network.Properties.Resources.ResourceNotFound, this.Name));

Copilot uses AI. Check for mistakes.
```

## 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**.
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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**.

Copilot uses AI. Check for mistakes.
Comment thread src/Network/Network/ChangeLog.md Outdated
## 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`).
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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").

Suggested change
- `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`).

Copilot uses AI. Check for mistakes.
Comment on lines +1042 to +1046
$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"
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +1071 to +1075

Assert-ThrowsContains {
Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -ResourceGroupName $rgname -Name $fakeCloudServicePip -PublicIpArmId $standaloneArmId
} "not found"

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Disassociates the standalone public IP **standalonePip** from the cloud service public IP **myCloudServicePublicIp**.

### Example 2: Pipe the cloud service public IP
```powershell
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
```powershell
```powershell
$standaloneId = '/subscriptions/{subId}/resourceGroups/myRg/providers/Microsoft.Network/publicIPAddresses/standalonePip'

Copilot uses AI. Check for mistakes.
### Example 2: Pipe the cloud service public IP
```powershell
$cloudPip = Get-AzPublicIpAddress -ResourceGroupName 'myResourceGroup' -Name 'myCloudServicePublicIp'
Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -InputObject $cloudPip -PublicIpArmId $standaloneId
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -InputObject $cloudPip -PublicIpArmId $standaloneId
$cloudPip | Invoke-AzPublicIpAddressDisassociateCloudServiceReservedIp -PublicIpArmId $standaloneId

Copilot uses AI. Check for mistakes.
@VeryEarly VeryEarly self-assigned this Apr 8, 2026
VeryEarly
VeryEarly previously approved these changes Apr 8, 2026
@VeryEarly VeryEarly enabled auto-merge (squash) April 8, 2026 05:22
@VeryEarly
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown
Contributor

Azure Pipelines successfully started running 3 pipeline(s).

auto-merge was automatically disabled April 11, 2026 08:16

Head branch was pushed to by a user without write access

@VeryEarly
Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines
Copy link
Copy Markdown
Contributor

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Mandatory = true,
ParameterSetName = ParameterSetNames.ByName,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The public IP address name.")]
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
HelpMessage = "The public IP address name.")]
HelpMessage = "The cloud service public IP address name.")]

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +63
[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; }
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +110
### -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
```
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +127 to +140
### -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
```
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +185
### -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
```
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines +1039 to +1047
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"
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
@VeryEarly VeryEarly merged commit 47e2acf into Azure:release-network-2025-07-01 Apr 13, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants