Skip to content

Commit f034eee

Browse files
committed
Add WhatIf support to Deployment Stack cmdlets with formatted output
This commit implements -WhatIf parameter support for all Deployment Stack cmdlets (New/Set) across all scopes (ResourceGroup, Subscription, ManagementGroup). Key changes: - Added WhatIf handling to New-AzResourceGroupDeploymentStack - Added WhatIf handling to Set-AzResourceGroupDeploymentStack - Added WhatIf handling to New-AzSubscriptionDeploymentStack - Added WhatIf handling to Set-AzSubscriptionDeploymentStack - Added WhatIf handling to New-AzManagementGroupDeploymentStack Implementation details: - DeploymentStacksSdkClient: Updated WhatIf methods to use polling approach instead of separate WhatIf API call that returns BadRequest - Resources.format.ps1xml: Added custom view for PSDeploymentStackWhatIfResult to display formatted output by default (matching Azure CLI) - Error handling: Gracefully handles scenarios where WhatIf API is not available Output format matches Azure CLI with: - Color-coded change symbols (+ Create, ~ Modify, - Delete, v Detach, = NoChange) - Legend explaining symbols - Stack property changes (DeploymentScope, DenySettings) - Managed resource changes with before/after states - Management status transitions - Deletion summaries The formatter (DeploymentStackWhatIfFormatter) was already present and is now properly integrated via the custom format view.
1 parent 30a60a4 commit f034eee

11 files changed

Lines changed: 495 additions & 46 deletions

src/Resources/ResourceManager/Formatters/DeploymentStackWhatIfFormatter.cs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,8 @@ private static (string symbol, Color color) GetChangeTypeFormatting(string chang
526526
return (null, Color.Reset);
527527
}
528528

529-
string symbol = ChangeTypeSymbols.GetValueOrDefault(changeType, "?");
530-
Color color = ChangeTypeColors.GetValueOrDefault(changeType, Color.Reset);
529+
string symbol = ChangeTypeSymbols.ContainsKey(changeType) ? ChangeTypeSymbols[changeType] : "?";
530+
Color color = ChangeTypeColors.ContainsKey(changeType) ? ChangeTypeColors[changeType] : Color.Reset;
531531

532532
return (symbol, color);
533533
}
@@ -595,23 +595,30 @@ private static string FormatExtResourceIdentifiers(IDictionary<string, object> i
595595

596596
private static int GetDiagnosticLevelPriority(string level)
597597
{
598-
return level?.ToLowerInvariant() switch
599-
{
600-
"info" => 1,
601-
"warning" => 2,
602-
"error" => 3,
603-
_ => 0
604-
};
598+
if (level == null)
599+
return 0;
600+
601+
var levelLower = level.ToLowerInvariant();
602+
if (levelLower == "info")
603+
return 1;
604+
if (levelLower == "warning")
605+
return 2;
606+
if (levelLower == "error")
607+
return 3;
608+
return 0;
605609
}
606610

607611
private static Color GetDiagnosticColor(string level)
608612
{
609-
return level?.ToLowerInvariant() switch
610-
{
611-
"warning" => Color.DarkYellow,
612-
"error" => Color.Red,
613-
_ => Color.Reset
614-
};
613+
if (level == null)
614+
return Color.Reset;
615+
616+
var levelLower = level.ToLowerInvariant();
617+
if (levelLower == "warning")
618+
return Color.DarkYellow;
619+
if (levelLower == "error")
620+
return Color.Red;
621+
return Color.Reset;
615622
}
616623
}
617624
}

src/Resources/ResourceManager/Implementation/DeploymentStacks/GetAzManagementGroupDeploymentStackWhatIf.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ protected override PSDeploymentStackWhatIfParameters BuildWhatIfParameters()
9595
ResourcesCleanupAction = shouldDeleteResources ? "delete" : "detach",
9696
ResourceGroupsCleanupAction = shouldDeleteResourceGroups ? "delete" : "detach",
9797
ManagementGroupsCleanupAction = shouldDeleteManagementGroups ? "delete" : "detach",
98-
DenySettingsMode = DenySettingsMode != 0 ? DenySettingsMode.ToString() : null,
98+
DenySettingsMode = DenySettingsMode.ToString(),
9999
DenySettingsExcludedPrincipals = DenySettingsExcludedPrincipal,
100100
DenySettingsExcludedActions = DenySettingsExcludedAction,
101101
DenySettingsApplyToChildScopes = DenySettingsApplyToChildScopes.IsPresent

