Framework/Helpers/SecurityCenterHelper.ps1

using namespace Microsoft.Azure.Commands.Resources.Models.Authorization
Set-StrictMode -Version Latest 
class SecurityCenterHelper
{
    static [string] $ProviderNamespace = "Microsoft.Security";
    static [string] $PolicyProviderNamespace = "Microsoft.PolicyInsights";
    static [string] $PoliciesApi = "policies/default";
    static [string] $AlertsApi = "alerts";
    static [string] $AutoProvisioningSettingsApi = "autoProvisioningSettings";
    static [string] $SecurityContactsApi = "securityContacts";
    static [string] $TasksApi = "tasks";
    static [string] $SecurityStatusApi = "securityStatuses";
    static [string] $ApiVersion = "?api-version=2015-06-01-preview";
    static [string] $ApiVersionNew = "?api-version=2017-08-01-preview";
    static [string] $ApiVersionLatest = "?api-version=2019-09-01";
    static [PSObject] $Recommendations = $null;
    

    static [Hashtable] AuthHeaderFromUri([string] $uri)
        {
        [System.Uri] $validatedUri = $null;
        if([System.Uri]::TryCreate($uri, [System.UriKind]::Absolute, [ref] $validatedUri))
        {
            return @{
                "Authorization"= ("Bearer " + [ContextHelper]::GetAccessToken($validatedUri.GetLeftPart([System.UriPartial]::Authority))); 
                "Content-Type"="application/json"
            };

        }
        
        return @{ "Content-Type"="application/json" };
    }
    
    static [System.Object[]] InvokeGetSecurityCenterRequest([string] $subscriptionId, [string] $apiType, [string] $apiVersion)
    {
        if([string]::IsNullOrWhiteSpace($subscriptionId))
        {
            throw [System.ArgumentException] ("The argument 'subscriptionId' is null");
        }

        if([string]::IsNullOrWhiteSpace($apiType))
        {
            throw [System.ArgumentException] ("The argument 'apiType' is null");
        }
        
        # Commenting this as it's costly call and expected to happen in Set-ASC/SSS/USS
        #[SecurityCenterHelper]::RegisterResourceProvider();
        $rmContext = [ContextHelper]::GetCurrentRMContext();
        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $uri = $ResourceAppIdURI + "subscriptions/$subscriptionId/providers/$([SecurityCenterHelper]::ProviderNamespace)/$($apiType)$($apiVersion)";
        return [WebRequestHelper]::InvokeGetWebRequest($uri);
    }

    static [System.Object[]] InvokePutSecurityCenterRequest([string] $resourceId, [System.Object] $body, [string] $apiVersion)
    {
        if([string]::IsNullOrWhiteSpace($resourceId))
        {
            throw [System.ArgumentException] ("The argument 'resourceId' is null");
        }

        # Commenting this as it's costly call and expected to happen in Set-ASC/SSS/USS
        #[SecurityCenterHelper]::RegisterResourceProvider();
        $rmContext = [ContextHelper]::GetCurrentRMContext();
        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $uri = $ResourceAppIdURI.TrimEnd("/") + $resourceId + $apiVersion;
        return [WebRequestHelper]::InvokeWebRequest([Microsoft.PowerShell.Commands.WebRequestMethod]::Put, $uri, $body);
    }

    static [PSObject] InvokeSecurityCenterSecurityStatus([string] $subscriptionId, [string] $resourceId)
    {
        try 
        {     
            if((-not [string]::IsNullOrEmpty($subscriptionId)) -and (-not [String]::IsNullOrEmpty($resourceId))) 
            {
                $rmContext = [ContextHelper]::GetCurrentRMContext();
                $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
                $uri = [System.String]::Format("{0}subscriptions/{1}/providers/microsoft.Security/securityStatuses?api-version=2015-06-01-preview&`$filter=tolower(Id)%20eq%20tolower('{2}/providers/Microsoft.Security/securityStatuses/{3}')", $ResourceAppIdURI, $subscriptionId, $resourceId, $resourceId.Split("/")[-1])
                $result = [WebRequestHelper]::InvokeGetWebRequest($uri);                    
                if(($result | Measure-Object).Count -gt 0)
                {
                    return $result                
                }                                        
            }                
            return $null
        } 
        catch
        { 
            return $null;
        }       
    }


