/// <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));
 }
Exemple #2
0
 /// <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;
 }
Exemple #3
0
 /// <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;
 }
Exemple #4
0
        /// <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;
        }
Exemple #5
0
 /// <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 },
 };
Exemple #6
0
        /// <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();
        }
Exemple #7
0
 /// <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 },
 };
Exemple #8
0
        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();
                    }
                }
            });
        }
Exemple #9
0
        /// <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;
        }
Exemple #12
0
        /// <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;
        }
Exemple #13
0
        /// <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;
            });
        }
Exemple #14
0
        /// <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));
                    }
                }
            }
        }
Exemple #16
0
        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);
            }
        }
Exemple #18
0
 /// <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();
 }