Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,12 @@ public void TestVmssLifecycleHookEventEndToEnd()
{
TestRunner.RunTestScript("Test-VmssLifecycleHookEventEndToEnd");
}

[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void TestVmssDisableCapacityReservationAssignment()
{
TestRunner.RunTestScript("Test-VmssDisableCapacityReservationAssignment");
}
}
}
77 changes: 77 additions & 0 deletions src/Compute/Compute.Test/ScenarioTests/StrategiesVmssTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -928,3 +928,80 @@ function Test-VmssLifecycleHookEventEndToEnd
Clean-ResourceGroup $rgname
}
}

<#
.SYNOPSIS
Tests -DisableCapacityReservationAssignment on New-AzVmssConfig/New-AzVmss (both the simple
parameter set and the config+New-AzVmss pipeline), on Update-AzVmss, verifies the resulting
CapacityReservation/CapacityReservationType properties surfaced by Get-AzVmssVM, and validates
that -DisableCapacityReservationAssignment and -CapacityReservationGroupId are mutually exclusive.
#>
function Test-VmssDisableCapacityReservationAssignment
{
# Setup
$vmssname = Get-ResourceName
$loc = Get-ComputeVMLocation

try
{
$username = "admin01"
$password = Get-PasswordForVM | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
[string]$domainNameLabel = "$vmssname$vmssname".tolower();

# Step 1: Simple parameter set - New-AzVmss with -DisableCapacityReservationAssignment directly.
$vmss = New-AzVmss -ResourceGroupName $vmssname -Name $vmssname -Location $loc -Credential $cred `
-DomainNameLabel $domainNameLabel -DisableCapacityReservationAssignment;
Assert-NotNull $vmss.VirtualMachineProfile.CapacityReservation;
Assert-True { $vmss.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment };
Assert-Null $vmss.VirtualMachineProfile.CapacityReservation.CapacityReservationGroup;

# Re-read the VMSS to confirm the setting persisted server-side.
$vmss = Get-AzVmss -ResourceGroupName $vmssname -Name $vmssname;
Assert-True { $vmss.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment };

# Step 2: Verify the VMSS VM (Get-AzVmssVM) surfaces the inherited CapacityReservation property.
$vms = Get-AzVmssVM -ResourceGroupName $vmssname -VMScaleSetName $vmssname;
Assert-True { @($vms).Count -gt 0 };
$vm = @($vms)[0];
Assert-NotNull $vm.CapacityReservation;
Assert-True { $vm.CapacityReservation.DisableCapacityReservationAssignment };

# Verify the instance view surfaces CapacityReservationType.
$vmInstanceView = Get-AzVmssVM -ResourceGroupName $vmssname -VMScaleSetName $vmssname -InstanceId $vm.InstanceId -InstanceView;
Assert-NotNull $vmInstanceView.CapacityReservationType;

# Step 3: Update-AzVmss - toggle DisableCapacityReservationAssignment off, then back on via the PUT path
# (-VirtualMachineScaleSet), and verify merge semantics (other settings on the VMSS remain unaffected).
$current = Get-AzVmss -ResourceGroupName $vmssname -Name $vmssname;
Update-AzVmss -ResourceGroupName $vmssname -VMScaleSetName $vmssname -VirtualMachineScaleSet $current -DisableCapacityReservationAssignment:$false;
$vmss = Get-AzVmss -ResourceGroupName $vmssname -Name $vmssname;
Assert-False { $vmss.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment };

$current = Get-AzVmss -ResourceGroupName $vmssname -Name $vmssname;
Update-AzVmss -ResourceGroupName $vmssname -VMScaleSetName $vmssname -VirtualMachineScaleSet $current -DisableCapacityReservationAssignment;
$vmss = Get-AzVmss -ResourceGroupName $vmssname -Name $vmssname;
Assert-True { $vmss.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment };

# Step 4: New-AzVmssConfig + New-AzVmss pipeline scenario.
$vmssConfig = New-AzVmssConfig -Location $loc -SkuCapacity 1 -SkuName "Standard_DS1_v2" -UpgradePolicyMode "Manual" `
-DisableCapacityReservationAssignment;
Assert-NotNull $vmssConfig.VirtualMachineProfile.CapacityReservation;
Assert-True { $vmssConfig.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment };

# Step 5: Negative test - -CapacityReservationGroupId and -DisableCapacityReservationAssignment are mutually exclusive.
Assert-ThrowsContains { New-AzVmssConfig -Location $loc -CapacityReservationGroupId "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Compute/capacityReservationGroups/crg" -DisableCapacityReservationAssignment } `
"cannot be used together";
Assert-ThrowsContains { Update-AzVmss -ResourceGroupName $vmssname -VMScaleSetName $vmssname -VirtualMachineScaleSet $current -CapacityReservationGroupId "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Compute/capacityReservationGroups/crg" -DisableCapacityReservationAssignment } `
"cannot be used together";

# Negative: PATCH path (no -VirtualMachineScaleSet) must reject -DisableCapacityReservationAssignment.
Assert-ThrowsContains { Update-AzVmss -ResourceGroupName $vmssname -VMScaleSetName $vmssname -DisableCapacityReservationAssignment } `
"CreateOrUpdate path";
}
finally
{
# Cleanup
Clean-ResourceGroup $vmssname
}
}
2 changes: 2 additions & 0 deletions src/Compute/Compute/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
-->
## Upcoming Release
* Updated ComputeRP-related cmdlets to use API version 2026-04-01, DiskRP-related cmdlets to use API version 2026-03-02, and GalleryRP-related cmdlets to use API version 2025-12-03.
* Added `-DisableCapacityReservationAssignment` parameter to `New-AzVmss`, `New-AzVmssConfig`, and `Update-AzVmss` to opt VMSS instances out of capacity reservation assignment.
* Added `CapacityReservation` property to `Get-AzVmssVM` output and `CapacityReservationType` property to its `-InstanceView` output.

## Version 11.8.0
* Deprecated installing the legacy Azure Enhanced Monitoring (AEM) extension for SAP on Virtual Machines (VMs); `Set-AzVMAEMExtension` now installs the new extension by default.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public string ResourceGroupName
public IDictionary<string, string> Tags { get; set; }
public string UserData { get; set; }
public string ResilientVMDeletionStatus { get; set; }
public CapacityReservationProfile CapacityReservation { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public partial class PSVirtualMachineScaleSetVMInstanceView
public IList<InstanceViewStatus> Statuses { get; set; }
public string AssignedHost { get; set; }
public string PlacementGroupId { get; set; }
public string CapacityReservationType { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,11 @@ public partial class NewAzureRmVmssConfigCommand : Microsoft.Azure.Commands.Reso
[ResourceIdCompleter("Microsoft.Compute/capacityReservationGroups")]
public string CapacityReservationGroupId { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "Specifies that the virtual machine scale set instances are explicitly opted out from being associated with any capacity reservation. When set, the instances will not be allowed to implicitly or explicitly associate with any type of capacity reservation and will consume capacity from the publicly available capacity. Minimum api-version: 2026-04-01.")]
public SwitchParameter DisableCapacityReservationAssignment { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "UserData for the VM, which will be Base64 encoded. Customer should not pass any secrets in here.",
Expand Down Expand Up @@ -701,6 +706,24 @@ private void Run()
vVirtualMachineProfile.CapacityReservation.CapacityReservationGroup = new SubResource(this.CapacityReservationGroupId);
}

if (this.IsParameterBound(c => c.DisableCapacityReservationAssignment))
{
if (this.IsParameterBound(c => c.CapacityReservationGroupId))
{
throw new PSArgumentException(
"The -CapacityReservationGroupId and -DisableCapacityReservationAssignment parameters cannot be used together.");
}
if (vVirtualMachineProfile == null)
{
vVirtualMachineProfile = new PSVirtualMachineScaleSetVMProfile();
}
if (vVirtualMachineProfile.CapacityReservation == null)
{
vVirtualMachineProfile.CapacityReservation = new CapacityReservationProfile();
}
vVirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment = this.DisableCapacityReservationAssignment.IsPresent;
}

if (this.IsParameterBound(c => c.AutomaticRepairGracePeriod))
{
if (vAutomaticRepairsPolicy == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ public override void ExecuteCmdlet()
[ResourceIdCompleter("Microsoft.Compute/capacityReservationGroups")]
public string CapacityReservationGroupId { get; set; }

[Parameter(
Mandatory = false,
HelpMessage = "Specifies that the virtual machine scale set instances are explicitly opted out from being associated with any capacity reservation. When set, the instances will not be allowed to implicitly or explicitly associate with any type of capacity reservation and will consume capacity from the publicly available capacity. Minimum api-version: 2026-04-01. This parameter is only supported when updating a Virtual Machine Scale Set via the -VirtualMachineScaleSet object parameter (e.g. piping the output of Get-AzVmss).")]
public SwitchParameter DisableCapacityReservationAssignment { get; set; }

[Parameter(
Mandatory = false)]
[ValidateNotNullOrEmpty]
Expand Down Expand Up @@ -1602,6 +1607,16 @@ void InitializeZoneAllocationPolicy()
"Provide a VirtualMachineScaleSet object via -VirtualMachineScaleSet parameter (e.g., pipe the output of 'Get-AzVmss') when configuring Scheduled Events.");
}

// CapacityReservation is not supported in VirtualMachineScaleSetUpdate (PATCH) model.
// When using the PATCH path (VirtualMachineScaleSet is null), DisableCapacityReservationAssignment
// is not applied and is therefore rejected at runtime.
if (this.IsParameterBound(c => c.DisableCapacityReservationAssignment))
{
throw new PSArgumentException(
"The -DisableCapacityReservationAssignment parameter is only supported when updating a Virtual Machine Scale Set using the CreateOrUpdate path. " +
"Provide a VirtualMachineScaleSet object via -VirtualMachineScaleSet parameter (e.g., pipe the output of 'Get-AzVmss') when configuring capacity reservation.");
}

if (this.IsParameterBound(c => c.ZonalPlatformFaultDomainAlignMode))
{
if (this.VirtualMachineScaleSetUpdate == null)
Expand Down Expand Up @@ -1678,6 +1693,24 @@ private void BuildPutObject()
this.VirtualMachineScaleSet.VirtualMachineProfile.CapacityReservation.CapacityReservationGroup.Id = this.CapacityReservationGroupId;
}

if (this.IsParameterBound(c => c.DisableCapacityReservationAssignment))
{
if (this.IsParameterBound(c => c.CapacityReservationGroupId))
{
throw new PSArgumentException(
"The -CapacityReservationGroupId and -DisableCapacityReservationAssignment parameters cannot be used together.");
}
if (this.VirtualMachineScaleSet.VirtualMachineProfile == null)
{
this.VirtualMachineScaleSet.VirtualMachineProfile = new PSVirtualMachineScaleSetVMProfile();
}
if (this.VirtualMachineScaleSet.VirtualMachineProfile.CapacityReservation == null)
{
this.VirtualMachineScaleSet.VirtualMachineProfile.CapacityReservation = new CapacityReservationProfile();
}
this.VirtualMachineScaleSet.VirtualMachineProfile.CapacityReservation.DisableCapacityReservationAssignment = this.DisableCapacityReservationAssignment.IsPresent;
}

if (this.IsParameterBound(c => c.CustomData))
{
if (this.VirtualMachineScaleSet.VirtualMachineProfile == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ public partial class NewAzureRmVmss : ComputeAutomationBaseCmdlet
[ResourceIdCompleter("Microsoft.Compute/capacityReservationGroups")]
public string CapacityReservationGroupId { get; set; }

[Parameter(
Mandatory = false,
ParameterSetName = SimpleParameterSet,
HelpMessage = "Specifies that the virtual machine scale set instances are explicitly opted out from being associated with any capacity reservation. When set, the instances will not be allowed to implicitly or explicitly associate with any type of capacity reservation and will consume capacity from the publicly available capacity. Minimum api-version: 2026-04-01.")]
public SwitchParameter DisableCapacityReservationAssignment { get; set; }

[Parameter(
Mandatory = false,
ParameterSetName = SimpleParameterSet,
Expand Down Expand Up @@ -597,6 +603,7 @@ private async Task<ResourceConfig<VirtualMachineScaleSet>> SimpleParameterSetNor
edgeZone: _cmdlet.EdgeZone,
orchestrationMode: _cmdlet.IsParameterBound(c => c.OrchestrationMode) ? _cmdlet.OrchestrationMode : null,
capacityReservationId: _cmdlet.IsParameterBound(c => c.CapacityReservationGroupId) ? _cmdlet.CapacityReservationGroupId : null,
disableCapacityReservationAssignment: _cmdlet.IsParameterBound(c => c.DisableCapacityReservationAssignment) ? _cmdlet.DisableCapacityReservationAssignment.IsPresent : (bool?)null,
userData: _cmdlet.IsParameterBound(c => c.UserData) ? _cmdlet.UserData : null,
imageReferenceId: _cmdlet.IsParameterBound(c => c.ImageReferenceId) ? _cmdlet.ImageReferenceId : null,
auxAuthHeader: auxAuthHeader,
Expand Down Expand Up @@ -748,6 +755,7 @@ private async Task<ResourceConfig<VirtualMachineScaleSet>> SimpleParameterSetOrc
edgeZone: _cmdlet.EdgeZone,
orchestrationMode: OrchestrationModes.Flexible,
capacityReservationId: _cmdlet.IsParameterBound(c => c.CapacityReservationGroupId) ? _cmdlet.CapacityReservationGroupId : null,
disableCapacityReservationAssignment: _cmdlet.IsParameterBound(c => c.DisableCapacityReservationAssignment) ? _cmdlet.DisableCapacityReservationAssignment.IsPresent : (bool?)null,
securityType: _cmdlet.SecurityType,
enableVtpm: _cmdlet.EnableVtpm,
enableSecureBoot: _cmdlet.EnableSecureBoot,
Expand All @@ -774,6 +782,12 @@ private async Task<ResourceConfig<VirtualMachineScaleSet>> SimpleParameterSetOrc

async Task SimpleParameterSetExecuteCmdlet(IAsyncCmdlet asyncCmdlet)
{
if (this.IsParameterBound(c => c.DisableCapacityReservationAssignment) && this.IsParameterBound(c => c.CapacityReservationGroupId))
{
throw new PSArgumentException(
"The -CapacityReservationGroupId and -DisableCapacityReservationAssignment parameters cannot be used together.");
}

bool loadBalancerNamePassedIn = !String.IsNullOrWhiteSpace(LoadBalancerName);

ResourceGroupName = ResourceGroupName ?? VMScaleSetName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScale
string edgeZone,
string orchestrationMode,
string capacityReservationId,
bool? disableCapacityReservationAssignment,
string userData,
string imageReferenceId,
Dictionary<string, List<string>> auxAuthHeader,
Expand Down Expand Up @@ -184,9 +185,10 @@ internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScale
Priority = priority,
EvictionPolicy = evictionPolicy,
BillingProfile = (maxPrice == null) ? null : new BillingProfile(maxPrice),
CapacityReservation = (capacityReservationId == null) ? null : new CapacityReservationProfile
CapacityReservation = (capacityReservationId == null && disableCapacityReservationAssignment == null) ? null : new CapacityReservationProfile
{
CapacityReservationGroup = new Microsoft.Azure.Management.Compute.Models.SubResource(capacityReservationId)
CapacityReservationGroup = (capacityReservationId == null) ? null : new Microsoft.Azure.Management.Compute.Models.SubResource(capacityReservationId),
DisableCapacityReservationAssignment = disableCapacityReservationAssignment
},
UserData = userData,
SecurityPostureReference = (securityPostureId != null || securityPostureExcludeExtension != null) ? new SecurityPostureReference
Expand Down Expand Up @@ -269,6 +271,7 @@ internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScale
string edgeZone,
string orchestrationMode,
string capacityReservationId,
bool? disableCapacityReservationAssignment,
Dictionary<string, List<string>> auxAuthHeader,
bool? enableVtpm = null,
bool? enableSecureBoot = null,
Expand Down Expand Up @@ -365,9 +368,10 @@ internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScale
Priority = priority,
EvictionPolicy = evictionPolicy,
BillingProfile = (maxPrice == null) ? null : new BillingProfile(maxPrice),
CapacityReservation = (capacityReservationId == null) ? null : new CapacityReservationProfile
CapacityReservation = (capacityReservationId == null && disableCapacityReservationAssignment == null) ? null : new CapacityReservationProfile
{
CapacityReservationGroup = new Microsoft.Azure.Management.Compute.Models.SubResource(capacityReservationId)
CapacityReservationGroup = (capacityReservationId == null) ? null : new Microsoft.Azure.Management.Compute.Models.SubResource(capacityReservationId),
DisableCapacityReservationAssignment = disableCapacityReservationAssignment
},
SecurityPostureReference = (securityPostureId != null || securityPostureExcludeExtension != null) ? new SecurityPostureReference
{
Expand Down
Loading