setup/backend/Function/code/policymgmt/run.ps1 (155 lines of code) (raw):

using namespace System.Net # Input bindings are passed in via param block. param($Request, $TriggerMetadata) # Write to the Azure Functions log stream. Write-Host "PowerShell HTTP trigger function processed a request." $userIdentityId=$ENV:PacksUserManagedId # Comes from the Function App settings (Configuration) if ([string]::IsNullOrEmpty($userIdentityId)) { "Error - PacksUserManagedId is not set." break } $SolutionTag=$Request.Body.SolutionTag $action=$Request.Body.Action "Action Selected: $action" # Interact with query parameters or the body of the request. switch ($action) { 'Remediate' { "Into selected Remediate action." "Policy List provided? Let's see..." $Request.Body.Policies $policylist=$Request.Body.Policies if ([string]::IsNullOrEmpty($policylist)) { "No policy list provided. Getting all policies and initiatives." $SolutionTag=$env:SolutionTag $polStateQuery=@" policyresources | where ['type'] == 'microsoft.policyinsights/policystates' | extend ComplianceState=tostring(properties.complianceState), PolicySetDefinitionName=tostring(properties.policySetDefinitionName) | where isnotempty(PolicySetDefinitionName) | where ComplianceState =~ "NonCompliant" | summarize by PolicySetDefinitionName | join kind= innerunique (policyresources | where ['type'] =~ "microsoft.authorization/policysetdefinitions" and isnotnull(properties.metadata.MonitorStarterPacks) | project PolicySetDefinitionName=name, PolicySetDefinitionId=id, policyDefinitions=properties.policyDefinitions) on PolicySetDefinitionName | project-away PolicySetDefinitionName1 "@ $inits=Search-AzGraph -Query $polStateQuery -UseTenantScope #$inits=Get-AzPolicySetDefinition | Where-Object {$_.Metadata.$SolutionTag -ne $null} | Where-Object {$_.Name -in $polState.PolicySetDefinitionName} $polStateQuery=@" policyresources | where ['type'] == 'microsoft.policyinsights/policystates' | extend ComplianceState=tostring(properties.complianceState), PolicySetDefinitionName=tostring(properties.policySetDefinitionName), PolicyDefinitionName=tostring(properties.policyDefinitionName) | where ComplianceState =~ "NonCompliant" | summarize by PolicyDefinitionName | join kind= innerunique (policyresources | where ['type'] =~ "microsoft.authorization/policydefinitions" and isnotnull(properties.metadata.MonitorStarterPacks) and properties.metadata.initiativeMember != true | project PolicyDefinitionName=name, PolicyDefinitionId=id) on PolicyDefinitionName | project-away PolicyDefinitionName1 "@ $pols=Search-AzGraph -Query $polStateQuery -UseTenantScope #$pols=Get-AzPolicyDefinition | Where-Object {($_.Metadata.$SolutionTag -ne $null -or $_.Metadata.MonitorStarterPacksComponents -ne $null) -and $_.Metadata.initiativeMember -ne $true} | Where-Object {$_.Name -in $polState.PolicyDefinitionName} "Found $($pols.Count) policies and $($inits.Count) policy sets to remediate" # $pols=Get-AzPolicyDefinition | Where-Object {$_.properties.Metadata.$SolutionTag -ne $null -or $_.properties.Metadata.MonitorStarterPacksComponents -ne $null} # $inits=Get-AzPolicySetDefinition | ? {$_.properties.Metadata.MonitorStarterPacks -ne $null} } else { "Policy list provided. Getting only those policies and initiatives." $pols=Get-AzPolicyDefinition | Where-Object {($_.Metadata.$SolutionTag -ne $null -or $_.Metadata.MonitorStarterPacksComponents -ne $null) -and $_.ResourceId -in $policylist.policyId} $inits=Get-AzPolicySetDefinition | Where-Object {$_.Metadata.MonitorStarterPacks -ne $null -and $_.ResourceId -in $policylist.policyId} } foreach ($pol in $pols) { "Policy $($pol.PolicyDefinitionId) is non-compliant" $assignmentsQuery=@" policyresources | where type == 'microsoft.authorization/policyassignments' | extend policyDefinitionId=properties.policyDefinitionId, Scope=properties.scope | where policyDefinitionId == '$($pol.PolicyDefinitionId)' "@ #$assignments=Get-AzPolicyAssignment -PolicyDefinitionId $pol.PolicyDefinitionId $assignments=Search-AzGraph -Query $assignmentsQuery -UseTenantScope foreach ($assignment in $assignments) { "Starting remediation for $($assignment.DisplayName)" Start-AzPolicyRemediation -Name "$($pol.PolicyDefinitionName) remediation" -PolicyAssignmentId $assignment.id -ResourceDiscoveryMode ExistingNonCompliant -Scope $assignment.Scope } } foreach ($init in $inits) { "Policy set $($init.PolicySetDefinitionId) is non-compliant" #$assignment=Get-AzPolicyAssignment -PolicyDefinitionId $init.PolicySetDefinitionId -Scope "IntermediateRoot" $assignmentsQuery=@" policyresources | where type == 'microsoft.authorization/policyassignments' | extend policyDefinitionId=properties.policyDefinitionId, Scope=properties.scope | where policyDefinitionId == '$($init.PolicySetDefinitionId)' "@ $assignments=Search-AzGraph -Query $assignmentsQuery -UseTenantScope if ($assignments.Count -gt 0) { "Found $($assignments.Count) assignments for $($init.PolicySetDefinitionId)" $policiesInSet=$init.PolicyDefinitions | Select-Object -ExpandProperty policyDefinitionReferenceId #$policiesInSet foreach ($pol in $policiesInSet) { "Starting remediation for $($assignment.Id) policy $pol" foreach ($assignment in $assignments) { Start-AzPolicyRemediation -Name "$($pol) remediation" -PolicyAssignmentId $assignment.Id -PolicyDefinitionReferenceId $pol -Scope $assignment.Scope } } } else { "No assignment found for $($init.PolicySetDefinitionId)" } } } 'Scan' { Start-AzPolicyComplianceScan -AsJob } 'Assign' { "Into selected Assign action." $policies=$Request.Body.policies | ConvertFrom-Json $scopes=$Request.Body.Scopes | ConvertFrom-Json $policies $scopes foreach ($policy in $policies) { $policyName=$policy.Name $policyDefinition=Get-AzPolicyDefinition -Id $policy.PolicyId foreach ($scope in $scopes) { $assignment=New-AzPolicyAssignment -Name "Assign-$policyName" -DisplayName "Assignment-$policyName" -Scope $scope.id ` -PolicyDefinition $policyDefinition -IdentityType UserAssigned -IdentityId $userIdentityId -Location eastus "Created assignment:" $assignment } } } 'Unassign' { "Into selected Assign action." $policies=$Request.Body.policies | ConvertFrom-Json #$scopes=$Request.Body.Scopes | ConvertFrom-Json $policies #$scopes foreach ($policy in $policies) { $policyName=$policy.Name "Scope: $($policy.scope)" "Assignment Name: $($policy.AssignmentName)" "Assignment Level: $($policy.ScopeLevel)" if ($policy.ScopeLevel -eq 'Sub') { $subId=$policy.Scope.split('/')[2] "Sub Id: $subId" if ($subId -ne (get-azcontext).Subscription.Id) { "Changing subscription to $($policy.Scope)." Select-AzSubscription -subscriptionId $subId } } else { "Keeping current context. " } Get-AzPolicyAssignment -Name $policy.AssignmentName -Scope $policy.scope | Remove-AzPolicyAssignment } } 'Default' { "No action specified. Bye." } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $body })