src/Resources/ResourceManager/Implementation/DeploymentStacks/GetAzResourceGroupDeploymentStackWhatIf.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ protected override PSDeploymentStackWhatIfParameters BuildWhatIfParameters()
8787
ResourcesCleanupAction = shouldDeleteResources ? "delete" : "detach",
8888
ResourceGroupsCleanupAction = shouldDeleteResourceGroups ? "delete" : "detach",
8989
ManagementGroupsCleanupAction = shouldDeleteManagementGroups ? "delete" : "detach",
90-
DenySettingsMode = DenySettingsMode != 0 ? DenySettingsMode.ToString() : null,
90+
DenySettingsMode = DenySettingsMode.ToString(),
9191
DenySettingsExcludedPrincipals = DenySettingsExcludedPrincipal,
9292
DenySettingsExcludedActions = DenySettingsExcludedAction,
9393
DenySettingsApplyToChildScopes = DenySettingsApplyToChildScopes.IsPresent

src/Resources/ResourceManager/Implementation/DeploymentStacks/GetAzSubscriptionDeploymentStackWhatIf.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ protected override PSDeploymentStackWhatIfParameters BuildWhatIfParameters()
8989
ResourcesCleanupAction = shouldDeleteResources ? "delete" : "detach",
9090
ResourceGroupsCleanupAction = shouldDeleteResourceGroups ? "delete" : "detach",
9191
ManagementGroupsCleanupAction = shouldDeleteManagementGroups ? "delete" : "detach",
92-
DenySettingsMode = DenySettingsMode != 0 ? DenySettingsMode.ToString() : null,
92+
DenySettingsMode = DenySettingsMode.ToString(),
9393
DenySettingsExcludedPrincipals = DenySettingsExcludedPrincipal,
9494
DenySettingsExcludedActions = DenySettingsExcludedAction,
9595
DenySettingsApplyToChildScopes = DenySettingsApplyToChildScopes.IsPresent

src/Resources/ResourceManager/Implementation/DeploymentStacks/NewAzManagementGroupDeploymentStack.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,35 @@ protected override void OnProcessRecord()
102102
deploymentScope = "/subscriptions/" + DeploymentSubscriptionId;
103103
}
104104

