I am trying to fetch a list of non-compliant resources via email for a particular policy across multiple subscriptions. However, I'm currently unable to achieve this. Here's what I've done so far:
The issue is that my current PS script only lists non-compliant resources from a single subscription. What modifications can be made to the PS script to fetch the non-compliant resource list across multiple subscriptions?
Connect-AzAccount -Identity
$policyDefinitionName = "policy-XXXXX"
$complianceState = Get-AzPolicyState -PolicyDefinitionName $policyDefinitionName
$nonCompliantResources = $complianceState | Where-Object { $_.ComplianceState -eq "NonCompliant" }
$csvString = $nonCompliantResources | Select-Object @{Name="SubscriptionName";Expression={(Get-AzSubscription -SubscriptionId $_.SubscriptionId).Name}},
@{Name="ResourceGroup";Expression={($_.ResourceId -split '/')[4]}},
@{Name="ResourceName";Expression={($_.ResourceId -split '/')[8]}},
PolicyDefinitionName | ConvertTo-Csv -NoTypeInformation | Out-String
return $csvString
What modifications can be made to the PS script to fetch the non-compliant resource list across multiple subscriptions?
There are two ways, If the same policy definition is assigned to two different subscriptions, we can filter for each subscription using foreach method in PowerShell, or you can assign the policy at the management group level. The policy will then apply to all subscriptions under the management group
If it's assigned at the management group level, you can fetch using below cmdlet as suggested bywenbo
follow the MS Doc for more details
Note: Make sure to assign the required role at the management group level to the Automation account identity.
Get-AzPolicyState -ManagementGroupName "xxxx" -PolicyDefinitionName $policyDefinitionName
If assigned to a different subscription with the same policy definition name instead of the management group, you can use the approach below.
# Get all subscriptions (you can filter this to a specific set of subscriptions if needed)
$subscriptions = Get-AzSubscription
$allNonCompliantResources = @()
# Loop through each subscription
foreach ($subscription in $subscriptions) {
Set-AzContext -SubscriptionId $subscription.Id
# Get the policy definitions with the specific name you're looking for
$result = Get-AzPolicyDefinition | Where-Object { $_.DisplayName -like "*Allow resources only in North Europe*" }
# Loop through each policy definition (in case there are multiple matching policies)
foreach ($policy in $result) {
# Get the policy state for the current subscription using the PolicyDefinition ID
$complianceState = Get-AzPolicyState -PolicyDefinitionName $policy.Name
# Filter for non-compliant resources and add them to the results array
$nonCompliantResources = $complianceState | Where-Object { $_.ComplianceState -eq "NonCompliant" }
$allNonCompliantResources += $nonCompliantResources
}
}
# Now you have the list of non-compliant resources across all subscriptions
$csvString = $allNonCompliantResources | Select-Object @{
Name="SubscriptionName";
Expression={(Get-AzSubscription -SubscriptionId $_.SubscriptionId).Name}},
@{
Name="ResourceGroup";
Expression={($_.ResourceId -split '/')[4]}},
@{
Name="ResourceName";
Expression={($_.ResourceId -split '/')[8]}},
@{
Name="PolicyDefinitionName";
Expression={$_ | Select-Object -ExpandProperty Name}} |
ConvertTo-Csv -NoTypeInformation | Out-String
# Return the CSV string (this can be used in the Logic App to send an email)
return $csvString
Output
Complaince result