Framework/Core/SVT/SubscriptionCore/SubscriptionCore.ps1

#using namespace Microsoft.Azure.Commands.Search.Models
Set-StrictMode -Version Latest 
class SubscriptionCore: SVTBase
{       
    hidden [AzureSecurityCenter] $ASCSettings
    hidden [ManagementCertificate[]] $ManagementCertificates
    hidden [PSObject] $RoleAssignments    
    hidden [PSObject] $ApprovedAdmins;
    hidden [PSObject] $MandatoryAccounts;
    hidden [PSObject] $DeprecatedAccounts;
    hidden [PSObject] $CurrentContext;
    hidden [bool] $HasGraphAPIAccess;

    
    SubscriptionCore([string] $subscriptionId): 
        Base($subscriptionId) 
    { 
        $this.GetResourceObject();
    }

    hidden [void] GetResourceObject()
    {
        $this.ASCSettings = [AzureSecurityCenter]::new()
        $this.CurrentContext = Get-AzureRmContext -ErrorAction Ignore
        $this.MandatoryAccounts = $null
        $this.RoleAssignments = $null
        $this.ApprovedAdmins = $null
        $this.DeprecatedAccounts = $null 
        $this.HasGraphAPIAccess = [RoleAssignmentHelper]::HasGraphAccess()
    }
    hidden [ControlResult] CheckSubscriptionAdminCount([ControlResult] $controlResult)
    {
        $this.GetRoleAssignments()
        $this.LoadRBACConfig()        

        #Excessive number of admins (> 5)

        $scope = $this.SubscriptionContext.Scope;
        
        $SubAdmins = @();
        $SubAdmins += $this.RoleAssignments | Where-Object { $_.RoleDefinitionName -eq 'CoAdministrator' `
                                                                                -or $_.RoleDefinitionName -like '*ServiceAdministrator*' `
                                                                                -or ($_.RoleDefinitionName -eq 'Owner' -and $_.Scope -eq $scope)}

        if($this.HasGraphAPIAccess -eq $false)
        {
            $this.PublishCustomMessage("Current Azure login context doesn't have graph api access");
        }
        $ClientSubAdmins = @()    
        $ApprovedSubAdmins = @()                
                
        $SubAdmins | ForEach-Object{
            $tempAdmin = $_
            $objId = $_.ObjectId
            $isApprovedAdmin = $false
            foreach($admin in $this.ApprovedAdmins)
            {
                $tempObjId = $admin.ObjectId
                if($admin.ObjectType -eq "ServicePrincipal")
                {
                    $out = $null
                    #do we need to check for scope
                    try { $out = $this.RoleAssignments | Where-Object { $_.ObjectId -eq $admin.ObjectId} } catch {}
                    if($null -ne $out)
                    {
                        $tempObjId = $out[0].ObjectId
                    }
                }     
                if($objId -eq $tempObjId)
                {
                    $ApprovedSubAdmins += $tempAdmin
                    $isApprovedAdmin = $true
                }                                             
            }
            if(-not $isApprovedAdmin)
            {
                $ClientSubAdmins += $tempAdmin
            }  
        }

        #$controlResult.AddMessage("There are a total of $($SubAdmins.Count) admin/owner accounts in your subscription`r`nOf these, the following $($ClientSubAdmins.Count) admin/owner accounts are not from a central team.", ($ClientSubAdmins | Select-Object DisplayName,SignInName,ObjectType, ObjectId), $true, "ClientSubAdmins");
        $controlResult.AddMessage("There are a total of $($SubAdmins.Count) admin/owner accounts in your subscription`r`nOf these, the following $($ClientSubAdmins.Count) admin/owner accounts are not from a central team.", ($ClientSubAdmins | Select-Object DisplayName,SignInName,ObjectType, ObjectId));        
        
        if(($ApprovedSubAdmins | Measure-Object).Count -gt 0)
        {
            #$controlResult.AddMessage("The following $($ApprovedSubAdmins.Count) admin/owner (approved) accounts are from a central team:`r`n", ($ApprovedSubAdmins | Select-Object DisplayName, SignInName, ObjectType, ObjectId), $true, "ApprovedSubAdmins");
            $controlResult.AddMessage("The following $($ApprovedSubAdmins.Count) admin/owner (approved) accounts are from a central team:`r`n", ($ApprovedSubAdmins | Select-Object DisplayName, SignInName, ObjectType, ObjectId));
        }
        $controlResult.AddMessage("Note: Approved central team accounts don't count against your limit");        

        #$ClientSubAdminsState = $this.GetControlState("ClientSubAdmins", $this.CurrentControlItem.ControlID)
        #[bool] $IsStateCheckEnabled = $true
        #[bool] $isMatch = $true;
        #if($ClientSubAdminsState -ne $null -and ($ClientSubAdminsState | Get-Member DataObject) -ne $null -and $ClientSubAdminsState.DataObject -ne $null -and ($ClientSubAdminsState.DataObject | Measure-Object).Count -gt 0)
        #{
        # if($ClientSubAdminsState.DataObject.Count -eq ($ClientSubAdmins | Measure-Object).Count)
        # {
        # $ClientSubAdmins | ForEach-Object {
        # $clientSubAdmin = $_
        # if(($ClientSubAdminsState.DataObject.value | Where-Object { $_.ObjectId -eq $clientSubAdmin.ObjectId} | Measure-Object).Count -le 0)
        # {
        # $isMatch = $false
        # }
        # }
        # }
        # else
        # {
        # $isMatch = $false
        # }
        #}
        #if($isMatch)
        #{
        # $ApprovedSubAdminsState = $this.GetControlState("ApprovedSubAdmins", $this.CurrentControlItem.ControlID)
        # if($ApprovedSubAdminsState -ne $null -and ($ApprovedSubAdminsState | Get-Member DataObject) -ne $null -and $ApprovedSubAdminsState.DataObject -ne $null -and ($ApprovedSubAdminsState.DataObject | Measure-Object).Count -gt 0)
        # {
        # if($ApprovedSubAdminsState.DataObject.Count -eq ($ApprovedSubAdmins | Measure-Object).Count)
        # {
        # $ApprovedSubAdmins | ForEach-Object {
        # $approvedSubAdmin = $_
        # if(($ApprovedSubAdminsState.DataObject.value | Where-Object { $_.ObjectId -eq $approvedSubAdmin.ObjectId} | Measure-Object).Count -le 0)
        # {
        # $isMatch = $false
        # }
        # }
        # }
        # else
        # {
        # $isMatch = $false
        # }
        # }
        #}
        if($ClientSubAdmins.Count -gt $this.ControlSettings.NoOfApprovedAdmins)
        {
            $controlResult.VerificationResult = [VerificationResult]::Failed
            $controlResult.AddMessage("Number of admins/owners configured at subscription scope are more than the approved limit: $($this.ControlSettings.NoOfApprovedAdmins). Total: " + $ClientSubAdmins.Count);
        }
        else {
            $controlResult.AddMessage([VerificationResult]::Passed,
                                        "Number of admins/owners configured at subscription scope are with in approved limit: $($this.ControlSettings.NoOfApprovedAdmins). Total: " + $ClientSubAdmins.Count);  
        } 
                       
        return $controlResult;
    }