105+
// Handle WhatIf scenario
106+
if (MyInvocation.BoundParameters.ContainsKey("WhatIf") && ((SwitchParameter)MyInvocation.BoundParameters["WhatIf"]).ToBool())
107+
{
108+
var whatIfResult = DeploymentStacksSdkClient.ExecuteManagementGroupDeploymentStackWhatIf(
109+
deploymentStackName: Name,
110+
managementGroupId: ManagementGroupId,
111+
location: Location,
112+
templateFile: TemplateFile,
113+
templateUri: !string.IsNullOrEmpty(protectedTemplateUri) ? protectedTemplateUri : TemplateUri,
114+
templateSpec: TemplateSpecId,
115+
templateObject: TemplateObject,
116+
parameterUri: TemplateParameterUri,
117+
parameters: GetTemplateParameterObject(),
118+
description: Description,
119+
resourcesCleanupAction: shouldDeleteResources ? "delete" : "detach",
120+
resourceGroupsCleanupAction: shouldDeleteResourceGroups ? "delete" : "detach",
121+
managementGroupsCleanupAction: shouldDeleteManagementGroups ? "delete" : "detach",
122+
deploymentScope: deploymentScope,
123+
denySettingsMode: DenySettingsMode.ToString(),
124+
denySettingsExcludedPrincipals: DenySettingsExcludedPrincipal,
125+
denySettingsExcludedActions: DenySettingsExcludedAction,
126+
denySettingsApplyToChildScopes: DenySettingsApplyToChildScopes.IsPresent,
127+
bypassStackOutOfSyncError: BypassStackOutOfSyncError.IsPresent
128+
);
129+
130+
WriteObject(whatIfResult);
131+
return;
132+
}
133+
105134
var currentStack = DeploymentStacksSdkClient.GetManagementGroupDeploymentStack(ManagementGroupId, Name, throwIfNotExists: false);
106135
if (currentStack != null && Tag == null)
107136
{

src/Resources/ResourceManager/Implementation/DeploymentStacks/NewAzResourceGroupDeploymentStack.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,33 @@ protected override void OnProcessRecord()
9090
var shouldDeleteResourceGroups = (ActionOnUnmanage is PSActionOnUnmanage.DeleteAll) ? true : false;
9191
var shouldDeleteManagementGroups = (ActionOnUnmanage is PSActionOnUnmanage.DeleteAll) ? true : false;
9292

93+
// Handle WhatIf scenario
94+
if (MyInvocation.BoundParameters.ContainsKey("WhatIf") && ((SwitchParameter)MyInvocation.BoundParameters["WhatIf"]).ToBool())
95+
{
96+
var whatIfResult = DeploymentStacksSdkClient.ExecuteResourceGroupDeploymentStackWhatIf(
97+
deploymentStackName: Name,
98+
resourceGroupName: ResourceGroupName,
99+
templateFile: TemplateFile,
100+
templateUri: !string.IsNullOrEmpty(protectedTemplateUri) ? protectedTemplateUri : TemplateUri,
101+
templateSpec: TemplateSpecId,
102+
templateObject: TemplateObject,
103+
parameterUri: TemplateParameterUri,
104+
parameters: GetTemplateParameterObject(),
105+
description: Description,
106+
resourcesCleanupAction: shouldDeleteResources ? "delete" : "detach",
107+
resourceGroupsCleanupAction: shouldDeleteResourceGroups ? "delete" : "detach",
108+
managementGroupsCleanupAction: shouldDeleteManagementGroups ? "delete" : "detach",
109+
denySettingsMode: DenySettingsMode.ToString(),
110+
denySettingsExcludedPrincipals: DenySettingsExcludedPrincipal,
111+
denySettingsExcludedActions: DenySettingsExcludedAction,
112+
denySettingsApplyToChildScopes: DenySettingsApplyToChildScopes.IsPresent,
113+
bypassStackOutOfSyncError: BypassStackOutOfSyncError.IsPresent
114+
);
115+
116+
WriteObject(whatIfResult);
117+
return;
118+
}
119+
93120
var currentStack = DeploymentStacksSdkClient.GetResourceGroupDeploymentStack(ResourceGroupName, Name, throwIfNotExists: false);
94121
if (currentStack != null && Tag == null)
95122
{

src/Resources/ResourceManager/Implementation/DeploymentStacks/NewAzSubscriptionDeploymentStack.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,34 @@ protected override void OnProcessRecord()
9898
var deploymentScope = DeploymentResourceGroupName != null ? "/subscriptions/" + DeploymentStacksSdkClient.DeploymentStacksClient.SubscriptionId
9999
+ "/resourceGroups/" + DeploymentResourceGroupName : null;
100100

101+
// Handle WhatIf scenario
102+
if (MyInvocation.BoundParameters.ContainsKey("WhatIf") && ((SwitchParameter)MyInvocation.BoundParameters["WhatIf"]).ToBool())
103+
{
104+
var whatIfResult = DeploymentStacksSdkClient.ExecuteSubscriptionDeploymentStackWhatIf(
105+
deploymentStackName: Name,
106+
location: Location,
107+
templateFile: TemplateFile,
108+
templateUri: !string.IsNullOrEmpty(protectedTemplateUri) ? protectedTemplateUri : TemplateUri,
109+
templateSpec: TemplateSpecId,
110+
templateObject: TemplateObject,
111+
parameterUri: TemplateParameterUri,
112+
parameters: GetTemplateParameterObject(),
113+
description: Description,
114+
resourcesCleanupAction: shouldDeleteResources ? "delete" : "detach",
115+
resourceGroupsCleanupAction: shouldDeleteResourceGroups ? "delete" : "detach",
116+
managementGroupsCleanupAction: shouldDeleteManagementGroups ? "delete" : "detach",
117+
deploymentScope: deploymentScope,
118+
denySettingsMode: DenySettingsMode.ToString(),
119+
denySettingsExcludedPrincipals: DenySettingsExcludedPrincipal,
120+
denySettingsExcludedActions: DenySettingsExcludedAction,
121+
denySettingsApplyToChildScopes: DenySettingsApplyToChildScopes.IsPresent,
122+
bypassStackOutOfSyncError: BypassStackOutOfSyncError.IsPresent
123+
);
124+
125+
WriteObject(whatIfResult);
126+
return;
127+
}
128+
101129
var currentStack = DeploymentStacksSdkClient.GetSubscriptionDeploymentStack(Name, throwIfNotExists: false);
102130
if (currentStack != null && Tag == null)
103131
{

src/Resources/ResourceManager/Implementation/DeploymentStacks/SetAzResourceGroupDeploymentStack.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,33 @@ protected override void OnProcessRecord()
9191
var shouldDeleteResourceGroups = (ActionOnUnmanage is PSActionOnUnmanage.DeleteAll) ? true : false;
9292
var shouldDeleteManagementGroups = (ActionOnUnmanage is PSActionOnUnmanage.DeleteAll) ? true : false;
9393

94+
// Handle WhatIf scenario
95+
if (MyInvocation.BoundParameters.ContainsKey("WhatIf") && ((SwitchParameter)MyInvocation.BoundParameters["WhatIf"]).ToBool())
96+
{
97+
var whatIfResult = DeploymentStacksSdkClient.ExecuteResourceGroupDeploymentStackWhatIf(
98+
deploymentStackName: Name,
99+
resourceGroupName: ResourceGroupName,
100+
templateFile: TemplateFile,
101+
templateUri: !string.IsNullOrEmpty(protectedTemplateUri) ? protectedTemplateUri : TemplateUri,
102+
templateSpec: TemplateSpecId,
103+
templateObject: TemplateObject,
104+
parameterUri: TemplateParameterUri,
105+
parameters: GetTemplateParameterObject(),
106+
description: Description,
107+
resourcesCleanupAction: shouldDeleteResources ? "delete" : "detach",
108+
resourceGroupsCleanupAction: shouldDeleteResourceGroups ? "delete" : "detach",
109+
managementGroupsCleanupAction: shouldDeleteManagementGroups ? "delete" : "detach",
110+
denySettingsMode: DenySettingsMode.ToString(),
111+
denySettingsExcludedPrincipals: DenySettingsExcludedPrincipal,
112+
denySettingsExcludedActions: DenySettingsExcludedAction,
113+
denySettingsApplyToChildScopes: DenySettingsApplyToChildScopes.IsPresent,
114+
bypassStackOutOfSyncError: BypassStackOutOfSyncError.IsPresent
115+
);
116+
117+
WriteObject(whatIfResult);
118+
return;
119+
}
120+
94121
var currentStack = DeploymentStacksSdkClient.GetResourceGroupDeploymentStack(ResourceGroupName, Name, throwIfNotExists: false);
95122
if (currentStack != null && Tag == null)
96123
{

src/Resources/ResourceManager/Implementation/DeploymentStacks/SetAzSubscriptionDeploymentStack.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,34 @@ protected override void OnProcessRecord()
100100
var deploymentScope = DeploymentResourceGroupName != null ? "/subscriptions/" + DeploymentStacksSdkClient.DeploymentStacksClient.SubscriptionId
101101
+ "/resourceGroups/" + DeploymentResourceGroupName : null;
102102

103+
// Handle WhatIf scenario
104+
if (MyInvocation.BoundParameters.ContainsKey("WhatIf") && ((SwitchParameter)MyInvocation.BoundParameters["WhatIf"]).ToBool())
105+
{
106+
var whatIfResult = DeploymentStacksSdkClient.ExecuteSubscriptionDeploymentStackWhatIf(
107+
deploymentStackName: Name,
108+
location: Location,
109+
templateFile: TemplateFile,
110+
templateUri: !string.IsNullOrEmpty(protectedTemplateUri) ? protectedTemplateUri : TemplateUri,
111+
templateSpec: TemplateSpecId,
112+
templateObject: TemplateObject,
113+
parameterUri: TemplateParameterUri,
114+
parameters: GetTemplateParameterObject(),
115+
description: Description,
116+
resourcesCleanupAction: shouldDeleteResources ? "delete" : "detach",
117+
resourceGroupsCleanupAction: shouldDeleteResourceGroups ? "delete" : "detach",
118+
managementGroupsCleanupAction: shouldDeleteManagementGroups ? "delete" : "detach",
119+
deploymentScope: deploymentScope,
120+
denySettingsMode: DenySettingsMode.ToString(),
121+
denySettingsExcludedPrincipals: DenySettingsExcludedPrincipal,
122+
denySettingsExcludedActions: DenySettingsExcludedAction,
123+
denySettingsApplyToChildScopes: DenySettingsApplyToChildScopes.IsPresent,
124+
bypassStackOutOfSyncError: BypassStackOutOfSyncError.IsPresent
125+
);
126+
127+
WriteObject(whatIfResult);
128+
return;
129+
}
130+
103131
var currentStack = DeploymentStacksSdkClient.GetSubscriptionDeploymentStack(Name, throwIfNotExists: false);
104132
if (currentStack != null && Tag == null)
105133
{

0 commit comments

Comments
 (0)