Framework/Listeners/RemoteReports/UsageTelemetry.ps1
Set-StrictMode -Version Latest class UsageTelemetry: ListenerBase { [Microsoft.ApplicationInsights.TelemetryClient] $TelemetryClient; hidden UsageTelemetry() { $this.TelemetryClient = [Microsoft.ApplicationInsights.TelemetryClient]::new() $this.TelemetryClient.InstrumentationKey = [Constants]::UsageTelemetryKey } hidden static [UsageTelemetry] $Instance = $null; static [UsageTelemetry] GetInstance() { if ( $null -eq [UsageTelemetry]::Instance -or $null -eq [UsageTelemetry]::Instance.TelemetryClient) { [UsageTelemetry]::Instance = [UsageTelemetry]::new(); } return [UsageTelemetry]::Instance } [void] RegisterEvents() { $this.UnregisterEvents(); $this.RegisterEvent([AzSKRootEvent]::GenerateRunIdentifier, { $currentInstance = [UsageTelemetry]::GetInstance(); try { $runIdentifier = [AzSKRootEventArgument] ($Event.SourceArgs | Select-Object -First 1) $currentInstance.SetRunIdentifier($runIdentifier); } catch { $currentInstance.PublishException($_); } }); $this.RegisterEvent([SVTEvent]::EvaluationCompleted, { $azskSettings = [ConfigurationManager]::GetAzSKSettings(); if($azskSettings.UsageTelemetryLevel -ne "Anonymous") { return; } $currentInstance = [UsageTelemetry]::GetInstance(); try { $invocationContext = [System.Management.Automation.InvocationInfo] $currentInstance.InvocationContext $SVTEventContexts = [SVTEventContext[]] $Event.SourceArgs $featureGroup = [RemoteReportHelper]::GetFeatureGroup($SVTEventContexts) if($featureGroup -eq [FeatureGroup]::Subscription){ [UsageTelemetry]::PushSubscriptionScanResults($currentInstance, $SVTEventContexts) }elseif($featureGroup -eq [FeatureGroup]::Service){ [UsageTelemetry]::PushServiceScanResults($currentInstance, $SVTEventContexts) }else{ } } catch { $currentInstance.PublishException($_); } $currentInstance.TelemetryClient.Flush() }); $this.RegisterEvent([AzSKGenericEvent]::Exception, { $currentInstance = [UsageTelemetry]::GetInstance(); try { [System.Management.Automation.ErrorRecord] $er = ($Event.SourceArgs | Select-Object -First 1) [UsageTelemetry]::PushException($currentInstance, @{}, @{}, $er); } catch { } }); $this.RegisterEvent([AzSKRootEvent]::CommandError, { $currentInstance = [UsageTelemetry]::GetInstance(); try { [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [UsageTelemetry]::PushException($currentInstance, @{}, @{}, $er); } catch { } }); $this.RegisterEvent([SVTEvent]::CommandError, { $currentInstance = [UsageTelemetry]::GetInstance(); try { [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [UsageTelemetry]::PushException($currentInstance, @{}, @{}, $er); } catch { } }); $this.RegisterEvent([SVTEvent]::EvaluationError, { $currentInstance = [UsageTelemetry]::GetInstance(); try { [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [UsageTelemetry]::PushException($currentInstance, @{}, @{}, $er); } catch { } }); $this.RegisterEvent([SVTEvent]::ControlError, { $currentInstance = [UsageTelemetry]::GetInstance(); try { [System.Management.Automation.ErrorRecord] $er = $Event.SourceArgs.ExceptionMessage [UsageTelemetry]::PushException($currentInstance, @{}, @{}, $er); } catch { } }); } static [void] PushSubscriptionScanResults( [UsageTelemetry] $Publisher, ` [SVTEventContext[]] $SVTEventContexts) { $eventData = @{ [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Subscription; "ScanKind" = [RemoteReportHelper]::GetSubscriptionScanKind( $Publisher.InvocationContext.MyCommand.Name, $Publisher.InvocationContext.BoundParameters); } $SVTEventContexts | ForEach-Object { $context = $_ [hashtable] $eventDataClone = $eventData.Clone(); $eventDataClone.Add("ControlIntId", $context.ControlItem.Id); $eventDataClone.Add("ControlId", $context.ControlItem.ControlID); $eventDataClone.Add("ControlSeverity", $context.ControlItem.ControlSeverity); if ($context.ControlItem.Enabled) { $eventDataClone.Add("ActualVerificationResult", $context.ControlResults[0].ActualVerificationResult) $eventDataClone.Add("AttestationStatus", $context.ControlResults[0].AttestationStatus) $eventDataClone.Add("VerificationResult", $context.ControlResults[0].VerificationResult) } else { $eventDataClone.Add("ActualVerificationResult", [VerificationResult]::Disabled) $eventDataClone.Add("AttestationStatus", [AttestationStatus]::None) $eventDataClone.Add("VerificationResult", [VerificationResult]::Disabled) } [UsageTelemetry]::PushEvent($Publisher, $eventDataClone, @{}) } } static [void] PushServiceScanResults( [UsageTelemetry] $Publisher, ` [SVTEventContext[]] $SVTEventContexts) { $NA = "NA" $SVTEventContextFirst = $SVTEventContexts[0] $eventData = @{ [TelemetryKeys]::FeatureGroup = [FeatureGroup]::Service; "ScanKind" = [RemoteReportHelper]::GetServiceScanKind( $Publisher.InvocationContext.MyCommand.Name, $Publisher.InvocationContext.BoundParameters); "Feature" = $SVTEventContextFirst.FeatureName; "ResourceGroup" = [RemoteReportHelper]::Mask($SVTEventContextFirst.ResourceContext.ResourceGroupName); "ResourceName" = [RemoteReportHelper]::Mask($SVTEventContextFirst.ResourceContext.ResourceName); "ResourceId" = [RemoteReportHelper]::Mask($SVTEventContextFirst.ResourceContext.ResourceId); } $SVTEventContexts | ForEach-Object { $SVTEventContext = $_ [hashtable] $eventDataClone = $eventData.Clone() $eventDataClone.Add("ControlIntId", $SVTEventContext.ControlItem.Id); $eventDataClone.Add("ControlId", $SVTEventContext.ControlItem.ControlID); $eventDataClone.Add("ControlSeverity", $SVTEventContext.ControlItem.ControlSeverity); if (!$SVTEventContext.ControlItem.Enabled) { $eventDataClone.Add("ActualVerificationResult", [VerificationResult]::Disabled) $eventDataClone.Add("AttestationStatus", [AttestationStatus]::None) $eventDataClone.Add("VerificationResult", [VerificationResult]::Disabled) [UsageTelemetry]::PushEvent($Publisher, $eventDataClone, @{}) } elseif ($SVTEventContext.ControlResults.Count -eq 1 -and ` ($SVTEventContextFirst.ResourceContext.ResourceName -eq $SVTEventContext.ControlResults[0].ChildResourceName -or ` [string]::IsNullOrWhiteSpace($SVTEventContext.ControlResults[0].ChildResourceName))) { $eventDataClone.Add("ActualVerificationResult", $SVTEventContext.ControlResults[0].ActualVerificationResult) $eventDataClone.Add("AttestationStatus", $SVTEventContext.ControlResults[0].AttestationStatus) $eventDataClone.Add("VerificationResult", $SVTEventContext.ControlResults[0].VerificationResult) $eventDataClone.Add("IsNestedResource", 'No') $eventDataClone.Add("NestedResourceName", $NA) [UsageTelemetry]::PushEvent($Publisher, $eventDataClone, @{}) } elseif ($SVTEventContext.ControlResults.Count -eq 1 -and ` $SVTEventContextFirst.ResourceContext.ResourceName -ne $SVTEventContext.ControlResults[0].ChildResourceName) { $eventDataClone.Add("ActualVerificationResult", $SVTEventContext.ControlResults[0].ActualVerificationResult) $eventDataClone.Add("AttestationStatus", $SVTEventContext.ControlResults[0].AttestationStatus) $eventDataClone.Add("VerificationResult", $SVTEventContext.ControlResults[0].VerificationResult) $eventDataClone.Add("IsNestedResource", 'Yes') $eventDataClone.Add("NestedResourceName", [RemoteReportHelper]::Mask($SVTEventContext.ControlResults[0].ChildResourceName)) [UsageTelemetry]::PushEvent($Publisher, $eventDataClone, @{}) } elseif ($SVTEventContext.ControlResults.Count -gt 1) { $eventDataClone.Add("IsNestedResource", 'Yes') $SVTEventContext.ControlResults | Foreach-Object { [hashtable] $eventDataCloneL2 = $eventDataClone.Clone() $eventDataCloneL2.Add("ActualVerificationResult", $_.ActualVerificationResult) $eventDataCloneL2.Add("AttestationStatus", $_.AttestationStatus) $eventDataCloneL2.Add("VerificationResult", $_.VerificationResult) $eventDataCloneL2.Add("NestedResourceName", [RemoteReportHelper]::Mask($_.ChildResourceName)) [UsageTelemetry]::PushEvent($Publisher, $eventDataCloneL2, @{}) } } } } static [void] PushEvent([UsageTelemetry] $Publisher, ` [hashtable] $Properties, [hashtable] $Metrics) { try{ [UsageTelemetry]::SetCommonProperties($Publisher, $Properties); $event = [Microsoft.ApplicationInsights.DataContracts.EventTelemetry]::new() $event.Name = "Control Scanned" $Properties.Keys | ForEach-Object { try{ $event.Properties.Add($_, $Properties[$_].ToString()); } catch{ } } $Metrics.Keys | ForEach-Object { try{ $event.Metrics.Add($_, $Metrics[$_]); } catch{ } } $Publisher.TelemetryClient.TrackEvent($event); } catch{ } } static [void] PushException([UsageTelemetry] $Publisher, ` [hashtable] $Properties, [hashtable] $Metrics, ` [System.Management.Automation.ErrorRecord] $ErrorRecord) { try{ [UsageTelemetry]::SetCommonProperties($Publisher, $Properties); $ex = [Microsoft.ApplicationInsights.DataContracts.ExceptionTelemetry]::new() $ex.Exception = $ErrorRecord.Exception try{ $ex.Properties.Add("ScriptStackTrace", [UsageTelemetry]::AnonScriptStackTrace($ErrorRecord.ScriptStackTrace)) }catch{} $Properties.Keys | ForEach-Object { try{ $ex.Properties.Add($_, $Properties[$_].ToString()); } catch{ } } $Metrics.Keys | ForEach-Object { try{ $ex.Metrics.Add($_, $Metrics[$_]); } catch{ } } $Publisher.TelemetryClient.TrackException($ex) $Publisher.TelemetryClient.Flush() } catch{ } } hidden static [void] SetCommonProperties([UsageTelemetry] $Publisher, [hashtable] $Properties) { try{ $NA = "NA"; $Properties.Add("InfoVersion", "V1"); try{ $Properties.Add("ScanSource", [RemoteReportHelper]::GetScanSource()); }catch{} try{ $Properties.Add("ScannerVersion", $Publisher.GetCurrentModuleVersion()); }catch{} try{ $Properties.Add("ControlVersion", $Publisher.GetCurrentModuleVersion()); }catch{} try{ $azureContext = Get-AzureRmContext try{ $Properties.Add([TelemetryKeys]::SubscriptionId, [RemoteReportHelper]::Mask($azureContext.Subscription.Id)) }catch{} try{ $Properties.Add([TelemetryKeys]::SubscriptionName, [RemoteReportHelper]::Mask($azureContext.Subscription.Name)) }catch{} try{ $Properties.Add("AzureEnv", $azureContext.Environment.Name) }catch{} try{ $Properties.Add("TenantId", [RemoteReportHelper]::Mask($azureContext.Tenant.Id)) }catch{} try{ $Properties.Add("AccountId", [RemoteReportHelper]::Mask($azureContext.Account.Id)) }catch{} try{ $Properties.Add("RunIdentifier", [RemoteReportHelper]::Mask($azureContext.Account.Id + '##' + $Publisher.RunIdentifier)); }catch{ $Properties.Add("RunIdentifier", $Publisher.RunIdentifier); } try{ $Properties.Add("AccountType", $azureContext.Account.Type) }catch{} }catch{ } } catch{ } } hidden static [string] AnonScriptStackTrace([string] $ScriptStackTrace) { try{ $ScriptStackTrace = $ScriptStackTrace.Replace($env:USERNAME, "USERNAME") $lines = $ScriptStackTrace.Split([System.Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) $newLines = $lines | ForEach-Object { $line = $_ $lineSplit = $line.Split(@(", "), [System.StringSplitOptions]::RemoveEmptyEntries); if($lineSplit.Count -eq 2){ $filePath = $lineSplit[1]; $startMarker = $filePath.IndexOf("AzSK") if($startMarker -gt 0){ $anonFilePath = $filePath.Substring($startMarker, $filePath.Length - $startMarker) $newLine = $lineSplit[0] + ", " + $anonFilePath $newLine } else{ $line } } else{ $line } } return ($newLines | Out-String) } catch{ return $ScriptStackTrace } } } |