    hidden [ControlResult] CheckApprovedCentralAccountsRBAC([ControlResult] $controlResult)
    {
        $this.GetRoleAssignments()
        $this.LoadRBACConfig()
        $state = $true        
        $scope = $this.SubscriptionContext.Scope
        $out = $null       
        $missingMandatoryAccount = @()                           
        $foundMandatoryAccount = @()                           
        if($null -ne $this.MandatoryAccounts)
        {                    
            foreach($admin in $this.MandatoryAccounts)
            {                        
                try{ $out = $this.RoleAssignments | Where-Object { $_.ObjectId -eq $admin.ObjectId -and $_.Scope -eq $scope -and $_.RoleDefinitionName -eq $admin.RoleDefinitionName }} catch { }
                if($null -eq  $out)
                {  
                    $missingMandatoryAccount+= $admin
                    $state = $false                                                                          
                }
                else
                {
                    $foundMandatoryAccount += $admin
                }     
            }
            if(($foundMandatoryAccount | Measure-Object).Count -gt 0)
            {
                #$controlResult.AddMessage("Found mandatory accounts:",$foundMandatoryAccount, $true, "FoundMandatoryAccounts")
                $controlResult.AddMessage("Found mandatory accounts:",$foundMandatoryAccount)
            }
            if(($missingMandatoryAccount | Measure-Object).Count -gt 0)
            {
                #$controlResult.AddMessage("Missing mandatory accounts:",$missingMandatoryAccount, $true, "MissingMandatoryAccounts")
                $controlResult.AddMessage("Missing mandatory accounts:",$missingMandatoryAccount)
            }
        }
        if(-not $state)
        {            
            $controlResult.VerificationResult = [VerificationResult]::Failed;
        }
        else {            
            $controlResult.VerificationResult = [VerificationResult]::Passed            
        }
        return $controlResult
    }

