Generate Azure Policy compliance report with resource list

Rakesh Singh 395 Reputation points
2025-02-12T16:28:45.67+00:00

I am looking for a way to generate a report for Azure Policy compliance, which contains azure policies under a targeted Initiative, compliance against each azure policy under this initiative, including compliant and non-compliant resource list.

At the moment, there is not even an export option on the policy portal which allows me to export non-compliant resources against deployed policies, have tried through PowerShell, just not able to get to a level wherein it generates a report including the resource names. Going through the list manually one by one is not ideal or maybe I am missing something.

Please assist.

Regards,
Rakesh Singh

Azure Policy
Azure Policy
An Azure service that is used to implement corporate governance and standards at scale for Azure resources.
1,020 questions
{count} votes

Accepted answer
  1. Naveena Patlolla 3,850 Reputation points Microsoft External Staff Moderator
    2025-02-13T02:44:40.1+00:00

    Hello Rakesh Singh,

    Can you please execute the below PowerShell script

    The script below retrieves details of all resource names, policy definition names, resource groups, subscription names, and locations from all Azure subscriptions.  

    # Login with Connect-AzAccount if not using Cloud Shell
     Connect-AzAccount
    # Initialize an empty array for storing non-compliant resources
    $vmArray = @()
    # Get all Azure subscriptions
    $azureSubscriptions = Get-AzSubscription
    # Loop through each subscription
    foreach ($subscription in $azureSubscriptions) {
        # Set the Azure context to the current subscription
        Set-AzContext -SubscriptionId $subscription.Id
        # Get non-compliant resources for the current subscription
        $nonCompliantResources = Get-AzPolicyState | Where-Object { $_.ComplianceState -eq "NonCompliant" }
        # Output the count of non-compliant resources for the current subscription
        Write-Host "Subscription: $($subscription.Name) - Non-Compliant Resources: $($nonCompliantResources.Count)"
        # Retrieve and process non-compliant resources
        foreach ($resource in $nonCompliantResources) {
            $resourceName = $resource.resourceId.Split('/')[-1]
            $resourceType = $resource.resourceType
            $complianceState = $resource.complianceState
            $resourceGroup = $resource.resourceGroup
            $resourceLocation = $resource.resourceLocation
            $policyDefinitionName = $resource.PolicyDefinitionReferenceId
            # Store resource details in an object
            $vmArray += New-Object PSObject -Property @{
                ResourceType         = $resourceType
                SubscriptionName     = $subscription.Name
                ComplianceState      = $complianceState
                ResourceName         = $resourceName
                ResourceLocation     = $resourceLocation
                PolicyDefinitionName = $policyDefinitionName
                ResourceGroup        = $resourceGroup
            }
        }
    }
    # Export the results to a CSV file
    $vmArray | Export-CSV -Path ".\compliance.csv" -NoTypeInformation
    Write-Host "Compliance report exported to compliance.csv"
    

    Output For Reference:

    image.png

    Feel free to reach out if you have any further questions or need additional information—I’m happy to assist!

    Please provide your valuable comments User's image

    Please do not forget to "Accept the answer” and “upvote it” wherever the information provided helps you, this can be beneficial to other community members.it would be greatly appreciated and helpful to others.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Naveena Patlolla 3,850 Reputation points Microsoft External Staff Moderator
    2025-02-17T03:09:26.6266667+00:00

    Hi @Rakesh Singh

    GoodDay!

    After many attempts, I finally succeeded in adding the column Initiative Name.

    It looks like I am the first to develop this kind of custom script for Azure Policies requirements. It was a really helpful and innovative approach that required thinking outside the box.

    Please find the script and output below.

    <#
    .SYNOPSIS
        This script retrieves non-compliant resources from all Azure subscriptions.
    .DESCRIPTION
        - Connects to Azure using Connect-AzAccount.
        - Retrieves a list of all Azure subscriptions.
        - Iterates through each subscription to fetch non-compliant resources.
        - Fetches associated policy details, including Policy Definition Name and Initiative Display Name.
        - Outputs results in a sorted format.
        - Saves the compliance report to a CSV file.
    .NOTES
        - Requires Az PowerShell Module.
        - User must have appropriate permissions to retrieve policy compliance data.
    #>
    # Login with Connect-AzAccount if not using Cloud Shell
    Connect-AzAccount
    # Initialize an empty array for storing non-compliant resources
    $vmArray = @()
    # Get all Azure subscriptions
    $azureSubscriptions = Get-AzSubscription
    # Loop through each subscription
    foreach ($subscription in $azureSubscriptions) {
        # Set the Azure context to the current subscription
        Set-AzContext -SubscriptionId $subscription.Id
        # Get non-compliant resources for the current subscription
        $nonCompliantResources = Get-AzPolicyState | Where-Object { $_.ComplianceState -eq "NonCompliant" }
        # Output the count of non-compliant resources for the current subscription
        Write-Host "Subscription: $($subscription.Name) - Non-Compliant Resources: $($nonCompliantResources.Count)"
        # Retrieve and process non-compliant resources
        foreach ($resource in $nonCompliantResources) {
            $resourceName = $resource.resourceId.Split('/')[-1]
            $resourceType = $resource.resourceType
            $complianceState = $resource.complianceState
            $resourceGroup = $resource.resourceGroup
            $resourceLocation = $resource.resourceLocation
            $policyDefinitionName = $resource.PolicyDefinitionReferenceId
            $PolicyAssignmentName = $resource.PolicyAssignmentName
            $InitiativeId = $resource.PolicySetDefinitionId  # Get Initiative ID
            $InitiativeName = $resource.PolicySetDefinitionName  # Short Initiative Name
            # Retrieve Initiative Display Name
            $InitiativeDisplayName = $null
            if ($InitiativeId) {
                $initiativeDetails = Get-AzPolicySetDefinition -Id $InitiativeId -ErrorAction SilentlyContinue
                if ($initiativeDetails) {
                    $InitiativeDisplayName = $initiativeDetails.Properties.DisplayName
                }
            }
            # Store resource details in an object
            $vmArray += New-Object PSObject -Property @{
                PolicyDefinitionName  = $policyDefinitionName
                InitiativeDisplayName = $InitiativeDisplayName  # Adding the Display Name
                ComplianceState       = $complianceState
                SubscriptionName      = $subscription.Name
                ResourceGroup         = $resourceGroup
                ResourceName          = $resourceName
                ResourceType          = $resourceType
                ResourceLocation      = $resourceLocation
            }
        }
    }
    # Sort and Export the results to a CSV file
    $vmArray | Sort-Object PolicyDefinitionName, InitiativeDisplayName, ComplianceState, SubscriptionName, ResourceGroup, ResourceName, ResourceType, ResourceLocation | Export-CSV -Path ".\compliance.csv" -NoTypeInformation
    Write-Host "Compliance report exported to compliance.csv"
    

    Please find the output: image.png

    Please do not forget to "Accept the answer” and upvote it wherever the information provided helps you, this can be beneficial to other community members.it would be greatly appreciated and helpful to others.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.