Skip to content

Commit c182350

Browse files
authored
[Az.Resources Policy] Add -NonComplianceMessage to Set/New-AzPolicyAssignment (#15060)
* Model changes * Update help docs * Re-record tests * Fix examples * Addressing mentat9 comments
1 parent 4f75001 commit c182350

File tree

44 files changed

+13648
-8876
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+13648
-8876
lines changed

src/Resources/ResourceManager/Components/Constants.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,17 @@ public static class Constants
8787
/// <summary>
8888
/// The default policy definition API version.
8989
/// </summary>
90-
public static readonly string PolicyDefinitionApiVersion = "2019-09-01";
90+
public static readonly string PolicyDefinitionApiVersion = "2020-09-01";
9191

9292
/// <summary>
9393
/// The default policy set definition API version.
9494
/// </summary>
95-
public static readonly string PolicySetDefintionApiVersion = "2019-09-01";
95+
public static readonly string PolicySetDefintionApiVersion = "2020-09-01";
9696

9797
/// <summary>
9898
/// The default policy assignment API version.
9999
/// </summary>
100-
public static readonly string PolicyAssignmentApiVersion = "2019-09-01";
100+
public static readonly string PolicyAssignmentApiVersion = "2020-09-01";
101101

102102
/// <summary>
103103
/// The default policy exemption API version.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Policy
16+
{
17+
using Newtonsoft.Json;
18+
19+
/// <summary>
20+
/// The policy assignment non compliance message used to describe why a resource is non-compliant with a policy.
21+
/// </summary>
22+
public class NonComplianceMessage
23+
{
24+
/// <summary>
25+
/// The message that describes why a resource is non-compliant with the policy. This is shown in 'deny' error messages and
26+
/// on resource's non-compliant compliance results.
27+
/// </summary>
28+
[JsonProperty(Required = Required.Default)]
29+
public string Message { get; set; }
30+
31+
/// <summary>
32+
/// The policy definition reference ID within a policy set definition that the message is intended for. This is only applicable if
33+
/// the policy assignment assigns a policy set definition. If this is not provided the message applies to all policies assigned by this
34+
/// policy assignment.
35+
/// </summary>
36+
[JsonProperty(Required = Required.Default)]
37+
public string PolicyDefinitionReferenceId { get; set; }
38+
}
39+
}

src/Resources/ResourceManager/Entities/Policy/PolicyAssignmentProperties.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,11 @@ public class PolicyAssignmentProperties
6969
/// </summary>
7070
[JsonProperty(Required = Required.Default)]
7171
public JObject Parameters { get; set; }
72+
73+
/// <summary>
74+
/// The non-compliance messages used to describe why a resource is non-compliant with the policy.
75+
/// </summary>
76+
[JsonProperty(Required = Required.Default)]
77+
public NonComplianceMessage[] NonComplianceMessages { get; set; }
7278
}
7379
}