    hidden [ControlResult] CheckDeprecatedAccountsRBAC([ControlResult] $controlResult)
    {
        $this.GetRoleAssignments()
        $this.LoadRBACConfig()
        $state = $true        
        $scope = $this.SubscriptionContext.Scope    
        $depCounter = 0  
        $out = $null  
        $foundDeprecatedAccounts = @()                                  
        if($null -ne  $this.DeprecatedAccounts)
        {                    
            foreach($depAcct in $this.DeprecatedAccounts)
            {                        
                try{ $out = $this.RoleAssignments | Where-Object { $_.ObjectId -eq $depAcct.ObjectId} } catch { }
                if($null -ne $out)
                {  
                    #$controlResult.AddMessage("`r`nFound deprecated account: [User] [$($depAcct.Name )] Type:[$($depAcct.ObjectType)]",$out)
                    $foundDeprecatedAccounts += $depAcct
                    $depCounter++
                    $state = $false                                                                          
                }       
            }                                                           
        }
        if(-not $state)
        {
            #$controlResult.AddMessage([VerificationResult]::Failed, "Found deprecated accounts on the subscription:", $foundDeprecatedAccounts, $true, "DeprecatedAccounts")
            $controlResult.AddMessage([VerificationResult]::Failed, "Found deprecated accounts on the subscription:", $foundDeprecatedAccounts)
        }
        else {
            $controlResult.VerificationResult = [VerificationResult]::Passed
        }        
        return $controlResult
    }

    hidden [ControlResult] CheckNonAADAccountsRBAC([ControlResult] $controlResult)
    {
        if($this.HasGraphAPIAccess)
        {  
            $this.GetRoleAssignments()       
            Set-Variable -Name liveAccounts -Scope Local

            $liveAccounts = [array]($this.RoleAssignments | Where-Object {$_.SignInName -like '*#EXT#@*.onmicrosoft.com'} )
            
            if(($liveAccounts | Measure-Object).Count -gt 0)
            {
                $controlResult.AddMessage([VerificationResult]::Failed, "Found non-AAD account access present on the subscription:",($liveAccounts | Select-Object SignInName,DisplayName, Scope, RoleDefinitionName))
                #$controlResult.AddMessage([VerificationResult]::Failed, "Found non-AAD account access present on the subscription:",($liveAccounts | Select-Object SignInName,DisplayName, Scope, RoleDefinitionName), $true, "NonAADAccounts")
                $controlResult.VerificationResult =[VerificationResult]::Failed
            }
            else {
                $controlResult.VerificationResult =[VerificationResult]::Passed
            }
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual, "Not able to query Graph API. This has to be manually verified.");
        }
          
