/// <summary> /// Constructs a new instance of <see cref="AzPredictorTelemetryClient"/>. /// </summary> /// <param name="azContext">The Az context which this module runs with.</param> public AzPredictorTelemetryClient(IAzContext azContext) { _telemetryClient = GetApplicationInsightTelemetryClient(); _azContext = azContext; _telemetryDispatcher = new ActionBlock <ITelemetryData>( (telemetryData) => DispatchTelemetryData(telemetryData)); }
/// <summary> /// Constructs a new instance of <see cref="AzPredictor"/>. /// </summary> /// <param name="service">The service that provides the suggestion.</param> /// <param name="telemetryClient">The client to collect telemetry.</param> /// <param name="settings">The settings for <see cref="AzPredictor"/>.</param> /// <param name="azContext">The Az context which this module runs in.</param> public AzPredictor(IAzPredictorService service, ITelemetryClient telemetryClient, Settings settings, IAzContext azContext) { _service = service; _telemetryClient = telemetryClient; _settings = settings; _azContext = azContext; }
/// <summary> /// Constructs a new instance of <see cref="AzPredictor"/> for testing. /// </summary> /// <param name="service">The service that provides the suggestion.</param> /// <param name="telemetryClient">The client to collect telemetry.</param> /// <param name="settings">The settings for <see cref="AzPredictor"/>.</param> /// <param name="azContext">The Az context which this module runs in.</param> internal AzPredictor(IAzPredictorService service, ITelemetryClient telemetryClient, Settings settings, IAzContext azContext) { _service = service; _telemetryClient = telemetryClient; _settings = settings; _azContext = azContext; _isInitialized = true; }
/// <summary> /// Constructs a new instance of <see cref="AzPredictorTelemetryClient"/> /// </summary> /// <param name="azContext">The Az context which this module runs with</param> public AzPredictorTelemetryClient(IAzContext azContext) { TelemetryConfiguration configuration = TelemetryConfiguration.CreateDefault(); configuration.InstrumentationKey = "7df6ff70-8353-4672-80d6-568517fed090"; // Use Azuer-PowerShell instrumentation key. see https://github.com/Azure/azure-powershell-common/blob/master/src/Common/AzurePSCmdlet.cs _telemetryClient = new TelemetryClient(configuration); _telemetryClient.Context.Location.Ip = "0.0.0.0"; _telemetryClient.Context.Cloud.RoleInstance = "placeholderdon'tuse"; _telemetryClient.Context.Cloud.RoleName = "placeholderdon'tuse"; _azContext = azContext; }
/// <summary> /// Creates common telemetry properties. /// </summary> public static IDictionary <string, string> CreateCommonProperties(IAzContext azContext) => new Dictionary <string, string>() { { "SessionId", TelemetryUtilities.SessionId }, { "Cohort", azContext.Cohort.ToString(CultureInfo.InvariantCulture) }, { "UserId", azContext.HashUserId }, { "IsInternal", azContext.IsInternal.ToString(CultureInfo.InvariantCulture) }, { "HashMacAddress", azContext.MacAddress }, { "PowerShellVersion", azContext.PowerShellVersion.ToString() }, { "ModuleVersion", azContext.ModuleVersion.ToString() }, { "OS", azContext.OSVersion }, };
/// <summary> /// The AzPredictor service interacts with the Aladdin service specified in serviceUri. /// At initialization, it requests a list of the popular commands. /// </summary> /// <param name="serviceUri">The URI of the Aladdin service.</param> /// <param name="telemetryClient">The telemetry client.</param> /// <param name="azContext">The Az context which this module runs with</param> public AzPredictorService(string serviceUri, ITelemetryClient telemetryClient, IAzContext azContext) { this._commandsEndpoint = $"{serviceUri}{AzPredictorConstants.CommandsEndpoint}?clientType={AzPredictorService.ClientType}&context={JsonConvert.SerializeObject(new CommandRequestContext())}"; this._predictionsEndpoint = serviceUri + AzPredictorConstants.PredictionsEndpoint; this._telemetryClient = telemetryClient; this._azContext = azContext; this._client = new HttpClient(); this._client.DefaultRequestHeaders?.Add(AzPredictorService.ThrottleByIdHeader, this._azContext.UserId); RequestCommands(); }
/// <summary> /// Creates common telemetry properties. /// </summary> public static IDictionary <string, string> CreateCommonProperties(IAzContext azContext) => new Dictionary <string, string>() { { "SessionId", TelemetryUtilities.SessionId }, { "Cohort", azContext.Cohort.ToString(CultureInfo.InvariantCulture) }, { "UserId", azContext.HashUserId }, { "IsInternal", azContext.IsInternal.ToString(CultureInfo.InvariantCulture) }, { "SurveyId", (azContext as AzContext)?.SurveyId }, // This is supposed to be temporarily. We should remove SurveyId. { "HashMacAddress", azContext.MacAddress }, { "PowerShellVersion", azContext.PowerShellVersion.ToString() }, { "ModuleVersion", azContext.ModuleVersion.ToString() }, { "OS", azContext.OSVersion }, };
public ParameterValuePredictor(ITelemetryClient telemetryClient, IAzContext azContext) { Validation.CheckArgument(telemetryClient, $"{nameof(telemetryClient)} cannot be null."); _telemetryClient = telemetryClient; _azContext = azContext; var fileInfo = new FileInfo(typeof(Settings).Assembly.Location); var directory = fileInfo.DirectoryName; var mappingFilePath = Path.Join(directory, "command_param_to_resource_map.json"); Exception exception = null; try { _commandParamToResourceMap = JsonSerializer.Deserialize <Dictionary <string, Dictionary <string, string> > >(File.ReadAllText(mappingFilePath), JsonUtilities.DefaultSerializerOptions); } catch (Exception e) { // We don't want it to crash the module when the file doesn't exist or when it's mal-formatted. exception = e; } _telemetryClient.OnLoadParameterMap(new ParameterMapTelemetryData(exception)); String path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); string[] paths = new string[] { path, "Microsoft", "Windows", "PowerShell", "AzPredictor", "paramValueHistory.json" }; _paramValueHistoryFilePath = System.IO.Path.Combine(paths); Directory.CreateDirectory(Path.GetDirectoryName(_paramValueHistoryFilePath)); Task.Run(() => { if (System.IO.File.Exists(_paramValueHistoryFilePath)) { _mutex.WaitOne(); try { var localParameterValues = JsonSerializer.Deserialize <ConcurrentDictionary <string, string> >(File.ReadAllText(_paramValueHistoryFilePath), JsonUtilities.DefaultSerializerOptions); foreach (var v in localParameterValues) { _localParameterValues.AddOrUpdate(v.Key, key => v.Value, (key, oldValue) => oldValue); } } finally { _mutex.ReleaseMutex(); } } }); }
/// <summary> /// Creates a new instance of <see cref="AzPredictorService"/>. /// </summary> /// <param name="serviceUri">The URI of the Aladdin service.</param> /// <param name="telemetryClient">The telemetry client.</param> /// <param name="azContext">The Az context which this module runs in.</param> public AzPredictorService(string serviceUri, ITelemetryClient telemetryClient, IAzContext azContext) { Validation.CheckArgument(!string.IsNullOrWhiteSpace(serviceUri), $"{nameof(serviceUri)} cannot be null or whitespace."); Validation.CheckArgument(telemetryClient, $"{nameof(telemetryClient)} cannot be null."); Validation.CheckArgument(azContext, $"{nameof(azContext)} cannot be null."); _commandsEndpoint = $"{serviceUri}{AzPredictorConstants.CommandsEndpoint}?clientType={AzPredictorService.ClientType}&context.versionNumber={azContext.AzVersion}"; _predictionsEndpoint = serviceUri + AzPredictorConstants.PredictionsEndpoint; _telemetryClient = telemetryClient; _azContext = azContext; _client = new HttpClient(); RequestAllPredictiveCommands(); }
/// <summary> /// Creates a new instance of <see cref="AzPredictorService"/>. /// </summary> /// <param name="serviceUri">The URI of the Aladdin service.</param> /// <param name="telemetryClient">The telemetry client.</param> /// <param name="azContext">The Az context which this module runs in.</param> public AzPredictorService(string serviceUri, ITelemetryClient telemetryClient, IAzContext azContext) { Validation.CheckArgument(!string.IsNullOrWhiteSpace(serviceUri), $"{nameof(serviceUri)} cannot be null or whitespace."); Validation.CheckArgument(telemetryClient, $"{nameof(telemetryClient)} cannot be null."); Validation.CheckArgument(azContext, $"{nameof(azContext)} cannot be null."); _commandsEndpoint = $"{serviceUri}{AzPredictorConstants.CommandsEndpoint}?clientType={AzPredictorService.ClientType}&context={JsonSerializer.Serialize(new CommandRequestContext(), JsonUtilities.DefaultSerializerOptions)}"; _predictionsEndpoint = serviceUri + AzPredictorConstants.PredictionsEndpoint; _telemetryClient = telemetryClient; _azContext = azContext; _client = new HttpClient(); RequestAllPredictiveCommands(); }
/// <summary> /// Create a new instance of <see cref="CommandLine"/> from <see cref="PredictiveCommand" />. /// </summary> /// <param name="predictiveCommand">The command information.</param> /// <param name="azContext">The current PowerShell conext.</param> public CommandLine(PredictiveCommand predictiveCommand, IAzContext azContext = null) { Validation.CheckArgument(predictiveCommand, $"{nameof(predictiveCommand)} cannot be null."); var predictionText = CommandLineUtilities.EscapePredictionText(predictiveCommand.Command); var commandAst = CommandLineUtilities.GetCommandAst(predictionText); var commandName = commandAst?.GetCommandName(); Validation.CheckInvariant <CommandLineException>(!string.IsNullOrWhiteSpace(commandName), $"Cannot get the command name from the model {predictiveCommand.Command}"); var parameterSet = new ParameterSet(commandAst, azContext); Name = commandName; Description = predictiveCommand.Description; ParameterSet = parameterSet; SourceText = predictiveCommand.Command; }
/// <summary> /// Create a new instance of <see cref="CommandLine"/> from <see cref="PredictiveCommand" />. /// </summary> /// <param name="predictiveCommand">The command information.</param> /// <param name="azContext">The current PowerShell conext.</param> public CommandLine(PredictiveCommand predictiveCommand, IAzContext azContext = null) { Validation.CheckArgument(predictiveCommand, $"{nameof(predictiveCommand)} cannot be null."); var predictionText = CommandLineUtilities.EscapePredictionText(predictiveCommand.Command); Ast ast = Parser.ParseInput(predictionText, out Token[] tokens, out _); var commandAst = ast.Find((ast) => ast is CommandAst, searchNestedScriptBlocks: false) as CommandAst; var commandName = commandAst?.GetCommandName(); Validation.CheckInvariant <CommandLineException>(!string.IsNullOrWhiteSpace(commandName), $"Cannot get the command name from the model {predictiveCommand.Command}"); var parameterSet = new ParameterSet(commandAst, azContext); Name = commandName; Description = predictiveCommand.Description; ParameterSet = parameterSet; SourceText = predictiveCommand.Command; }
/// <summary> /// Constructs a new instance of <see cref="AzPredictor"/> to use in PowerShell's prediction subsystem. /// </summary> public AzPredictor() { // To make import-module fast, we'll do all the initialization in a task. // Slow initialization may make opening a PowerShell window slow if "Import-Module" is added to the user's profile. Task.Run(() => { _settings = Settings.GetSettings(); var azContext = new AzContext() { IsInternal = (_settings.SetAsInternal == true) ? true : false, SurveyId = _settings.SurveyId?.ToString(CultureInfo.InvariantCulture) ?? string.Empty, }; RegisterDisposableObject(azContext); _azContext = azContext; _azContext.UpdateContext(); _telemetryClient = new AzPredictorTelemetryClient(_azContext); _service = new AzPredictorService(_settings.ServiceUri, _telemetryClient, _azContext); _isInitialized = true; }); }
/// <summary> /// Constructs a new instance of <see cref="AzPredictor"/> to use in PowerShell's prediction subsystem. /// </summary> public AzPredictor() { _powerShellRuntime = new PowerShellRuntime(); _surveyHelper = new AzPredictorSurveyHelper(_powerShellRuntime); // To make import-module fast, we'll do all the initialization in a task. // Slow initialization may make opening a PowerShell window slow if "Import-Module" is added to the user's profile. Task.Run(() => { _settings = Settings.GetSettings(); _azContext = new AzContext(_powerShellRuntime) { IsInternal = (_settings.SetAsInternal == true) ? true : false, }; _azContext.UpdateContext(); // This will run the script in the right context. var _ = _azContext.PowerShellVersion; _telemetryClient = new AzPredictorTelemetryClient(_azContext); _service = new AzPredictorService(_settings.ServiceUri, _telemetryClient, _azContext); _isInitialized = true; }); }
/// <summary> /// Creates a new instance of <see cref="CommandLinePredictor"/>. /// </summary> /// <param name="modelPredictions">List of suggestions from the model, sorted by frequency (most to least).</param> /// <param name="parameterValuePredictor">Provide the prediction to the parameter values.</param> /// <param name="telemetryClient">The telemetry client.</param> /// <param name="azContext">The current PowerShell conext.</param> public CommandLinePredictor(IList <PredictiveCommand> modelPredictions, ParameterValuePredictor parameterValuePredictor, ITelemetryClient telemetryClient, IAzContext azContext = null) { Validation.CheckArgument(modelPredictions, $"{nameof(modelPredictions)} cannot be null."); _telemetryClient = telemetryClient; _parameterValuePredictor = parameterValuePredictor; var commnadLines = new List <CommandLine>(); if (modelPredictions != null) { for (var i = 0; i < modelPredictions.Count; ++i) { try { this._commandLinePredictions.Add(new CommandLine(modelPredictions[i], azContext)); } catch (Exception e) { _telemetryClient?.OnParseCommandLineFailure(new CommandLineParsingTelemetryData(modelPredictions[i].Command, e)); } } } }
public ParameterSet(CommandAst commandAst, IAzContext azContext = null) { Validation.CheckArgument(commandAst, $"{nameof(commandAst)} cannot be null."); _commandAst = commandAst; _azContext = azContext; var parameters = new List <Parameter>(); CommandParameterAst param = null; Ast arg = null; // positional parameters must be before named parameters. // This loop will convert them to named parameters. // Loop through all the parameters. The first element of CommandElements is the command name, so skip it. bool hasSeenNamedParameter = false; bool hasSeenIncompleteParameter = false; for (var i = 1; i < commandAst.CommandElements.Count(); ++i) { var elem = commandAst.CommandElements[i]; if (elem is CommandParameterAst p) { if (hasSeenIncompleteParameter) { throw new CommandLineException("'-' is in the middle of the parameter list."); } hasSeenNamedParameter = true; AddNamedParameter(param, arg); // In case there is a switch parameter, we store the parameter name/value and add them when we see the next pair. param = p; arg = null; } else if (AzPredictorConstants.ParameterIndicator == elem?.ToString().Trim().FirstOrDefault()) { // We have an incomplete command line such as // `New-AzResourceGroup -Name ResourceGroup01 -Location WestUS -` // We'll ignore the incomplete parameter. AddNamedParameter(param, arg); param = null; arg = null; hasSeenIncompleteParameter = true; parameters.Add(new Parameter(AzPredictorConstants.DashParameterName, null, false)); } else { if (hasSeenIncompleteParameter || (hasSeenNamedParameter && param == null)) { throw new CommandLineException("Positional parameters must be before named parameters."); } if (param == null) { // This is a positional parameter. var pair = BoundParameters.First((pair) => pair.Value.Value == elem); var parameterName = pair.Key; var parameterValue = CommandLineUtilities.EscapePredictionText(pair.Value.Value.ToString()); parameters.Add(new Parameter(parameterName, parameterValue, true)); BoundParameters.Remove(pair); // Remove it so that we can match another parameter with the same value. } else { arg = elem; AddNamedParameter(param, arg); param = null; arg = null; } } } Validation.CheckInvariant <CommandLineException>((param != null) || (arg == null)); AddNamedParameter(param, arg); Parameters = parameters; void AddNamedParameter(CommandParameterAst parameter, Ast parameterValue) { if (parameter != null) { var value = parameterValue?.ToString(); if (value == null) { value = parameter.Argument?.ToString(); } if (value != null) { value = CommandLineUtilities.UnescapePredictionText(value); } parameters.Add(new Parameter(parameter.ParameterName, value, false)); } } }
/// <summary> /// Constructs a new instance of <see cref="MockAzPredictorService"/> /// </summary> /// <param name="history">The history that the suggestion is for</param> /// <param name="suggestions">The suggestions collection</param> /// <param name="commands">The commands collection</param> /// <param name="azContext">The Az context which this module runs in.</param> public MockAzPredictorService(string history, IList <PredictiveCommand> suggestions, IList <PredictiveCommand> commands, IAzContext azContext) : base(azContext) { ResetRequestPredictionTask(); if (history != null) { SetCommandToRequestPrediction(history); if (suggestions != null) { SetCommandBasedPreditor(history, suggestions); } } if (commands != null) { SetFallbackPredictor(commands); } }
/// <summary> /// A default constructor for the derived class. This is used in test cases. /// </summary> /// <param name="azContext">The Az context which this module runs in.</param> protected AzPredictorService(IAzContext azContext) { _azContext = azContext; RequestAllPredictiveCommands(); }