src/Resources/ResourceManager/Implementation/Policy/NewAzurePolicyAssignment.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
1616
{
1717
using System;
1818
using System.Collections;
19+
using System.Linq;
1920
using System.Management.Automation;
2021

2122
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
@@ -74,7 +75,6 @@ public class NewAzurePolicyAssignmentCmdlet : PolicyCmdletBase, IDynamicParamete
7475
/// <summary>
7576
/// Gets or sets the policy assignment policy definition parameter.
7677
/// </summary>
77-
[CmdletParameterBreakingChange("PolicyDefinition", OldParamaterType = typeof(PSObject), NewParameterTypeName = "PsPolicyDefinition")]
7878
[Parameter(Mandatory = false, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicyDefinitionHelp)]
7979
[Parameter(ParameterSetName = PolicyCmdletBase.DefaultParameterSet, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicyDefinitionHelp)]
8080
[Parameter(ParameterSetName = PolicyCmdletBase.PolicyParameterObjectParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicyDefinitionHelp)]
@@ -84,7 +84,6 @@ public class NewAzurePolicyAssignmentCmdlet : PolicyCmdletBase, IDynamicParamete
8484
/// <summary>
8585
/// Gets or sets the policy assignment policy set definition parameter.
8686
/// </summary>
87-
[CmdletParameterBreakingChange("PolicySetDefinition", OldParamaterType = typeof(PSObject), NewParameterTypeName = "PsPolicySetDefinition")]
8887
[Parameter(Mandatory = false, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicySetDefinitionHelp)]
8988
[Parameter(ParameterSetName = PolicyCmdletBase.DefaultParameterSet, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicySetDefinitionHelp)]
9089
[Parameter(ParameterSetName = PolicyCmdletBase.PolicySetParameterObjectParameterSet, Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.NewPolicyAssignmentPolicySetDefinitionHelp)]
@@ -133,6 +132,13 @@ public class NewAzurePolicyAssignmentCmdlet : PolicyCmdletBase, IDynamicParamete
133132
[LocationCompleter("Microsoft.ManagedIdentity/userAssignedIdentities")]
134133
public string Location { get; set; }
135134

135+
/// <summary>
136+
/// Gets or sets the messages that describe why a resource is non-compliant with the policy.
137+
/// </summary>
138+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.PolicyAssignmentNonComplianceMessageHelp)]
139+
[ValidateNotNull]
140+
public PsNonComplianceMessage[] NonComplianceMessage { get; set; }
141+
136142
/// <summary>
137143
/// Executes the cmdlet.
138144
/// </summary>
@@ -206,7 +212,8 @@ private JToken GetResource()
206212
NotScopes = this.NotScope ?? null,
207213
Metadata = this.Metadata == null ? null : this.GetObjectFromParameter(this.Metadata, nameof(this.Metadata)),
208214
EnforcementMode = EnforcementMode ?? PolicyAssignmentEnforcementMode.Default,
209-
Parameters = this.GetParameters(this.PolicyParameter, this.PolicyParameterObject)
215+
Parameters = this.GetParameters(this.PolicyParameter, this.PolicyParameterObject),
216+
NonComplianceMessages = this.NonComplianceMessage?.Where(message => message != null).SelectArray(message => message.ToModel())
210217
}
211218
};
212219

src/Resources/ResourceManager/Implementation/Policy/PolicyHelpStrings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public static class PolicyHelpStrings
5454
public const string SetPolicyAssignmentInputObjectHelp = "The policy assignment object to update that was output from another cmdlet.";
5555
public const string PolicyAssignmentAssignIdentityHelp = "Generate and assign an Azure Active Directory Identity for this policy assignment. The identity will be used when executing deployments for 'deployIfNotExists' and 'modify' policies. Location is required when assigning an identity.";
5656
public const string PolicyAssignmentLocationHelp = "The location of the policy assignment's resource identity. This is required when the -AssignIdentity switch is used.";
57+
public const string PolicyAssignmentNonComplianceMessageHelp = "The non-compliance messages that describe why a resource is non-compliant with the policy.";
5758

5859
/// <summary>
5960
/// Policy definition cmdlet parameter help strings
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy
2+
{
3+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Policy;
4+
using Newtonsoft.Json.Linq;
5+
6+
/// <summary>
7+
/// The policy assignment non compliance message used to describe why a resource is non-compliant with a policy.
8+
/// </summary>
9+
public class PsNonComplianceMessage
10+
{
11+
/// <summary>
12+
/// Creates an instance of <see cref="PsNonComplianceMessage"/>.
13+
/// </summary>
14+
public PsNonComplianceMessage()
15+
{
16+
}
17+
18+
/// <summary>
19+
/// Creates an instance of <see cref="PsNonComplianceMessage"/> from the equivalent model representation.
20+
/// </summary>
21+
/// <param name="messageModel">The non-compliance message model.</param>
22+
public PsNonComplianceMessage(NonComplianceMessage messageModel)
23+
{
24+
this.Message = messageModel.Message;
25+
this.PolicyDefinitionReferenceId = messageModel.PolicyDefinitionReferenceId;
26+
}
27+
28+
/// <summary>
29+
/// The message that describes why a resource is non-compliant with the policy. This is shown in 'deny' error messages and
30+
/// on resource's non-compliant compliance results.
31+
/// </summary>
32+
public string Message { get; set; }
33+
34+
/// <summary>
35+
/// The policy definition reference ID within a policy set definition that the message is intended for. This is only applicable if
36+
/// the policy assignment assigns a policy set definition. If this is not provided the message applies to all policies assigned by this
37+
/// policy assignment.
38+
/// </summary>
39+
public string PolicyDefinitionReferenceId { get; set; }
40+
41+
/// <summary>
42+
/// Convert to JSON
43+
/// </summary>
44+
/// <returns>JSON representatnion of the non-compliance message.</returns>
45+
public JToken ToJToken()
46+
{
47+
var returnValue = new JObject();
48+
if (this.Message != null)
49+
{
50+
returnValue["message"] = this.Message;
51+
}
52+
53+
if (this.PolicyDefinitionReferenceId != null)
54+
{
55+
returnValue["policyDefinitionReferenceId"] = this.PolicyDefinitionReferenceId;
56+
}
57+
58+
return returnValue;
59+
}
60+
61+
/// <summary>
62+
/// Converts the powershell model to the entity model.
63+
/// </summary>
64+
public NonComplianceMessage ToModel()
65+
{
66+
return new NonComplianceMessage
67+
{
68+
Message = this.Message,
69+
PolicyDefinitionReferenceId = this.PolicyDefinitionReferenceId
70+
};
71+
}
72+
}
73+
}

