Framework/Listeners/RemoteReports/ControlTelemetry.ps1

Set-StrictMode -Version Latest

class ControlTelemetry: ListenerBase {
    [Microsoft.ApplicationInsights.TelemetryClient] $TelemetryClient;

    hidden ControlTelemetry() {
        $this.TelemetryClient = [Microsoft.ApplicationInsights.TelemetryClient]::new()
    }

    hidden static [ControlTelemetry] $Instance = $null;

    static [ControlTelemetry] GetInstance() {
        if ( $null  -eq [ControlTelemetry]::Instance -or  $null  -eq [ControlTelemetry]::Instance.TelemetryClient) {
            [ControlTelemetry]::Instance = [ControlTelemetry]::new();
        }
        return [ControlTelemetry]::Instance
    }

    [void] RegisterEvents() {
        $this.UnregisterEvents();

        $this.RegisterEvent([AzSdkRootEvent]::GenerateRunIdentifier, {
            $currentInstance = [ControlTelemetry]::GetInstance();
            try
            {
                $runIdentifier = [AzSdkRootEventArgument] ($Event.SourceArgs | Select-Object -First 1)
                $currentInstance.SetRunIdentifier($runIdentifier);
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });

        $this.RegisterEvent([SVTEvent]::EvaluationCompleted, {
            $currentInstance = [ControlTelemetry]::GetInstance();
            try
            {
                $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext
                $SVTEventContexts = [SVTEventContext[]] $Event.SourceArgs
                $featureGroup = [RemoteReportHelper]::GetFeatureGroup($SVTEventContexts)
                if($featureGroup -eq [FeatureGroup]::Subscription){
                    $currentInstance.PushSubscriptionScanResults($SVTEventContexts)
                }elseif($featureGroup -eq [FeatureGroup]::Service){
                    $currentInstance.PushServiceScanResults($SVTEventContexts)
                }else{
                }
            }
            catch
            {
                $currentInstance.PublishException($_);
            }
        });
    }

    hidden [void] PushSubscriptionScanResults([SVTEventContext[]] $SVTEventContexts)
    {
        $baseProperties = @{
            "RunIdentifier" = $this.RunIdentifier;
            [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Subscription;
            "ScanKind" = [RemoteReportHelper]::GetSubscriptionScanKind(
                $this.InvocationContext.MyCommand.Name,
                $this.InvocationContext.BoundParameters);
        }
        $this.PushControlResults($SVTEventContexts, $baseProperties)

    }

    hidden [void] PushServiceScanResults([SVTEventContext[]] $SVTEventContexts)
    {
        $SVTEventContextFirst = $SVTEventContexts[0]
        $baseProperties = @{
            "RunIdentifier" = $this.RunIdentifier;
            [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Service;
            "ScanKind" = [RemoteReportHelper]::GetServiceScanKind(
                $this.InvocationContext.MyCommand.Name,
                $this.InvocationContext.BoundParameters);
            "Feature" = $SVTEventContextFirst.FeatureName;
            "ResourceGroup" = $SVTEventContextFirst.ResourceContext.ResourceGroupName;
            "ResourceName" = $SVTEventContextFirst.ResourceContext.ResourceName;
            "ResourceId" = $SVTEventContextFirst.ResourceContext.ResourceId;
        }
        $this.PushControlResults($SVTEventContexts, $baseProperties)
    }

    hidden [void] PushControlResults([SVTEventContext[]] $SVTEventContexts, [hashtable] $BaseProperties){
        $telemetryEvents = [System.Collections.ArrayList]::new()
        foreach($context in $SVTEventContexts){
            $propertiesCollection = $this.AttachControlProperties($BaseProperties, $context)
            foreach($properties in $propertiesCollection){
                $telemetryEvent = "" | Select-Object Name, Properties, Metrics
                $telemetryEvent.Name = "Control Scanned"
                $telemetryEvent.Properties = $properties
                $telemetryEvents.Add($telemetryEvent) | Out-Null
            }
        }
        [AppInsightsHelper]::TrackEvents($telemetryEvents);
    }

    hidden [hashtable[]] AttachControlProperties([hashtable] $BaseProperties, [SVTEventContext] $context){
        if($context -eq $null) {return  ([hashtable[]]([System.Collections.ArrayList]::new()))}
        $properties = @{}
        if ($BaseProperties -ne $null) {
            $properties = $BaseProperties.Clone()
        }
        $propertiesArray = [System.Collections.ArrayList]::new()

        $properties.Add("ControlIntId", $context.ControlItem.Id);
        $properties.Add("ControlId", $context.ControlItem.ControlID);
        $properties.Add("ControlSeverity", $context.ControlItem.ControlSeverity);
        if (!$context.ControlItem.Enabled) {
            $properties.Add("VerificationResult", [VerificationResult]::Disabled)
            $properties.Add("AttestationStatus", [AttestationStatus]::None)
            $propertiesArray.Add($properties) | Out-Null
        }else{
            $results = $context.ControlResults
            if($results.Count -eq 1){
                $properties.Add("ActualVerificationResult", $results[0].ActualVerificationResult)
                $properties.Add("AttestationStatus", $results[0].AttestationStatus)
                $properties.Add("VerificationResult", $results[0].VerificationResult)
                if($context.ResourceContext -ne $null){
                    if($context.ResourceContext.ResourceName -eq $results[0].ChildResourceName -or [string]::IsNullOrWhiteSpace($results[0].ChildResourceName)){
                        $properties.Add("IsNestedResource", 'No')
                        $properties.Add("NestedResourceName", "NA")
                    }else{
                        $properties.Add("IsNestedResource", 'Yes')
                        $properties.Add("NestedResourceName", $results[0].ChildResourceName)
                    }
                }
                if(($results[0].StateManagement -ne $null) -and ($results[0].StateManagement.AttestedStateData -ne $null)) {
                    $properties.Add("AttestedBy", $results[0].StateManagement.AttestedStateData.AttestedBy)
                    $properties.Add("Justification", $results[0].StateManagement.AttestedStateData.Justification)
                }
                $propertiesArray.Add($properties) | Out-Null
            }elseif($results.Count -gt 1){
                $properties.Add("IsNestedResource", 'Yes')
                foreach($result in $results){
                    $propertiesIn = $properties.Clone()
                    $propertiesIn.Add("ActualVerificationResult", $result.ActualVerificationResult)
                    $propertiesIn.Add("AttestationStatus", $result.AttestationStatus)
                    $propertiesIn.Add("VerificationResult", $result.VerificationResult)
                    $propertiesIn.Add("NestedResourceName", $result.ChildResourceName)
                    if(($result.StateManagement -ne $null) -and ($result.StateManagement.AttestedStateData -ne $null)) {
                        $propertiesIn.Add("AttestedBy", $result.StateManagement.AttestedStateData.AttestedBy)
                        $propertiesIn.Add("Justification", $result.StateManagement.AttestedStateData.Justification)
                    }
                    $propertiesArray.Add($propertiesIn) | Out-Null
                }
            }
        }
        $returnObj = [hashtable[]] $propertiesArray
        return $returnObj;
    }
}