    hidden static [PSObject] InvokeGetASCTasks([string] $subscriptionId)
    {
        # Commenting this as it's costly call and expected to happen in Set-ASC/SSS/USS
        #[SecurityCenterHelper]::RegisterResourceProvider();
        if(([SecurityCenterHelper]::Recommendations | Measure-Object).Count -eq 0)
        {
            $ascTasks = [SecurityCenterHelper]::InvokeGetSecurityCenterRequest($subscriptionId, [SecurityCenterHelper]::TasksApi, [SecurityCenterHelper]::ApiVersion)
            $tasks = [AzureSecurityCenter]::GetASCTasks($ascTasks);        
            [SecurityCenterHelper]::Recommendations = $tasks;
        }
        return [SecurityCenterHelper]::Recommendations;
    }

    static [void] RegisterResourceProvider()
    {
        [ResourceHelper]::RegisterResourceProviderIfNotRegistered([SecurityCenterHelper]::PolicyProviderNamespace);
        [ResourceHelper]::RegisterResourceProviderIfNotRegistered([SecurityCenterHelper]::ProviderNamespace);
    }

    static [void] RegisterResourceProviderNoException()
    {
        try
        {
            [SecurityCenterHelper]::RegisterResourceProvider();
        }
        catch
        { 
            [EventBase]::PublishGenericException($_);
        }
    }
}


class ASCTelemetryHelper {
    [string] $SubscriptionId = "";
    [string] $ASCTier = "";
    [PSObject[]] $ResourceTier = $null;
    [PSObject] $SecurityContactSettings = $null;
    [PSObject] $SecureScore = $null;
    [PSObject] $WorkspaceSettings = $null;
    [string] $SecurityEventsTier = "";
    [PSObject[]] $ASCRecommendations = $null;
    [PSObject[]] $ThreatDetection = $null;
    [string] $AutoProvisioningStatus = "";
    static [ASCTelemetryHelper] $ascData = $null;

     ASCTelemetryHelper([string] $subscriptionId, [string] $ascTierSetting, [string] $autoProvisioningSettings, [PSObject] $securityContacts)
    {
        $this.SubscriptionId = $subscriptionId;
        $this.ASCTier = $ascTierSetting;
        $this.AutoProvisioningStatus = $autoProvisioningSettings;
        $this.SecurityContactSettings = $securityContacts;
        $this.UpdateCurrentInstance();
    }

     [void] UpdateCurrentInstance()
    {
        $this.GetASCTierResourceWise();
        #Some API calls have been commented as we are yet to decide whether we can use them or not
        #$this.GetSecureScore();
        #$this.GetThreatDetectionSettings();
        #$this.GetASCRecommendations();
        $this.GetWorkspaceSettings();
        #$this.GetSecurityEventsTier();

         [ASCTelemetryHelper]::ascData = $this;
    }

     [void] GetASCTierResourceWise()
    {
        $ResourceUrl= [WebRequestHelper]::GetResourceManagerUrl()
        $validatedUri = "$ResourceUrl/subscriptions/$($this.SubscriptionId)/providers/Microsoft.Security/pricings?api-version=2018-06-01"
        $ascTierResourceWiseDetails = [WebRequestHelper]::InvokeGetWebRequest($validatedUri)

          $ascTierResourceWiseDetailsList = [System.Collections.ArrayList]::new()
        foreach($resourceDetails in $ascTierResourceWiseDetails)
        {
            if([Helpers]::CheckMember($resourceDetails,"name"))
            {
                if([Helpers]::CheckMember($resourceDetails,"properties.pricingTier"))
                {
                    $ASCResourceTier = New-Object psobject -Property @{
                        Name = $resourceDetails.name;
                        Tier = $resourceDetails.properties.pricingTier;
                    }
                    $ascTierResourceWiseDetailsList.Add($ASCResourceTier) | Out-Null
                }
            }
        }

          $this.ResourceTier = $ascTierResourceWiseDetailsList;
    }

     [void] GetSecureScore()
    {
        $uri = "https://s2.security.ext.azure.com/api/SecureScore/subscriptions";
        $body = '{"subscriptionId":["'+$this.SubscriptionId+'"],"limitedSelectedSubscriptionIds":[],"shouldRetrieveDataForLimitedSubscriptions":false}';

         $result = $this.GetContentFromPostRequest($uri, $body);

         if($null -eq $result)
        {
            $this.SecureScore = $null;
        }
        else 
        {
            $this.SecureScore = New-Object psobject -Property @{
                CurrentSecureScore = $result.currentSecureScore;
                MaxSecureScore = $result.maxSecureScore;
            }
        }
    }