src/Resources/ResourceManager/Implementation/Policy/PsPolicyAssignment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
using Newtonsoft.Json.Linq;
99

1010
/// <summary>
11-
/// Class that wraps a policy definition PSObject
11+
/// Class that wraps a policy assignment PSObject
1212
/// </summary>
1313
public class PsPolicyAssignment
1414
{

src/Resources/ResourceManager/Implementation/Policy/PsPolicyAssignmentProperties.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy
22
{
3+
using System.Linq;
34
using System.Management.Automation;
4-
55
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.Policy;
66
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
77

@@ -23,6 +23,10 @@ public PsPolicyAssignmentProperties(JToken input)
2323
EnforcementMode = (PsPolicyAssignmentEnforcementMode)properties.EnforcementMode;
2424
PolicyDefinitionId = properties.PolicyDefinitionId;
2525
Parameters = properties.Parameters.ToPsObject();
26+
NonComplianceMessages = properties
27+
.NonComplianceMessages?
28+
.Where(message => message != null)
29+
.SelectArray(message => new PsNonComplianceMessage(message));
2630
}
2731

2832
/// <summary>
@@ -65,6 +69,11 @@ public PsPolicyAssignmentProperties(JToken input)
6569
/// </summary>
6670
public PSObject Parameters { get; set; }
6771

72+
/// <summary>
73+
/// The non-compliance messages used to describe why a resource is non-compliant with the policy.
74+
/// </summary>
75+
public PsNonComplianceMessage[] NonComplianceMessages { get; set; }
76+
6877
/// <summary>
6978
/// Convert to JSON
7079
/// </summary>
@@ -109,6 +118,11 @@ public JToken ToJToken()
109118
returnValue["parameters"] = this.Parameters.ToJToken();
110119
}
111120

121+
if (this.NonComplianceMessages != null)
122+
{
123+
returnValue["nonComplianceMessages"] = this.NonComplianceMessages.ToJToken();
124+
}
125+
112126
return returnValue;
113127
}
114128
}

