Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
Telemetry.cs1028 linesDownload Raw Back to utils
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Diagnostics;7using System.IO;8using System.Linq;9using System.Management.Automation;10using System.Runtime.InteropServices;11using System.Threading;12 13using Microsoft.ApplicationInsights;14using Microsoft.ApplicationInsights.Metrics;15using Microsoft.ApplicationInsights.Channel;16using Microsoft.ApplicationInsights.Extensibility;17using Microsoft.ApplicationInsights.Extensibility.Implementation;18 19namespace Microsoft.PowerShell.Telemetry20{21    /// <summary>22    /// The category of telemetry.23    /// </summary>24    internal enum TelemetryType25    {26        /// <summary>27        /// Telemetry of the application type (cmdlet, script, etc).28        /// </summary>29        ApplicationType,30 31        /// <summary>32        /// Send telemetry when we load a module, only module names in the s_knownModules list33        /// will be reported, otherwise it will be "anonymous".34        /// </summary>35        ModuleLoad,36 37        /// <summary>38        /// Send telemetry when we load a module using Windows compatibility feature, only module names in the s_knownModules list39        /// will be reported, otherwise it will be "anonymous".40        /// </summary>41        WinCompatModuleLoad,42 43        /// <summary>44        /// Send telemetry for experimental module feature deactivation.45        /// All experimental engine features will be have telemetry.46        /// </summary>47        ExperimentalEngineFeatureDeactivation,48 49        /// <summary>50        /// Send telemetry for experimental module feature activation.51        /// All experimental engine features will be have telemetry.52        /// </summary>53        ExperimentalEngineFeatureActivation,54 55        /// <summary>56        /// Send telemetry for an experimental feature when use.57        /// </summary>58        ExperimentalFeatureUse,59 60        /// <summary>61        /// Send telemetry for experimental module feature deactivation.62        /// Experimental module features will send telemetry based on the module it is in.63        /// If we send telemetry for the module, we will also do so for any experimental feature64        /// in that module.65        /// </summary>66        ExperimentalModuleFeatureDeactivation,67 68        /// <summary>69        /// Send telemetry for experimental module feature activation.70        /// Experimental module features will send telemetry based on the module it is in.71        /// If we send telemetry for the module, we will also do so for any experimental feature72        /// in that module.73        /// </summary>74        ExperimentalModuleFeatureActivation,75 76        /// <summary>77        /// Send telemetry for each PowerShell.Create API.78        /// </summary>79        PowerShellCreate,80 81        /// <summary>82        /// Remote session creation.83        /// </summary>84        RemoteSessionOpen,85 86        /// <summary>87        /// Send telemetry for a stable feature when used.88        /// By making a distinction between this and experimental feature use, it will make89        /// queries much easier.90        /// </summary>91        FeatureUse,92    }93 94    /// <summary>95    /// Set up the telemetry initializer to mask the platform specific names.96    /// </summary>97    internal class NameObscurerTelemetryInitializer : ITelemetryInitializer98    {99        // Report the platform name information as "na".100        private const string _notavailable = "na";101 102        /// <summary>103        /// Initialize properties we are obscuring to "na".104        /// </summary>105        /// <param name="telemetry">The instance of our telemetry.</param>106        public void Initialize(ITelemetry telemetry)107        {108            telemetry.Context.Cloud.RoleName = _notavailable;109            telemetry.Context.GetInternalContext().NodeName = _notavailable;110            telemetry.Context.Cloud.RoleInstance = _notavailable;111        }112    }113 114    /// <summary>115    /// Send up telemetry for startup.116    /// </summary>117    public static class ApplicationInsightsTelemetry118    {119        // The string for SubsystermRegistration120        internal const string s_subsystemRegistration = "Subsystem.Registration";121 122        // If this env var is true, yes, or 1, telemetry will NOT be sent.123        private const string _telemetryOptoutEnvVar = "POWERSHELL_TELEMETRY_OPTOUT";124 125        // PSCoreInsight2 telemetry key126        // private const string _psCoreTelemetryKey = "ee4b2115-d347-47b0-adb6-b19c2c763808"; // Production127        private const string _psCoreTelemetryKey = "d26a5ef4-d608-452c-a6b8-a4a55935f70d"; // V7 Preview 3128 129        // In the event there is a problem in creating the node identifier file, use the default identifier.130        // This can happen if we are running in a system which has a read-only filesystem.131        private static readonly Guid _defaultNodeIdentifier = new Guid("2f998828-3f4a-4741-bf50-d11c6be42f50");132 133        // Use "anonymous" as the string to return when you can't report a name134        private const string Anonymous = "anonymous";135 136        // Use '0.0' as the string for an anonymous module version137        private const string AnonymousVersion = "0.0";138 139        // Use 'n/a' as the string when there's no tag to report140        private const string NoTag = "n/a";141 142        // the telemetry failure string143        private const string _telemetryFailure = "TELEMETRY_FAILURE";144 145        // Telemetry client to be reused when we start sending more telemetry146        private static TelemetryClient s_telemetryClient { get; }147 148        // the unique identifier for the user, when we start we149        private static string s_uniqueUserIdentifier { get; }150 151        // the session identifier152        private static string s_sessionId { get; }153 154        // private semaphore to determine whether we sent the startup telemetry event155        private static int s_startupEventSent = 0;156 157        /// Use a hashset for quick lookups.158        /// We send telemetry only a known set of modules and tags.159        /// If it's not in the list (initialized in the static constructor), then we report anonymous160        /// or don't report anything (in the case of tags).161        private static readonly HashSet<string> s_knownModules;162        private static readonly HashSet<string> s_knownModuleTags;163 164        private static readonly HashSet<string> s_knownSubsystemNames;165 166        private static readonly string s_uuidPath;167 168        /// <summary>Gets a value indicating whether telemetry can be sent.</summary>169        public static bool CanSendTelemetry { get; private set; }170 171        /// <summary>172        /// Initializes static members of the <see cref="ApplicationInsightsTelemetry"/> class.173        /// Static constructor determines whether telemetry is to be sent, and then174        /// sets the telemetry key and set the telemetry delivery mode.175        /// Creates the session ID and initializes the HashSet of known module names.176        /// Gets or constructs the unique identifier.177        /// </summary>178        static ApplicationInsightsTelemetry()179        {180            // If we can't send telemetry, there's no reason to do any of this181            CanSendTelemetry = !Utils.GetEnvironmentVariableAsBool(name: _telemetryOptoutEnvVar, defaultValue: false)182                && Platform.TryDeriveFromCache("telemetry.uuid", out s_uuidPath);183 184            if (!CanSendTelemetry)185            {186                return;187            }188 189            s_sessionId = Guid.NewGuid().ToString();190            TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault();191            configuration.ConnectionString = "InstrumentationKey=" + _psCoreTelemetryKey;192 193            // Set this to true to reduce latency during development194            configuration.TelemetryChannel.DeveloperMode = false;195 196            // Be sure to obscure any information about the client node name.197            configuration.TelemetryInitializers.Add(new NameObscurerTelemetryInitializer());198 199            s_telemetryClient = new TelemetryClient(configuration);200 201            // use a hashset when looking for module names, it should be quicker than a string comparison202            s_knownModules = new HashSet<string>(StringComparer.OrdinalIgnoreCase)203            {204                "AADRM",205                "activedirectory",206                "adcsadministration",207                "adcsdeployment",208                "addsadministration",209                "addsdeployment",210                "adfs",211                "adrms",212                "adrmsadmin",213                "agpm",214                "AIShell",215                "appbackgroundtask",216                "applocker",217                "appv",218                "appvclient",219                "appvsequencer",220                "appvserver",221                "appx",222                "assignedaccess",223                "Az",224                "Az.Accounts",225                "Az.Advisor",226                "Az.Aks",227                "Az.AlertsManagement",228                "Az.AnalysisServices",229                "Az.ApiManagement",230                "Az.ApplicationInsights",231                "Az.Attestation",232                "Az.Automation",233                "Az.Batch",234                "Az.Billing",235                "Az.Blueprint",236                "Az.Cdn",237                "Az.CognitiveServices",238                "Az.Compute",239                "Az.ContainerInstance",240                "Az.ContainerRegistry",241                "Az.DataBox",242                "Az.DataFactory",243                "Az.DataLakeAnalytics",244                "Az.DataLakeStore",245                "Az.DataMigration",246                "Az.DataShare",247                "Az.DeploymentManager",248                "Az.DeviceProvisioningServices",249                "Az.DevSpaces",250                "Az.DevTestLabs",251                "Az.Dns",252                "Az.EventGrid",253                "Az.EventHub",254                "Az.FrontDoor",255                "Az.GuestConfiguration",256                "Az.HDInsight",257                "Az.HealthcareApis",258                "Az.IotCentral",259                "Az.IotHub",260                "Az.KeyVault",261                "Az.Kusto",262                "Az.LogicApp",263                "Az.MachineLearning",264                "Az.ManagedServiceIdentity",265                "Az.ManagedServices",266                "Az.ManagementPartner",267                "Az.Maps",268                "Az.MarketplaceOrdering",269                "Az.Media",270                "Az.MixedReality",271                "Az.Monitor",272                "Az.NetAppFiles",273                "Az.Network",274                "Az.NotificationHubs",275                "Az.OperationalInsights",276                "Az.Peering",277                "Az.PolicyInsights",278                "Az.PowerBIEmbedded",279                "Az.PrivateDns",280                "Az.RecoveryServices",281                "Az.RedisCache",282                "Az.Relay",283                "Az.Reservations",284                "Az.ResourceGraph",285                "Az.Resources",286                "Az.Search",287                "Az.Security",288                "Az.ServiceBus",289                "Az.ServiceFabric",290                "Az.SignalR",291                "Az.Sql",292                "Az.Storage",293                "Az.StorageSync",294                "Az.StorageTable",295                "Az.StreamAnalytics",296                "Az.Subscription",297                "Az.Tools.Predictor",298                "Az.TrafficManager",299                "Az.Websites",300                "Azs.Azurebridge.Admin",301                "Azs.Backup.Admin",302                "Azs.Commerce.Admin",303                "Azs.Compute.Admin",304                "Azs.Fabric.Admin",305                "Azs.Gallery.Admin",306                "Azs.Infrastructureinsights.Admin",307                "Azs.Keyvault.Admin",308                "Azs.Network.Admin",309                "Azs.Storage.Admin",310                "Azs.Subscriptions",311                "Azs.Subscriptions.Admin",312                "Azs.Update.Admin",313                "AzStorageTable",314                "Azure",315                "Azure.AnalysisServices",316                "Azure.Storage",317                "AzureAD",318                "AzureInformationProtection",319                "AzureRM.Aks",320                "AzureRM.AnalysisServices",321                "AzureRM.ApiManagement",322                "AzureRM.ApplicationInsights",323                "AzureRM.Automation",324                "AzureRM.Backup",325                "AzureRM.Batch",326                "AzureRM.Billing",327                "AzureRM.Cdn",328                "AzureRM.CognitiveServices",329                "AzureRm.Compute",330                "AzureRM.Compute.ManagedService",331                "AzureRM.Consumption",332                "AzureRM.ContainerInstance",333                "AzureRM.ContainerRegistry",334                "AzureRM.DataFactories",335                "AzureRM.DataFactoryV2",336                "AzureRM.DataLakeAnalytics",337                "AzureRM.DataLakeStore",338                "AzureRM.DataMigration",339                "AzureRM.DeploymentManager",340                "AzureRM.DeviceProvisioningServices",341                "AzureRM.DevSpaces",342                "AzureRM.DevTestLabs",343                "AzureRm.Dns",344                "AzureRM.EventGrid",345                "AzureRM.EventHub",346                "AzureRM.FrontDoor",347                "AzureRM.HDInsight",348                "AzureRm.Insights",349                "AzureRM.IotCentral",350                "AzureRM.IotHub",351                "AzureRm.Keyvault",352                "AzureRM.LocationBasedServices",353                "AzureRM.LogicApp",354                "AzureRM.MachineLearning",355                "AzureRM.MachineLearningCompute",356                "AzureRM.ManagedServiceIdentity",357                "AzureRM.ManagementPartner",358                "AzureRM.Maps",359                "AzureRM.MarketplaceOrdering",360                "AzureRM.Media",361                "AzureRM.Network",362                "AzureRM.NotificationHubs",363                "AzureRM.OperationalInsights",364                "AzureRM.PolicyInsights",365                "AzureRM.PowerBIEmbedded",366                "AzureRM.Profile",367                "AzureRM.RecoveryServices",368                "AzureRM.RecoveryServices.Backup",369                "AzureRM.RecoveryServices.SiteRecovery",370                "AzureRM.RedisCache",371                "AzureRM.Relay",372                "AzureRM.Reservations",373                "AzureRM.ResourceGraph",374                "AzureRM.Resources",375                "AzureRM.Scheduler",376                "AzureRM.Search",377                "AzureRM.Security",378                "AzureRM.ServerManagement",379                "AzureRM.ServiceBus",380                "AzureRM.ServiceFabric",381                "AzureRM.SignalR",382                "AzureRM.SiteRecovery",383                "AzureRM.Sql",384                "AzureRm.Storage",385                "AzureRM.StorageSync",386                "AzureRM.StreamAnalytics",387                "AzureRM.Subscription",388                "AzureRM.Subscription.Preview",389                "AzureRM.Tags",390                "AzureRM.TrafficManager",391                "AzureRm.UsageAggregates",392                "AzureRm.Websites",393                "AzureRmStorageTable",394                "bestpractices",395                "bitlocker",396                "bitstransfer",397                "booteventcollector",398                "branchcache",399                "CimCmdlets",400                "clusterawareupdating",401                "CompatPowerShellGet",402                "configci",403                "ConfigurationManager",404                "CompletionPredictor",405                "DataProtectionManager",406                "dcbqos",407                "deduplication",408                "defender",409                "devicehealthattestation",410                "dfsn",411                "dfsr",412                "dhcpserver",413                "directaccessclient",414                "directaccessclientcomponent",415                "directaccessclientcomponents",416                "dism",417                "dnsclient",418                "dnsserver",419                "ElasticDatabaseJobs",420                "EventTracingManagement",421                "failoverclusters",422                "fileserverresourcemanager",423                "FIMAutomation",424                "GPRegistryPolicy",425                "grouppolicy",426                "hardwarecertification",427                "hcs",428                "hgsattestation",429                "hgsclient",430                "hgsdiagnostics",431                "hgskeyprotection",432                "hgsserver",433                "hnvdiagnostics",434                "hostcomputeservice",435                "hpc",436                "HPC.ACM",437                "HPC.ACM.API.PS",438                "HPCPack2016",439                "hyper-v",440                "IISAdministration",441                "international",442                "ipamserver",443                "iscsi",444                "iscsitarget",445                "ISE",446                "kds",447                "Microsoft.MBAM",448                "Microsoft.MEDV",449                "MgmtSvcAdmin",450                "MgmtSvcConfig",451                "MgmtSvcMySql",452                "MgmtSvcSqlServer",453                "Microsoft.AzureStack.ReadinessChecker",454                "Microsoft.Crm.PowerShell",455                "Microsoft.DiagnosticDataViewer",456                "Microsoft.DirectoryServices.MetadirectoryServices.Config",457                "Microsoft.Dynamics.Nav.Apps.Management",458                "Microsoft.Dynamics.Nav.Apps.Tools",459                "Microsoft.Dynamics.Nav.Ide",460                "Microsoft.Dynamics.Nav.Management",461                "Microsoft.Dynamics.Nav.Model.Tools",462                "Microsoft.Dynamics.Nav.Model.Tools.Crm",463                "Microsoft.EnterpriseManagement.Warehouse.Cmdlets",464                "Microsoft.Medv.Administration.Commands.WorkspacePackager",465                "Microsoft.PowerApps.Checker.PowerShell",466                "Microsoft.PowerShell.Archive",467                "Microsoft.PowerShell.ConsoleGuiTools",468                "Microsoft.PowerShell.Core",469                "Microsoft.PowerShell.Crescendo",470                "Microsoft.PowerShell.Diagnostics",471                "Microsoft.PowerShell.Host",472                "Microsoft.PowerShell.LocalAccounts",473                "Microsoft.PowerShell.Management",474                "Microsoft.PowerShell.ODataUtils",475                "Microsoft.PowerShell.Operation.Validation",476                "Microsoft.PowerShell.PSAdapter",477                "Microsoft.PowerShell.PSResourceGet",478                "Microsoft.PowerShell.RemotingTools",479                "Microsoft.PowerShell.SecretManagement",480                "Microsoft.PowerShell.SecretStore",481                "Microsoft.PowerShell.Security",482                "Microsoft.PowerShell.TextUtility",483                "Microsoft.PowerShell.Utility",484                "Microsoft.SharePoint.Powershell",485                "Microsoft.SystemCenter.ServiceManagementAutomation",486                "Microsoft.Windows.ServerManager.Migration",487                "Microsoft.WSMan.Management",488                "Microsoft.Xrm.OnlineManagementAPI",489                "Microsoft.Xrm.Tooling.CrmConnector.PowerShell",490                "Microsoft.Xrm.Tooling.PackageDeployment",491                "Microsoft.Xrm.Tooling.PackageDeployment.Powershell",492                "Microsoft.Xrm.Tooling.Testing",493                "MicrosoftPowerBIMgmt",494                "MicrosoftPowerBIMgmt.Data",495                "MicrosoftPowerBIMgmt.Profile",496                "MicrosoftPowerBIMgmt.Reports",497                "MicrosoftPowerBIMgmt.Workspaces",498                "MicrosoftStaffHub",499                "MicrosoftTeams",500                "MIMPAM",501                "mlSqlPs",502                "MMAgent",503                "MPIO",504                "MsDtc",505                "MSMQ",506                "MSOnline",507                "MSOnlineBackup",508                "WmsCmdlets",509                "WmsCmdlets3",510                "NanoServerImageGenerator",511                "NAVWebClientManagement",512                "NetAdapter",513                "NetConnection",514                "NetEventPacketCapture",515                "Netlbfo",516                "Netldpagent",517                "NetNat",518                "Netqos",519                "NetSecurity",520                "NetSwitchtTeam",521                "Nettcpip",522                "Netwnv",523                "NetworkConnectivity",524                "NetworkConnectivityStatus",525                "NetworkController",526                "NetworkControllerDiagnostics",527                "NetworkloadBalancingClusters",528                "NetworkSwitchManager",529                "NetworkTransition",530                "NFS",531                "NPS",532                "OfficeWebapps",533                "OperationsManager",534                "PackageManagement",535                "PartnerCenter",536                "pcsvdevice",537                "pef",538                "Pester",539                "pkiclient",540                "platformidentifier",541                "pnpdevice",542                "PowerShellEditorServices",543                "PowerShellGet",544                "powershellwebaccess",545                "printmanagement",546                "ProcessMitigations",547                "provisioning",548                "PSDesiredStateConfiguration",549                "PSDiagnostics",550                "PSReadLine",551                "PSScheduledJob",552                "PSScriptAnalyzer",553                "PSWorkflow",554                "PSWorkflowUtility",555                "RemoteAccess",556                "RemoteDesktop",557                "RemoteDesktopServices",558                "ScheduledTasks",559                "Secureboot",560                "ServerCore",561                "ServerManager",562                "ServerManagerTasks",563                "ServerMigrationcmdlets",564                "ServiceFabric",565                "Microsoft.Online.SharePoint.PowerShell",566                "shieldedvmdatafile",567                "shieldedvmprovisioning",568                "shieldedvmtemplate",569                "SkypeOnlineConnector",570                "SkypeForBusinessHybridHealth",571                "smbshare",572                "smbwitness",573                "smisconfig",574                "softwareinventorylogging",575                "SPFAdmin",576                "Microsoft.SharePoint.MigrationTool.PowerShell",577                "sqlps",578                "SqlServer",579                "StartLayout",580                "StartScreen",581                "Storage",582                "StorageDsc",583                "storageqos",584                "Storagereplica",585                "Storagespaces",586                "Syncshare",587                "System.Center.Service.Manager",588                "TLS",589                "TroubleshootingPack",590                "TrustedPlatformModule",591                "UEV",592                "UpdateServices",593                "UserAccessLogging",594                "vamt",595                "VirtualMachineManager",596                "vpnclient",597                "WasPSExt",598                "WDAC",599                "WDS",600                "WebAdministration",601                "WebAdministrationDsc",602                "WebApplicationProxy",603                "WebSites",604                "Whea",605                "WhiteboardAdmin",606                "WindowsDefender",607                "WindowsDefenderDsc",608                "WindowsDeveloperLicense",609                "WindowsDiagnosticData",610                "WindowsErrorReporting",611                "WindowServerRackup",612                "WindowsSearch",613                "WindowsServerBackup",614                "WindowsUpdate",615                "WinGetCommandNotFound",616                "wsscmdlets",617                "wsssetup",618                "wsus",619                "xActiveDirectory",620                "xBitLocker",621                "xDefender",622                "xDhcpServer",623                "xDismFeature",624                "xDnsServer",625                "xHyper-V",626                "xHyper-VBackup",627                "xPSDesiredStateConfiguration",628                "xSmbShare",629                "xSqlPs",630                "xStorage",631                "xWebAdministration",632                "xWindowsUpdate",633            };634 635            // use a hashset when looking for module names, it should be quicker than a string comparison636            s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase)637            {638                "CrescendoBuilt",639            };640 641            s_uniqueUserIdentifier = GetUniqueIdentifier().ToString();642            s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)643            {644                "Completion",645                "General Feedback",646                "Windows Package Manager - WinGet",647                "Az Predictor"648            };649        }650 651        /// <summary>652        /// Send module load telemetry as a metric.653        /// For modules we send the module name (if allowed), and the version.654        /// Some modules (CIM) will continue use the string alternative method.655        /// </summary>656        /// <param name="telemetryType">The type of telemetry that we'll be sending.</param>657        /// <param name="moduleInfo">The module to report. If it is not allowed, then it is set to 'anonymous'.</param>658        internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, PSModuleInfo moduleInfo)659        {660            if (!CanSendTelemetry)661            {662                return;663            }664 665            // Package up the module name, version, and known tags as a metric.666            // Note that the allowed tags will be a comma separated list which will need to667            // be handled in the telemetry query.668            try669            {670                string allowedModuleName = GetModuleName(moduleInfo.Name);671                string allowedModuleVersion = allowedModuleName == Anonymous ? AnonymousVersion : moduleInfo.Version?.ToString();672                var allowedModuleTags = moduleInfo.Tags.Where(t => s_knownModuleTags.Contains(t)).Distinct();673                string allowedModuleTagString = allowedModuleTags.Any() ? string.Join(',', allowedModuleTags) : NoTag;674 675                s_telemetryClient.676                    GetMetric(new MetricIdentifier(string.Empty, telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version", "Tag")).677                    TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString);678            }679            catch680            {681                // Ignore errors.682            }683 684        }685 686        /// <summary>687        /// Send module load telemetry as a metric.688        /// For modules we send the module name (if allowed), and the version.689        /// Some modules (CIM) will continue use the string alternative method.690        /// </summary>691        /// <param name="telemetryType">The type of telemetry that we'll be sending.</param>692        /// <param name="moduleName">The module name to report. If it is not allowed, then it is set to 'anonymous'.</param>693        internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, string moduleName)694        {695            if (!CanSendTelemetry)696            {697                return;698            }699 700            try701            {702                string allowedModuleName = GetModuleName(moduleName);703                s_telemetryClient.GetMetric(telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, AnonymousVersion);704            }705            catch706            {707                // Ignore errors.708            }709        }710 711        /// <summary>712        /// Send telemetry as a metric.713        /// </summary>714        /// <param name="metricId">The type of telemetry that we'll be sending.</param>715        /// <param name="data">The specific details about the telemetry.</param>716        /// <param name="value">The count of instances for the telemetry payload.</param>717        internal static void SendTelemetryMetric(TelemetryType metricId, string data, double value = 1.0)718        {719            if (!CanSendTelemetry)720            {721                return;722            }723 724            // These should be handled by SendModuleTelemetryMetric.725            Debug.Assert(metricId != TelemetryType.ModuleLoad, "ModuleLoad should be handled by SendModuleTelemetryMetric.");726            Debug.Assert(metricId != TelemetryType.WinCompatModuleLoad, "WinCompatModuleLoad should be handled by SendModuleTelemetryMetric.");727 728            string metricName = metricId.ToString();729            try730            {731                switch (metricId)732                {733                    case TelemetryType.ApplicationType:734                    case TelemetryType.PowerShellCreate:735                    case TelemetryType.RemoteSessionOpen:736                    case TelemetryType.ExperimentalEngineFeatureActivation:737                    case TelemetryType.ExperimentalEngineFeatureDeactivation:738                    case TelemetryType.ExperimentalFeatureUse:739                    case TelemetryType.FeatureUse:740                        s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, data);741                        break;742                    case TelemetryType.ExperimentalModuleFeatureActivation:743                    case TelemetryType.ExperimentalModuleFeatureDeactivation:744                        string experimentalFeatureName = GetExperimentalFeatureName(data);745                        s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);746                        break;747                }748            }749            catch750            {751                // do nothing, telemetry can't be sent752                // don't send the panic telemetry as if we have failed above, it will likely fail here.753            }754        }755 756        /// <summary>757        /// Send additional information about an feature as it is used.758        /// </summary>759        /// <param name="featureName">The name of the feature.</param>760        /// <param name="detail">The details about the feature use.</param>761        /// <param name="value">The value to report when sending the payload.</param>762        internal static void SendUseTelemetry(string featureName, string detail, double value = 1.0)763        {764            if (!CanSendTelemetry)765            {766                return;767            }768 769            // keep payload small770            if (featureName is null || detail is null || featureName.Length > 33 || detail.Length > 33)771            {772                return;773            }774 775            if (string.Compare(featureName, s_subsystemRegistration, true) == 0)776            {777                SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value);778            }779            else780            {781                SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value);782            }783        }784 785        /// <summary>786        /// Send additional information about an experimental feature as it is used.787        /// </summary>788        /// <param name="featureName">The name of the experimental feature.</param>789        /// <param name="detail">The details about the experimental feature use.</param>790        internal static void SendExperimentalUseData(string featureName, string detail)791        {792            if (!CanSendTelemetry)793            {794                return;795            }796 797            SendTelemetryMetric(TelemetryType.ExperimentalFeatureUse, string.Join(":", featureName, detail));798        }799 800        // Get the experimental feature name. If we can report it, we'll return the name of the feature, otherwise, we'll return "anonymous"801        private static string GetExperimentalFeatureName(string featureNameToValidate)802        {803            // An experimental feature in a module is guaranteed to start with the module name804            // we can strip out the text past the last '.' as the text before that will be the ModuleName805            int lastDotIndex = featureNameToValidate.LastIndexOf('.');806            string moduleName = featureNameToValidate.Substring(0, lastDotIndex);807            if (s_knownModules.Contains(moduleName))808            {809                return featureNameToValidate;810            }811 812            return Anonymous;813        }814 815        // Get the module name. If we can report it, we'll return the name, otherwise, we'll return the string "anonymous"816        private static string GetSubsystemName(string subsystemNameToValidate)817        {818            if (s_knownSubsystemNames.Contains(subsystemNameToValidate))819            {820                return subsystemNameToValidate;821            }822 823            return Anonymous;824        }825 826        // Get the module name. If we can report it, we'll return the name, otherwise, we'll return anonymous.827        private static string GetModuleName(string moduleNameToValidate)828        {829            if (s_knownModules.Contains(moduleNameToValidate))830            {831                return moduleNameToValidate;832            }833 834            return Anonymous;835        }836 837        /// <summary>838        /// Create the startup payload and send it up.839        /// This is done only once during for the console host.840        /// </summary>841        /// <param name="mode">The "mode" of the startup.</param>842        /// <param name="parametersUsed">The parameter bitmap used when starting.</param>843        internal static void SendPSCoreStartupTelemetry(string mode, double parametersUsed)844        {845            // Check if we already sent startup telemetry846            if (Interlocked.CompareExchange(ref s_startupEventSent, 1, 0) == 1)847            {848                return;849            }850 851            if (!CanSendTelemetry)852            {853                return;854            }855 856            // This is the payload which reports the startup information of OS and shell details.857            var properties = new Dictionary<string, string>();858 859            // This is the payload for the parameter data which is sent as a metric.860            var parameters = new Dictionary<string, double>();861 862            // The variable POWERSHELL_DISTRIBUTION_CHANNEL is set in our docker images and863            // by various other environments. This allows us to track the actual docker OS as864            // OSDescription provides only "linuxkit" which has limited usefulness.865            var channel = Environment.GetEnvironmentVariable("POWERSHELL_DISTRIBUTION_CHANNEL");866 867            // Construct the payload for the OS and shell details.868            properties.Add("SessionId", s_sessionId);869            properties.Add("UUID", s_uniqueUserIdentifier);870            properties.Add("GitCommitID", PSVersionInfo.GitCommitId);871            properties.Add("OSDescription", RuntimeInformation.OSDescription);872            properties.Add("RuntimeIdentifier", RuntimeInformation.RuntimeIdentifier);873            properties.Add("OSChannel", string.IsNullOrEmpty(channel) ? "unknown" : channel);874            properties.Add("StartMode", string.IsNullOrEmpty(mode) ? "unknown" : mode);875 876            // Construct the payload for the parameters used.877            parameters.Add("Param", parametersUsed);878            try879            {880                s_telemetryClient.TrackEvent("ConsoleHostStartup", properties, parameters);881            }882            catch883            {884                // do nothing, telemetry cannot be sent885            }886        }887 888        /// <summary>889        /// Try to read the file and collect the guid.890        /// </summary>891        /// <param name="telemetryFilePath">The path to the telemetry file.</param>892        /// <param name="id">The newly created id.</param>893        /// <returns>894        /// The method returns a bool indicating success or failure of creating the id.895        /// </returns>896        private static bool TryGetIdentifier(string telemetryFilePath, out Guid id)897        {898            if (File.Exists(telemetryFilePath))899            {900                // attempt to read the persisted identifier901                const int GuidSize = 16;902                byte[] buffer = new byte[GuidSize];903                try904                {905                    using (FileStream fs = new FileStream(telemetryFilePath, FileMode.Open, FileAccess.Read))906                    {907                        // if the read is invalid, or wrong size, we return it908                        int n = fs.Read(buffer, 0, GuidSize);909                        if (n == GuidSize)910                        {911                            // it's possible this could through912                            id = new Guid(buffer);913                            if (id != Guid.Empty)914                            {915                                return true;916                            }917                        }918                    }919                }920                catch921                {922                    // something went wrong, the file may not exist or not have enough bytes, so return false923                }924            }925 926            id = Guid.Empty;927            return false;928        }929 930        /// <summary>931        /// Try to create a unique identifier and persist it to the telemetry.uuid file.932        /// </summary>933        /// <param name="telemetryFilePath">The path to the persisted telemetry.uuid file.</param>934        /// <returns>935        /// The method node id.936        /// </returns>937        private static Guid CreateUniqueIdentifierAndFile(string telemetryFilePath)938        {939            // one last attempt to retrieve before creating incase we have a lot of simultaneous entry into the mutex.940            Guid id = Guid.Empty;941            if (TryGetIdentifier(telemetryFilePath, out id))942            {943                return id;944            }945 946            // The directory may not exist, so attempt to create it947            // CreateDirectory will simply return the directory if exists948            bool attemptFileCreation = true;949            try950            {951                Directory.CreateDirectory(Path.GetDirectoryName(telemetryFilePath));952            }953            catch954            {955                // There was a problem in creating the directory for the file, do not attempt to create the file.956                // We don't send telemetry here because there are valid reasons for the directory to not exist957                // and not be able to be created.958                attemptFileCreation = false;959            }960 961            // If we were able to create the directory, try to create the file,962            // if this fails we will send telemetry to indicate this and then use the default identifier.963            if (attemptFileCreation)964            {965                try966                {967                    id = Guid.NewGuid();968                    File.WriteAllBytes(telemetryFilePath, id.ToByteArray());969                    return id;970                }971                catch972                {973                    // another bit of telemetry to notify us about a problem with saving the unique id.974                    s_telemetryClient.GetMetric(_telemetryFailure, "Detail").TrackValue(1, "saveuuid");975                }976            }977 978            // all attempts to create an identifier have failed, so use the default node id.979            id = _defaultNodeIdentifier;980            return id;981        }982 983        /// <summary>984        /// Retrieve the unique identifier from the persisted file, if it doesn't exist create it.985        /// Generate a guid which will be used as the UUID.986        /// </summary>987        /// <returns>A guid which represents the unique identifier.</returns>988        private static Guid GetUniqueIdentifier()989        {990            // Try to get the unique id. If this returns false, we'll991            // create/recreate the telemetry.uuid file to persist for next startup.992            Guid id = Guid.Empty;993            if (TryGetIdentifier(s_uuidPath, out id))994            {995                return id;996            }997 998            // Multiple processes may start simultaneously so we need a system wide999            // way to control access to the file in the case (although remote) when we have1000            // simultaneous shell starts without the persisted file which attempt to create the file.1001            try1002            {1003                // CreateUniqueIdentifierAndFile shouldn't throw, but the mutex might1004                using var m = new Mutex(true, "CreateUniqueUserId");1005                m.WaitOne();1006                try1007                {1008                    return CreateUniqueIdentifierAndFile(s_uuidPath);1009                }1010                finally1011                {1012                    m.ReleaseMutex();1013                }1014            }1015            catch (Exception)1016            {1017                // Any problem in generating a uuid will result in no telemetry being sent.1018                // Try to send the failure in telemetry, but it will have no unique id.1019                s_telemetryClient.GetMetric(_telemetryFailure, "Detail").TrackValue(1, "mutex");1020            }1021 1022            // something bad happened, turn off telemetry since the unique id wasn't set.1023            CanSendTelemetry = false;1024            return id;1025        }1026    }1027}1028