diff --git a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs
index 6be8d3c595..5a15df53ca 100644
--- a/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs
+++ b/src/System.Management.Automation/CoreCLR/CorePsAssemblyLoadContext.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.Loader;
+using Microsoft.PowerShell.Telemetry;
namespace System.Management.Automation
{
@@ -607,16 +608,19 @@ namespace System.Management.Automation
[UnmanagedCallersOnly]
public static int LoadAssemblyFromNativeMemory(IntPtr data, int size)
{
+ int result = 0;
try
{
using var stream = new UnmanagedMemoryStream((byte*)data, size);
AssemblyLoadContext.Default.LoadFromStream(stream);
- return 0;
}
catch
{
- return -1;
+ result = -1;
}
+
+ ApplicationInsightsTelemetry.SendUseTelemetry("PowerShellUnsafeAssemblyLoad", result == 0 ? "1" : "0");
+ return result;
}
}
}
diff --git a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs
index f58f51dfd3..41bf4ac352 100644
--- a/src/System.Management.Automation/engine/Modules/ModuleUtils.cs
+++ b/src/System.Management.Automation/engine/Modules/ModuleUtils.cs
@@ -44,8 +44,6 @@ namespace System.Management.Automation.Internal
| FileAttributes.Offline
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN;
-
- return;
}
///
diff --git a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs
index aba105c8fa..328eb4eee8 100644
--- a/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs
+++ b/src/System.Management.Automation/engine/Subsystem/FeedbackSubsystem/IFeedbackProvider.cs
@@ -9,6 +9,7 @@ using System.Management.Automation.Internal;
using System.Management.Automation.Language;
using System.Management.Automation.Runspaces;
using System.Threading;
+using Microsoft.PowerShell.Telemetry;
namespace System.Management.Automation.Subsystem.Feedback
{
@@ -287,13 +288,14 @@ namespace System.Management.Automation.Subsystem.Feedback
.AddParameter("ExpandProperty", "Name")
.Invoke();
- if (results.Count > 0)
- {
- return new FeedbackItem(
- SuggestionStrings.Suggestion_CommandNotFound,
- new List(results),
- FeedbackDisplayLayout.Landscape);
- }
+ if (results.Count > 0)
+ {
+ ApplicationInsightsTelemetry.SendUseTelemetry("FuzzyMatching", "CommandNotFound");
+ return new FeedbackItem(
+ SuggestionStrings.Suggestion_CommandNotFound,
+ new List(results),
+ FeedbackDisplayLayout.Landscape);
+ }
return null;
}
diff --git a/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs b/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs
index c290e807ce..8756fd69c9 100644
--- a/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs
+++ b/src/System.Management.Automation/engine/Subsystem/SubsystemInfo.cs
@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation.Internal;
+using Microsoft.PowerShell.Telemetry;
namespace System.Management.Automation.Subsystem
{
@@ -96,6 +97,7 @@ namespace System.Management.Automation.Subsystem
internal void RegisterImplementation(ISubsystem impl)
{
AddImplementation(impl);
+ ApplicationInsightsTelemetry.SendUseTelemetry(ApplicationInsightsTelemetry.s_subsystemRegistration, impl.Name);
}
internal ISubsystem UnregisterImplementation(Guid id)
diff --git a/src/System.Management.Automation/utils/Telemetry.cs b/src/System.Management.Automation/utils/Telemetry.cs
index ff655bbe60..9e40e60a4d 100644
--- a/src/System.Management.Automation/utils/Telemetry.cs
+++ b/src/System.Management.Automation/utils/Telemetry.cs
@@ -83,6 +83,13 @@ namespace Microsoft.PowerShell.Telemetry
/// Remote session creation.
///
RemoteSessionOpen,
+
+ ///
+ /// Send telemetry for a stable feature when used.
+ /// By making a distinction between this and experimental feature use, it will make
+ /// queries much easier.
+ ///
+ FeatureUse,
}
///
@@ -110,6 +117,9 @@ namespace Microsoft.PowerShell.Telemetry
///
public static class ApplicationInsightsTelemetry
{
+ // The string for SubsystermRegistration
+ internal const string s_subsystemRegistration = "Subsystem.Registration";
+
// If this env var is true, yes, or 1, telemetry will NOT be sent.
private const string _telemetryOptoutEnvVar = "POWERSHELL_TELEMETRY_OPTOUT";
@@ -152,6 +162,8 @@ namespace Microsoft.PowerShell.Telemetry
private static readonly HashSet s_knownModules;
private static readonly HashSet s_knownModuleTags;
+ private static readonly HashSet s_knownSubsystemNames;
+
/// Gets a value indicating whether telemetry can be sent.
public static bool CanSendTelemetry { get; private set; } = false;
@@ -620,6 +632,13 @@ namespace Microsoft.PowerShell.Telemetry
};
s_uniqueUserIdentifier = GetUniqueIdentifier().ToString();
+ s_knownSubsystemNames = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ "Completion",
+ "general",
+ "Windows Package Manager - WinGet",
+ "Az Predictor"
+ };
}
}
@@ -715,7 +734,7 @@ namespace Microsoft.PowerShell.Telemetry
s_telemetryClient.
GetMetric(new MetricIdentifier(string.Empty, telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version", "Tag")).
- TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString);
+ TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString);
}
catch
{
@@ -754,7 +773,8 @@ namespace Microsoft.PowerShell.Telemetry
///
/// The type of telemetry that we'll be sending.
/// The specific details about the telemetry.
- internal static void SendTelemetryMetric(TelemetryType metricId, string data)
+ /// The count of instances for the telemetry payload.
+ internal static void SendTelemetryMetric(TelemetryType metricId, string data, double value = 1.0)
{
if (!CanSendTelemetry)
{
@@ -776,12 +796,13 @@ namespace Microsoft.PowerShell.Telemetry
case TelemetryType.ExperimentalEngineFeatureActivation:
case TelemetryType.ExperimentalEngineFeatureDeactivation:
case TelemetryType.ExperimentalFeatureUse:
- s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, data);
+ case TelemetryType.FeatureUse:
+ s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, data);
break;
case TelemetryType.ExperimentalModuleFeatureActivation:
case TelemetryType.ExperimentalModuleFeatureDeactivation:
string experimentalFeatureName = GetExperimentalFeatureName(data);
- s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);
+ s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);
break;
}
}
@@ -792,6 +813,35 @@ namespace Microsoft.PowerShell.Telemetry
}
}
+ ///
+ /// Send additional information about an feature as it is used.
+ ///
+ /// The name of the feature.
+ /// The details about the feature use.
+ /// The value to report when sending the payload.
+ internal static void SendUseTelemetry(string featureName, string detail, double value = 1.0)
+ {
+ if (!CanSendTelemetry)
+ {
+ return;
+ }
+
+ // keep payload small
+ if (featureName is null || detail is null || featureName.Length > 33 || detail.Length > 33)
+ {
+ return;
+ }
+
+ if (string.Compare(featureName, s_subsystemRegistration, true) == 0)
+ {
+ ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value);
+ }
+ else
+ {
+ ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value);
+ }
+ }
+
///
/// Send additional information about an experimental feature as it is used.
///
@@ -822,7 +872,18 @@ namespace Microsoft.PowerShell.Telemetry
return Anonymous;
}
- // Get the module name. If we can report it, we'll return the name, otherwise, we'll return "anonymous"
+ // Get the module name. If we can report it, we'll return the name, otherwise, we'll return the string "anonymous"
+ private static string GetSubsystemName(string subsystemNameToValidate)
+ {
+ if (s_knownSubsystemNames.Contains(subsystemNameToValidate))
+ {
+ return subsystemNameToValidate;
+ }
+
+ return Anonymous;
+ }
+
+ // Get the module name. If we can report it, we'll return the name, otherwise, we'll return anonymous.
private static string GetModuleName(string moduleNameToValidate)
{
if (s_knownModules.Contains(moduleNameToValidate))