Functions/Get-AHRegulationCompliance.ps1
Function Get-AHRegulationCompliance { <# .SYNOPSIS Gets regulatory compliance of the regulation specified and generates a report showing compliance with each control in the regulation. .DESCRIPTION .PARAMETER AllSubscriptions Run this command against all subscriptions. .PARAMETER Subscription Specifies the subscription to run against. The default is the current subscription. .PARAMETER Regulation Specifies the regulation out of the Regulations.json file to check for compliance with. The file is extensible and easily modified to customize and add additional regulations. .PARAMETER RegulationFile The file that has the regulations stored in it. .PARAMETER Summary Summarize the results .PARAMETER Parallel Enables parallel execution so that all regulations are checked simultaneously. This must not be used at the same time as AllSubscriptions. .EXAMPLE $results = Get-AHRegulationCompliance -Regulation "DoD 800-53R4" -Parallel #This finds regulatory compliance with DoD 800-53R4 for the current subscription. .EXAMPLE $results = Get-AHRegulationCompliance -Regulation "DoD 800-53R4" -AllSubscriptions #This gets regulatory compliance with DoD 800-53R4 across all subscriptions. .EXAMPLE $results = Get-AHRegulationCompliance -Regulation "DoD 800-53R4" -AllSubscriptions -Summary #This gets regulatory compliance with DoD 800-53R4 across all subscriptions then summarizes it by control. This report makes it easy to find how many resources are not compliant with each control in an entire tenant. .INPUTS String .OUTPUTS System.Management.Automation.PSCustomObject .NOTES Author: Paul Harrison #> [CmdletBinding()] param ( [Switch] $AllSubscriptions, [Parameter(ValueFromPipeline = $true)] $Subscription, [string] $Regulation, [string] $RegulationFile = 'C:\GitHub\AzureHelper\Regulations.json', [switch] $Summary, [validatescript( { $_ -and (($PSVersionTable.psversion.major -gt 7 -and $PSVersionTable.psversion.minor -gt 0) -or ($PSVersionTable.psversion.major -eq 7 -and $PSVersionTable.psversion.minor -eq 0 -and $PSVersionTable.psversion.Patch -ge 3)) })] [switch] $Parallel ) # begin { If (!(Test-Path $RegulationFile)) { throw 'Invalid Regulation File' } $Regulations = Get-Content $RegulationFile | ConvertFrom-Json $RegToCheck = $Regulations | Where-Object { $_.Name -eq $Regulation } If ($Null -eq $RegToCheck) { throw "$Regulation not found in $RegulationFile" } $Total = @() $Sub = (Get-AzContext).Subscription.Name $controlCount = 0 $policyCount = 0 $PolicyDefinitions = Get-AzPolicyDefinition #single threaded version If (!$Parallel) { ForEach ($Control in $RegToCheck.Control) { Write-Progress -Activity "Checking for $($RegToCheck.Name) compliance" -Status "Checking $($Control.Name)" -PercentComplete (100 * $controlCount / $($RegToCheck.Control.count)) $policyCount = 0 $subTotal = ForEach ($Policy in $Control.Policy) { Write-Progress -Activity "Checking: $($Policy.Name)" -PercentComplete (100 * $policyCount / $($Control.Policy.count)) -Id 1 $policyCount++ $PolicyDefinitionId = ($PolicyDefinitions | Where-Object { $_.Properties.DisplayName -eq $Policy.Name }).PolicyDefinitionId $PolicyState = Get-AzPolicyState -Filter "PolicyDefinitionId eq '$PolicyDefinitionID'" $item = New-Object PSCustomObject -Property @{ Subscription = $Sub Regulation = $Regulation Control = $Control.Name Policy = $Policy.Name PolicyExists = ($Null -ne $PolicyDefinitionId) NonCompliantCount = ($PolicyState | Where-Object { $_.ComplianceState -eq 'NonCompliant' }).count TotalObjectCount = ($PolicyState).count } $item } $Total += $subTotal $controlCount++ } } Else { #yay multithreading $RegToCheck.Control | ForEach-Object -ThrottleLimit 64 -Parallel { $Control = $_ # Write-Progress -Activity "Checking for $($RegToCheck.Name) compliance" -Status "Checking $($Control.Name)" -PercentComplete (100 * $controlCount / $($using:RegToCheck.Control.count)) $policyCount = 0 ForEach ($Policy in $Control.Policy) { # Write-Progress -Activity "Checking: $($Policy.Name)" -PercentComplete (100 * $policyCount / $($Control.Policy.count)) -Id 1 $policyCount++ $PolicyDefinitionId = ($using:PolicyDefinitions | Where-Object { $_.Properties.DisplayName -eq $Policy.Name }).PolicyDefinitionId $PolicyState = Get-AzPolicyState -Filter "PolicyDefinitionId eq '$PolicyDefinitionID'" $item = New-Object PSCustomObject -Property @{ Subscription = $using:Sub Regulation = $using:Regulation Control = $Control.Name Policy = $Policy.Name PolicyExists = ($Null -ne $PolicyDefinitionId) NonCompliantCount = ($PolicyState | Where-Object { $_.ComplianceState -eq 'NonCompliant' }).count TotalObjectCount = ($PolicyState).count } $item } $Total += $subTotal $controlCount++ } } If (!$Summary) { $Total } Else { $Total | Group-Object -Property Control | Select-Object @{N = 'Subscription'; E = { $Sub } }, @{N = 'Regulation'; E = { $Regulation } }, @{N = 'Control'; E = { $_.Name } }, @{N = 'isCompliant'; E = { $_.count -eq 0 } } } } #} #process { # if ($Subscription) { $Subscription | Invoke-AzureCommand -ScriptBlock $MyScriptBlock <#-ArgumentList $ArgumentList#> } # else { Invoke-AzureCommand -ScriptBlock $MyScriptBlock -AllSubscriptions:$AllSubscriptions <#-ArgumentList $ArgumentList#> } #} #} <# $policyState | Where{$_.ComplianceState -eq 'NonCompliant'}).count 2 PS C:\GitHub\AzureHelper> $policyState = Get-AzPolicyState -Filter "PolicyDefinitionId eq '/providers/Microsoft.Authorization/policyDefinitions/6b1cbf55-e8b6-442f-ba4c-7246b6381474'" PS C:\GitHub\AzureHelper> #> |