        return $controlResult
    }

    hidden [ControlResult] CheckSVCAccountsRBAC([ControlResult] $controlResult)
    {
        if($this.HasGraphAPIAccess)
        {      
            $this.GetRoleAssignments()
            $serviceAccounts = @()
            if($null -ne $this.CurrentContext)
            {    
                $GraphAccessToken = [Helpers]::GetAccessToken([WebRequestHelper]::GraphAPIUri)
            }
    
            $uniqueUsers = @();
            $uniqueUsers += $this.RoleAssignments | Sort-Object SignInName -Unique | Select-Object DisplayName, SignInName,ObjectId, ObjectType
            $uniqueUsers | ForEach-Object{
                Set-Variable -Name user -Scope Local -Value $_
                Set-Variable -Name ObjectId -Scope Local -Value $_.ObjectId
                Set-Variable -Name SignInName -Scope Local -Value $_.SignInName
                Set-Variable -Name ObjectType -Scope Local -Value $_.ObjectType            
                $isServiceAccount = [IdentityHelpers]::IsServiceAccount($_.ObjectId, $_.SignInName, $_.ObjectType, $GraphAccessToken)
                if($isServiceAccount)
                {
                    $userScopes = $this.RoleAssignments | Where-Object {$_.SignInName -eq $SignInName}
                    $userScopes | ForEach-Object{
                        Set-Variable -Name userScope -Scope Local -Value $_
                        $serviceAccounts += $userScope
                    } 
                }
            }

            if(($serviceAccounts | Measure-Object).Count -gt 0)
            {
                $serviceAccounts = $serviceAccounts | Where-Object {-not ($_.SignInName -like 'Sc-*')}                
            }
                
            if(($serviceAccounts | Measure-Object).Count -gt 0)
            {
                #$controlResult.AddMessage([VerificationResult]::Failed, "Found non-MFA enabled accounts present on the subscription",($serviceAccounts | Select-Object Scope, DisplayName, SignInName, RoleDefinitionName, ObjectId, ObjectType), $true, "NonMFAAccounts")
                $controlResult.AddMessage([VerificationResult]::Failed, "Found non-MFA enabled accounts present on the subscription",($serviceAccounts | Select-Object Scope, DisplayName, SignInName, RoleDefinitionName, ObjectId, ObjectType));
            }
            else {
                $controlResult.VerificationResult =[VerificationResult]::Passed  
            }            
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual, "Not able to query Graph API. This has to be manually verified.");
        }
          
        return $controlResult
    }

    hidden [ControlResult] CheckCoAdminCount([ControlResult] $controlResult)
    {
        $this.GetRoleAssignments()
        Set-Variable -Name classicCoAdmins -Scope Local

        $classicCoAdmins = $this.RoleAssignments | Where-Object { $_.RoleDefinitionName -eq 'CoAdministrator' `
                                                                                -or $_.RoleDefinitionName -like '*ServiceAdministrator*' }
        $count = ($classicCoAdmins | Measure-Object).Count
        #$controlResult.AddMessage("No. of CoAdministrators found: $count", ($classicCoAdmins | Select-Object DisplayName, Scope, ObjectType, ObjectId), $true, "CoAdminsList")
        $controlResult.AddMessage("No. of CoAdministrators found: $count",  ($classicCoAdmins | Select-Object DisplayName, Scope, ObjectType, ObjectId))
        if($count -gt $this.ControlSettings.NoOfClassicAdminsLimit)
        {
            $controlResult.VerificationResult = [VerificationResult]::Failed
        }
        else {
            $controlResult.VerificationResult =[VerificationResult]::Passed  
        }
                
        return $controlResult
    }

    hidden [ControlResult] CheckManagementCertsPresence([ControlResult] $controlResult)
    {
        try
        {
            $this.GetManagementCertificates()
            if($this.ControlSettings.WhitelistedMgmtCerts | Get-Member -Name "Thumbprints")
            {    
                $this.ManagementCertificates | ForEach-Object {
                    Set-Variable -Name certObject -Value $_ -Scope Local
                    if(($this.ControlSettings.WhitelistedMgmtCerts.Thumbprints | Where-Object {$_ -eq $certObject.CertThumbprint} | Measure-Object).Count -gt 0 -and $certObject.Difference.Days -le $this.ControlSettings.WhitelistedMgmtCerts.ApprovedValidityRangeInDays)                
                    {
                        $certObject.Whitelisted = $true
                    }
                }
            }
            
            $FilteredMgmtCerts = @();
            $FilteredMgmtCerts += $this.ManagementCertificates | Where {-not $_.Whitelisted}    
            Set-Variable -Name isCompliant -Scope Local
            

            if($null -ne $FilteredMgmtCerts  -and $FilteredMgmtCerts.Count -gt 0)
            {                    
                #$controlResult.AddMessage([VerificationResult]::Failed,"Found Management certificates on the subscription.",($this.ManagementCertificates | Select-Object CertThumbprint, SubjectName, Issuer, Created , ExpiryDate , IsExpired, Whitelisted), $true, "MgmtCerts")
                $controlResult.AddMessage([VerificationResult]::Failed,"Found Management certificates on the subscription.",($this.ManagementCertificates | Select-Object CertThumbprint, SubjectName, Issuer, Created , ExpiryDate , IsExpired, Whitelisted))
            }
            else {
                $controlResult.VerificationResult = [VerificationResult]::Passed  
            }
        }
        catch
        {
            $controlResult.AddMessage([VerificationResult]::Manual,"Doesn't have required permissions to check management certificates on this subscription.")
        }
        return $controlResult
    }

    hidden [ControlResult] CheckAzureSecurityCenterSettings([ControlResult] $controlResult)
    {
        $secCenter = [SecurityCenter]::new($this.SubscriptionContext.SubscriptionId);
        if ($secCenter) 
        {
            $controlResult.AddMessage([MessageData]::new("Security center policies must be configured with settings mentioned below:", $secCenter.Policy.properties)); 
            $misConfiguredPolicies = $secCenter.GetMisconfiguredPolicies();
                
            if($misConfiguredPolicies.Count -ne 0)
            {
                $controlResult.AddMessage([VerificationResult]::Failed, [MessageData]::new("Following security center policies are not correctly configured. Please update the policies in order to comply.", $misConfiguredPolicies));
            }
            else
            {
                $controlResult.AddMessage([VerificationResult]::Passed, [MessageData]::new("All security center policies are correctly configured."));
            }
        }
        
        return $controlResult
    }

    hidden [ControlResult] CheckAzureSecurityCenterAlerts([ControlResult] $controlResult)
    {
        $this.GetASCAlerts()
        
        $activeAlerts = ($this.ASCSettings.Alerts | Where-Object {$_.State -eq "Active"})
        if(($activeAlerts | Measure-Object).Count -gt 0)
        {
            $controlResult.AddMessage([VerificationResult]::Failed,"Azure Security Center have active alerts that need to resolved.")
        }        
        else {
            $controlResult.VerificationResult =[VerificationResult]::Passed  
        }   
        
        $controlResult.AddMessage(($activeAlerts | Select-Object State, AlertDisplayName, AlertName, Description, ReportedTimeUTC, RemediationSteps))
                
        return $controlResult
    }

    hidden [ControlResult] CheckAzureSecurityCenterRecommendations([ControlResult] $controlResult)
    {
        $this.GetASCTasks()    
        $activeRecommendations = ($this.ASCSettings.Tasks | Where-Object {$_.State -eq "Active"})
        if(($activeRecommendations | Measure-Object).Count -gt 0)
        {
            $controlResult.AddMessage([VerificationResult]::Failed,"Azure Security Center have actives recommendations that need to resolved.")
        }        
        else {
            $controlResult.VerificationResult =[VerificationResult]::Passed  
        }       
        
        $controlResult.AddMessage(($activeRecommendations | Select-Object Name, State, ResourceId));
                
        return $controlResult
    }

    hidden [ControlResult] CheckSPNsRBAC([ControlResult] $controlResult)
    {
        if($this.HasGraphAPIAccess)
        { 
            $this.GetRoleAssignments()
            $scope = $this.SubscriptionContext.Scope
            $servicePrincipalNames = $this.RoleAssignments | Where-Object {$_.ObjectType -eq "ServicePrincipal" -and ($_.RoleDefinitionName -eq "Owner" -or $_.RoleDefinitionName -eq "Contributor") -and $_.Scope -eq $scope}                 
            if(($servicePrincipalNames | Measure-Object).Count -gt 0)
            {
                $controlResult.VerificationResult = [VerificationResult]::Failed
                #$controlResult.AddMessage("Below is the list SPNs which have either owner or contributor access on subscription:", ($servicePrincipalNames | Select-Object DisplayName, SignInName,ObjectType), $true, "CriticalSPNs")
                $controlResult.AddMessage("Below is the list SPNs which have either owner or contributor access on subscription:", ($servicePrincipalNames | Select-Object DisplayName, SignInName,ObjectType))        
            }
            else {
                    $controlResult.VerificationResult =[VerificationResult]::Passed  
            }            
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Manual, "Not able to query Graph API. This has to be manually verified.");
        }
        return $controlResult
    }

    hidden [ControlResult] CheckResourceLocksUsage([ControlResult] $controlResult)
    {
        $foundLocks = $true
        $lockDtls = $null
        #Command will throw exception if no locks found
        try {
                $lockDtls = Get-AzureRmResourceLock -ErrorAction Stop # -Scope "/subscriptions/$SubscriptionId"
        }
        catch
        {
            $foundLocks = $false
        }
        if($null -eq $lockDtls)
        {
            $foundLocks = $false
        }

        if($foundLocks)
        {
            #$controlResult.AddMessage([VerificationResult]::Verify, "Subscription lock details :", ($lockDtls | Select-Object Name, @{Name="Lock Level";Expression={$_.Properties.level}}, LockId, @{Name="Notes";Expression={$_.Properties.notes}} ), $true, "SubscriptionLocks")
            $controlResult.AddMessage([VerificationResult]::Verify, "Subscription lock details :", ($lockDtls | Select-Object Name,  @{Name="Lock Level";Expression={$_.Properties.level}}, LockId, @{Name="Notes";Expression={$_.Properties.notes}} ))
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Failed, "There are no resource locks present on the subscription.");
        }
        return $controlResult
    }

    hidden [ControlResult] CheckARMPoliciesCompliance([ControlResult] $controlResult)
    {
        $UserTags = @()
        $UserTags += "mandatory" 

        $subARMPolConfig = $this.LoadServerConfigFile("Subscription.ARMPolicies.json")
        $output = @()
        $foundMandatoryPolicies = $true
        if($null -ne $subARMPolConfig)
        {
            $subARMPolConfig = [array]($subARMPolConfig)
            $subARMPolConfig | ForEach-Object{
                Set-Variable -Name pol -Scope Local -Value $_
                Set-Variable -Name polEnabled -Scope Local -Value $_.enabled
                Set-Variable -Name policyDefinitionName -Scope Local -Value $_.policyDefinitionName
                Set-Variable -Name tags -Scope Local -Value $_.tags
                $haveMatchedTags = ((($tags | Where-Object { $UserTags.Contains($_.Trim().ToLower()) }) | Measure-Object).Count -gt 0)                        
                if($polEnabled -and $haveMatchedTags)
                {
                    $mandatoryPolicies = [array](Get-AzureRMPolicyAssignment | Where-Object {$_.Name -eq $policyDefinitionName})
                    if($null -eq $mandatoryPolicies -or ($mandatoryPolicies | Measure-Object).Count -le 0)
                    {
                        $foundMandatoryPolicies = $false
                        $output += $pol
                    }
                }
            }                    
        }
                
        if($foundMandatoryPolicies)
        {
            $controlResult.AddMessage([VerificationResult]::Passed, "Found all the mandatory policies on the Subscription.");
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Failed, "Some of the mandatory policies are missing which are demanded by the control tags [$UserTags]", $output);
        } 
        return $controlResult
    }

    hidden [ControlResult] CheckCriticalAlertsPresence([ControlResult] $controlResult)
    {
        $UserTags = @()
        $UserTags += "mandatory"
        $output = @()
        $subInsightsAlertsConfig = $this.LoadServerConfigFile("Subscription.InsAlerts.json")    
        $foundRequiredAlerts = $true
        if($null -ne $subInsightsAlertsConfig)
        {
            $subInsightsAlertsConfig =[array]($subInsightsAlertsConfig)
            
            $AlertsPkgRG = "AzSDKAlertsRG"
            $alertsRG = [array] (Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -match "^$AlertsPkgRG"})
            $configuredAlerts = $null
            if (($alertsRG | Measure-Object).Count -eq 1)
            {
                $configuredAlerts = Get-AzureRmAlertRule -ResourceGroup $AlertsPkgRG
            }
                    
            if((($alertsRG | Measure-Object).Count -eq 1) -and ($null -ne $configuredAlerts)){
                $subInsightsAlertsConfig | ForEach-Object{
                    Set-Variable -Name alert -Scope Local -Value $_
                    Set-Variable -Name alertEnabled -Scope Local -Value $_.Enabled
                    Set-Variable -Name alertName -Scope Local -Value $_.Name
                    Set-Variable -Name tags -Scope Local -Value $_.Tags
                    $haveMatchedTags = ((($tags | Where-Object { $UserTags.Contains($_.Trim().ToLower()) }) | Measure-Object).Count -gt 0)                        
                    if($alertEnabled -and $haveMatchedTags)
                    {
                        $foundAlert = [array]($configuredAlerts | Where-Object  {$_.Name -eq $alertName})
                        if($null -eq $foundAlert -or ($foundAlert | Measure-Object).Count -le 0)
                        {
                            $foundRequiredAlerts = $false
                            $output += $alert
                        }
                    }
                }                   
            }
            else {
                $foundRequiredAlerts = $false                        
            } 
        }
                
        if($foundRequiredAlerts)
        {
            $controlResult.AddMessage([VerificationResult]::Passed, "Insights alerts has been configured on the subscription.");
        }
        else
        {
            $controlResult.AddMessage([VerificationResult]::Failed, "Missing mandatory critical alerts on the subcription.", $output);
        }                                   
        return $controlResult
    }

    hidden [ControlResult] CheckCustomRBACRolesPresence([ControlResult] $controlResult)
    {
        $this.GetRoleAssignments()
        $out = @()
        $output = @()

        Get-AzureRmRoleDefinition -Custom | ForEach-Object{
                    
            Set-Variable -Name RoleDefn -Value $_    
            $out = "" | Select-Object RoleDefinitionName, RoleAssignmentScope
                    
            $RoleAssignments = [array]($this.RoleAssignments | Where-Object { $_.RoleDefinitionId -eq $RoleDefn.Id})
            if($null -ne $RoleAssignments -and $RoleAssignments.Length -gt 0)
            {
                $RoleAssignments | ForEach-Object{
                    Set-Variable -Name RoleAssignment -Value $_    
                    $out.RoleDefinitionName = $RoleDefn.Name
                    $out.RoleAssignmentScope = $RoleAssignment.Scope
                    $output+= $out
                }        
            }
            else
            {
                $out.RoleDefinitionName = $RoleDefn.Name
                $out.RoleAssignmentScope = "UnAssigned"
                $output+= $out
            }     
        }                
        $output = [array]($output)
        if($null -ne $output -and $output.Length -gt 0)
        {
            #$controlResult.AddMessage([VerificationResult]::Verify, "Found custom RBAC definitions`r`nNo. of custom RBAC roles: $($output.Length)", $output, $true, "CustomRBAC")
            $controlResult.AddMessage([VerificationResult]::Verify, "Found custom RBAC definitions`r`nNo. of custom RBAC roles: $($output.Length)", $output)
        }
        else
        {                               
           $controlResult.VerificationResult = [VerificationResult]::Passed
        }
                                         
        return $controlResult
    }

    hidden [ControlResult] CheckPresenceOfClassicResources([ControlResult] $controlResult)
    {
        $classicResources = [array] (Get-AzureRMResource | Where-Object {$_.ResourceType -like "*classic*"} )        
        if(($classicResources | Measure-Object).Count -gt 0)
        {
            #$controlResult.AddMessage([VerificationResult]::Failed, "Found classic resources on the susbcription.", $classicResources, $true, "ClassicResources")
            $controlResult.AddMessage([VerificationResult]::Failed, "Found classic resources on the susbcription.", $classicResources)
        }
        else
        {                               
           $controlResult.VerificationResult = [VerificationResult]::Passed
        }
                                         
        return $controlResult
    }
    

    hidden [void] LoadRBACConfig()
    {
        if($null -eq $this.MandatoryAccounts`
            -or $null -eq  $this.ApprovedAdmins`
            -or $null -eq  $this.DeprecatedAccounts`
            )
            {
                $this.MandatoryAccounts = @()
                $this.ApprovedAdmins = @()                
                $subRBACConfig = $this.LoadServerConfigFile("Subscription.RBAC.json")
                if($null -ne $subRBACConfig)
                {
                     $subRBACConfig.ValidActiveAccounts | Where-Object {$_.Enabled} | ForEach-Object{
                         if($_.RoleDefinitionName -eq "Owner")
                         {
                            $this.ApprovedAdmins += $_
                         }
                         if(($_.Tags | Where-Object {$_ -eq "Mandatory"} | Measure-Object).Count -gt 0)
                         {
                            $this.MandatoryAccounts += $_
                         }
                    }
                }
                $this.DeprecatedAccounts = $subRBACConfig.DeprecatedAccounts | Where-Object {$_.Enabled}
            }
    }

    hidden [void] GetRoleAssignments()
    {
        if($null -eq $this.RoleAssignments)
        {
            $this.RoleAssignments =  [RoleAssignmentHelper]::GetAzSDKRoleAssignment($true,$true)
        }
    }

    hidden [void] GetManagementCertificates()
    {
        $ResourceAppIdURI = [WebRequestHelper]::ClassicManagementUri;
        $ClassicAccessToken = [Helpers]::GetAccessToken($ResourceAppIdURI)
        if($null -ne $ClassicAccessToken) 
        {
            $header = "Bearer " + $ClassicAccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json"; "x-ms-version" ="2013-08-01"}
            $uri = [string]::Format("{0}/{1}/certificates","https://management.core.windows.net",$this.SubscriptionContext.SubscriptionId)
            $mgmtCertsResponse = Invoke-WebRequest -Method GET -Uri $uri -Headers $headers -UseBasicParsing
            if($mgmtCertsResponse.StatusCode -ge 200 -and $mgmtCertsResponse.StatusCode -le 399)
            {             
                if($null -ne $mgmtCertsResponse.Content)
                {                
                    [xml] $mgmtCerts = $mgmtCertsResponse.Content;
                    $this.ManagementCertificates = @();
                    if($null -ne $mgmtCerts -and [Helpers]::CheckMember($mgmtCerts, "SubscriptionCertificates.SubscriptionCertificate"))
                    {
                        $this.ManagementCertificates = [ManagementCertificate]::ListManagementCertificates($mgmtCerts.SubscriptionCertificates.SubscriptionCertificate)
                    }
                }
            }
        }        
    }
    
    hidden [void] GetASCAlerts()
    {
        $ResourceAppIdURI = [WebRequestHelper]::AzureManagementUri;
        $AccessToken = [Helpers]::GetAccessToken($ResourceAppIdURI)
        if($null -ne $AccessToken) 
        {
            $header = "Bearer " + $AccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json";}
            $uri=[system.string]::Format("https://management.azure.com/subscriptions/{0}/providers/microsoft.Security/alerts?api-version=2015-06-01-preview",$this.SubscriptionContext.SubscriptionId)
            $result = ""
            $err = $null
            $output = $null
            try { 
                $result = Invoke-WebRequest -Method GET -Uri $uri -Headers $headers -UseBasicParsing
                if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){
                    if($null -ne $result.Content){
                        $json = (ConvertFrom-Json $result.Content)
                        if($null -ne $json){
                            if(($json | Get-Member -Name "value"))
                            {
                                $output += $json.value;
                            }
                            else
                            {
                                $output += $json;
                            }      
                        }
                    }
                } 
            } 
            catch{ 
                $err = $_ 
                if($null -ne $err)
                {
                    if($null -ne $err.ErrorDetails.Message){
                        $json = (ConvertFrom-Json $err.ErrorDetails.Message)
                        if($null -ne $json){
                            $return = $json
                            if($json.'odata.error'.code -eq "Request_ResourceNotFound")
                            {
                                $return = $json.'odata.error'.message
                            }
                        }
                    }
                }
            }
            $this.ASCSettings.Alerts = [AzureSecurityCenter]::GetASCAlerts($output)
        }
    }

    hidden [void] GetASCTasks()
    {
        $ResourceAppIdURI = [WebRequestHelper]::AzureManagementUri;
        $AccessToken = [Helpers]::GetAccessToken($ResourceAppIdURI)
        if($null -ne $AccessToken) 
        {
            $header = "Bearer " + $AccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json";}
            $uri=[system.string]::Format("https://management.azure.com/subscriptions/{0}/providers/microsoft.Security/tasks?api-version=2015-06-01-preview", $this.SubscriptionContext.SubscriptionId)
            $result = ""
            $err = $null
            $output = $null
            try { 
                $result = Invoke-WebRequest -Method GET -Uri $uri -Headers $headers -UseBasicParsing
                if($result.StatusCode -ge 200 -and $result.StatusCode -le 399){
                    if($null -ne $result.Content){
                        $json = (ConvertFrom-Json $result.Content)
                        if($null -ne $json){
                            if($json | Get-Member -Name "value")
                            {
                                $output += $json.value;
                            }
                            else
                            {
                                $output += $json;
                            }        
                        }
                    }
                } 
            } 
            catch{ 
                $err = $_ 
                if($null -ne $err)
                {
                    if($null -ne $err.ErrorDetails.Message){
                        $json = (ConvertFrom-Json $err.ErrorDetails.Message)
                        if($null -ne $json){
                            $return = $json
                            if($json.'odata.error'.code -eq "Request_ResourceNotFound")
                            {
                                $return = $json.'odata.error'.message
                            }
                        }
                    }
                }
            }
            $this.ASCSettings.Tasks = [AzureSecurityCenter]::GetASCTasks($output)
        }
    }
}