src/Resources/ResourceManager/Implementation/Policy/SetAzurePolicyAssignment.cs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
1616
{
1717
using System;
1818
using System.Collections;
19+
using System.Linq;
1920
using System.Management.Automation;
2021

2122
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
@@ -130,6 +131,13 @@ public class SetAzurePolicyAssignmentCmdlet : PolicyCmdletBase
130131
[Parameter(ParameterSetName = PolicyCmdletBase.InputObjectParameterSet, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.SetPolicyAssignmentInputObjectHelp)]
131132
public PsPolicyAssignment InputObject { get; set; }
132133

134+
/// <summary>
135+
/// Gets or sets the messages that describe why a resource is non-compliant with the policy.
136+
/// </summary>
137+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = PolicyHelpStrings.PolicyAssignmentNonComplianceMessageHelp)]
138+
[ValidateNotNull]
139+
public PsNonComplianceMessage[] NonComplianceMessage { get; set; }
140+
133141
/// <summary>
134142
/// Executes the cmdlet.
135143
/// </summary>
@@ -166,7 +174,7 @@ protected override void OnProcessRecord()
166174
/// </summary>
167175
private JToken GetResource(string resourceId, string apiVersion)
168176
{
169-
var resource = this.GetExistingResource(resourceId, apiVersion).Result.ToResource();
177+
var resource = this.GetExistingResource(resourceId, apiVersion).Result.ToResource<PolicyAssignmentProperties>();
170178

171179
// get incoming object properties if present
172180
JObject inputMetadata = null;
@@ -178,36 +186,42 @@ private JToken GetResource(string resourceId, string apiVersion)
178186

179187
var parameterMetadata = this.Metadata != null ? this.GetObjectFromParameter(this.Metadata, nameof(this.Metadata)) : null;
180188

181-
PolicyAssignmentEnforcementMode? existingMode = null;
182-
if (Enum.TryParse(resource.Properties["enforcementMode"]?.ToString(), true, out PolicyAssignmentEnforcementMode tempMode))
183-
{
184-
existingMode = tempMode;
185-
}
186-
187189
PolicyAssignmentEnforcementMode? inputMode = null;
188190
if (Enum.TryParse(this.InputObject?.Properties?.EnforcementMode?.ToString(), true, out PolicyAssignmentEnforcementMode tempMode1))
189191
{
190192
inputMode = tempMode1;
191193
}
192194

195+
// Grab the non-compliance messages from the parameter or input object or existing resource
196+
var nonComplianceMessages = this.NonComplianceMessage?.Where(message => message != null).SelectArray(message => message.ToModel());
197+
if (nonComplianceMessages == null && this.InputObject?.Properties.NonComplianceMessages != null)
198+
{
199+
nonComplianceMessages = this.InputObject.Properties.NonComplianceMessages.Where(message => message != null).SelectArray(message => message.ToModel());
200+
}
201+
else if (nonComplianceMessages == null)
202+
{
203+
nonComplianceMessages = resource.Properties.NonComplianceMessages;
204+
}
205+
193206
var policyAssignmentObject = new PolicyAssignment
194207
{
195208
Name = this.Name ?? this.InputObject?.Name ?? resource.Name,
196209
Identity = this.AssignIdentity.IsPresent ? new ResourceIdentity { Type = ResourceIdentityType.SystemAssigned } : null,
197210
Location = this.Location ?? this.InputObject?.Location ?? resource.Location,
198211
Properties = new PolicyAssignmentProperties
199212
{
200-
DisplayName = this.DisplayName ?? this.InputObject?.Properties?.DisplayName ?? resource.Properties["displayName"]?.ToString(),
201-
Description = this.Description ?? this.InputObject?.Properties?.Description ?? resource.Properties["description"]?.ToString(),
202-
Scope = resource.Properties["scope"]?.ToString(),
203-
NotScopes = this.NotScope ?? this.InputObject?.Properties?.NotScopes ?? resource.Properties["NotScopes"]?.ToString()?.Split(','),
204-
PolicyDefinitionId = resource.Properties["policyDefinitionId"]?.ToString(),
205-
Metadata = parameterMetadata ?? inputMetadata ?? resource.Properties["metadata"] as JObject,
206-
EnforcementMode = this.EnforcementMode ?? inputMode ?? existingMode,
213+
DisplayName = this.DisplayName ?? this.InputObject?.Properties?.DisplayName ?? resource.Properties.DisplayName,
214+
Description = this.Description ?? this.InputObject?.Properties?.Description ?? resource.Properties.Description,
215+
Scope = resource.Properties.Scope,
216+
NotScopes = this.NotScope ?? this.InputObject?.Properties?.NotScopes ?? resource.Properties.NotScopes,
217+
PolicyDefinitionId = resource.Properties.PolicyDefinitionId,
218+
Metadata = parameterMetadata ?? inputMetadata ?? resource.Properties.Metadata,
219+
EnforcementMode = this.EnforcementMode ?? inputMode ?? resource.Properties.EnforcementMode,
220+
NonComplianceMessages = nonComplianceMessages,
207221
Parameters =
208222
this.GetParameters(this.PolicyParameter, this.PolicyParameterObject)
209223
?? this.InputObject?.Properties?.Parameters?.ToResourcePropertiesBody() as JObject
210-
?? resource.Properties["parameters"] as JObject
224+
?? resource.Properties.Parameters
211225
}
212226
};
213227

0 commit comments

Comments
 (0)