     [void] GetThreatDetectionSettings()
    {
        $uri = "https://s2.security.ext.azure.com/api/threatDetectionSettings/getThreatDetectionSettings?subscriptionId="+$this.SubscriptionId;

        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $AccessToken = [ContextHelper]::GetAccessToken($ResourceAppIdURI)
        $result = $null;

         if($null -ne $AccessToken)
        {
            $header = "Bearer " + $AccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json";}

             $result = [WebRequestHelper]::InvokeGetWebRequest($uri, $headers)
        }

         if($null -eq $result)
        {
            $this.ThreatDetection = $null
        }
        else 
        {
            $TDEdetailsList = [System.Collections.ArrayList]::new();
            foreach($TDEdetails in $result)
            {
                if([Helpers]::CheckMember($TDEdetails,"name"))
                {
                    if([Helpers]::CheckMember($TDEdetails,"properties.enabled"))
                    {
                        $TDEtype = New-Object psobject -Property @{
                            Name = $TDEdetails.name;
                            isEnabled = $TDEdetails.properties.enabled;
                        }
                        $TDEdetailsList.Add($TDEtype) | Out-Null
                    }
                }
            }

             $this.ThreatDetection = $TDEdetailsList;
        }
    }

     [void] GetASCRecommendations()
    {
        $uri = "https://s2.security.ext.azure.com/api/Assessments/aggregated?`$pageSize=40&failedAssessmentsOnly=true";
        $body = '{"Subscriptions":["'+$this.SubscriptionId+'"],"resourceTypeFilter":[],"limitedSelectedSubscriptions":[],"shouldRetrieveDataForLimitedSubscriptions":false,"resourceGroupIdFilter":[],"resourceIdFilter":[],"categoryFilter":null}'

         $result = $this.GetContentFromPostRequest($uri, $body);

         if($null -eq $result)
        {
            $this.ASCRecommendations = $null
        }
        else 
        {
            $this.ASCRecommendations = $result.results
        }
    }

     [void] GetSecurityEventsTier()
    {
        $uri = "https://s2.security.ext.azure.com/api/securityEventsTier/getSecurityEventsTier?subscriptionId="+$this.SubscriptionId;
        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $AccessToken = [ContextHelper]::GetAccessToken($ResourceAppIdURI)
        $result = $null;

         if($null -ne $AccessToken)
        {
            $header = "Bearer " + $AccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json";}

             $result = [WebRequestHelper]::InvokeGetWebRequest($uri, $headers)
        }

         if($null -ne $result)
        {
            $this.SecurityEventsTier = $result.tier
        }
        else 
        {
            $this.SecurityEventsTier = $null    
        }
    }

     [void] GetWorkspaceSettings()
    {
        $ResourceUrl= [WebRequestHelper]::GetResourceManagerUrl()
        $validatedUri = "$ResourceUrl/subscriptions/$($this.SubscriptionId)/providers/Microsoft.Security/workspaceSettings/default?api-version=2017-08-01-preview"
        $workspaceSettingsDetails = [WebRequestHelper]::InvokeGetWebRequest($validatedUri)

         if([Helpers]::CheckMember($workspaceSettingsDetails,"properties.workspaceId"))
        {
            $this.WorkspaceSettings = New-Object psobject -Property @{
                WorkspaceId = $workspaceSettingsDetails.properties.workspaceId;
                Scope = $workspaceSettingsDetails.properties.scope;
            }
        }
        else 
        {
            $this.WorkspaceSettings = $null;
        }
    }

     [PSObject] GetContentFromPostRequest($uri, $body)
    {
        $ResourceAppIdURI = [WebRequestHelper]::GetResourceManagerUrl()
        $AccessToken = [ContextHelper]::GetAccessToken($ResourceAppIdURI)
        if($null -ne $AccessToken)
        {
            $header = "Bearer " + $AccessToken
            $headers = @{"Authorization"=$header;"Content-Type"="application/json";}
            $result = ""
            $err = $null
            $output = $null
            try {
                $result = Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body -ContentType "application/json" -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;
                            }
                        }
                    }
                }
                return $output
            }
            catch
            {
                $err = $_
                if($null -ne $err)
                {
                    if($null -ne $err.ErrorDetails.Message){
                        $json = (ConvertFrom-Json $err.ErrorDetails.Message)
                        if($null -ne $json){
                            if($json.'odata.error'.code -eq "Request_ResourceNotFound")
                            {
                                return $json.'odata.error'.message
                            }
                            return $json
                        }
                    }
                }
            }
        }
        return $null
    }
}