Пример #1
0
        private PowerShellResult InvokePowerShell(PSCommand command)
        {
            using (var powerShell = System.Management.Automation.PowerShell.Create())
            {
                powerShell.RunspacePool = _analysisRunspacePool;
                powerShell.Commands     = command;
                PowerShellResult result = null;
                try
                {
                    Collection <PSObject>          output = InvokePowerShellWithModulePathPreservation(powerShell);
                    PSDataCollection <ErrorRecord> errors = powerShell.Streams.Error;
                    result = new PowerShellResult(output, errors, powerShell.HadErrors);
                }
                catch (CommandNotFoundException ex)
                {
                    // This exception is possible if the module path loaded
                    // is wrong even though PSScriptAnalyzer is available as a module
                    _logger.LogError(ex.Message);
                }
                catch (CmdletInvocationException ex)
                {
                    // We do not want to crash EditorServices for exceptions caused by cmdlet invocation.
                    // Two main reasons that cause the exception are:
                    // * PSCmdlet.WriteOutput being called from another thread than Begin/Process
                    // * CompositionContainer.ComposeParts complaining that "...Only one batch can be composed at a time"
                    _logger.LogError(ex.Message);
                }

                return(result);
            }
        }
Пример #2
0
        private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command, Runspace runspace)
        {
            PowerShellResult result = await InvokePowerShellAsync(command, runspace).ConfigureAwait(false);

            IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult;

            _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count));

            var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count];
            int i             = 0;

            foreach (PSObject diagnostic in diagnosticResults)
            {
                // scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic);
                scriptMarkers[i] = ScriptFileMarker.FromUpgradePlan(diagnostic);
                if (scriptMarkers[i].RuleName != "ReadyToUpgradeCmdletParameter")
                {
                    i++;
                }
            }

            Array.Resize(ref scriptMarkers, i);

            return(scriptMarkers);
        }
        public async Task When_installing()
        {
            var mockApp = GetMock <IApp>();

            mockApp.SetupGet(x => x.AppId).Returns(RandomString());
            mockApp.SetupGet(x => x.InstallScript).Returns(RandomString());
            mockApp.SetupGet(x => x.VerificationScript).Returns(RandomString());
            var app = mockApp.Object;

            var verificationResultPreInstall = new PowerShellResult
            {
                AsString = "False"
            };

            var desktopSystemEntriesPreInstall = new List <string>
            {
                RandomString(),
            };

            var desktopSystemEntriesAddedDuringInstall = new List <string>
            {
                RandomString(),
                RandomString(),
            };

            var desktopSystemEntriesPostInstall =
                desktopSystemEntriesPreInstall.Union(desktopSystemEntriesAddedDuringInstall).ToList();

            bool isPreInstall = true;

            GetMock <IDesktopRepository>().Setup(x => x.LoadSystemEntries()).Returns(() =>
            {
                if (isPreInstall)
                {
                    isPreInstall = false;
                    return(desktopSystemEntriesPreInstall);
                }

                return(desktopSystemEntriesPostInstall);
            });
            GetMock <IPowerShell>().Setup(x => x.ExecuteAsync(app.VerificationScript !))
            .ReturnsAsync(verificationResultPreInstall);

            await BecauseAsync(() => ClassUnderTest.InstallOrUpgradeAsync(app));

            It("logs", () =>
            {
                GetMock <IConsoleLogger>().Verify(x => x.Info($"Installing '{app.AppId}'"));
                GetMock <IConsoleLogger>().Verify(x => x.Result($"Installed '{app.AppId}'"));
            });

            It("runs the install script", () =>
            {
                GetMock <IPowerShell>().Verify(x => x.ExecuteAsync(app.VerificationScript !), Times.Exactly(2));
                GetMock <IPowerShell>().Verify(x => x.ExecuteAsync(app.InstallScript));
            });
Пример #4
0
        /// <summary>
        /// Format a given script text with default codeformatting settings.
        /// </summary>
        /// <param name="scriptDefinition">Script text to be formatted</param>
        /// <param name="settings">ScriptAnalyzer settings</param>
        /// <param name="rangeList">The range within which formatting should be applied.</param>
        /// <returns>The formatted script text.</returns>
        public async Task <string> FormatAsync(
            string scriptDefinition,
            Hashtable settings,
            int[] rangeList)
        {
            // We cannot use Range type therefore this workaround of using -1 default value.
            // Invoke-Formatter throws a ParameterBinderValidationException if the ScriptDefinition is an empty string.
            if (string.IsNullOrEmpty(scriptDefinition))
            {
                return(null);
            }

            var argsDict = new Dictionary <string, object> {
                { "ScriptDefinition", scriptDefinition },
                { "Settings", settings }
            };

            if (rangeList != null)
            {
                argsDict.Add("Range", rangeList);
            }

            PowerShellResult result = await InvokePowerShellAsync("Invoke-Formatter", argsDict);

            if (result == null)
            {
                _logger.Write(LogLevel.Error, "Formatter returned null result");
                return(null);
            }

            if (result.HasErrors)
            {
                var errorBuilder = new StringBuilder().Append(s_indentJoin);
                foreach (ErrorRecord err in result.Errors)
                {
                    errorBuilder.Append(err).Append(s_indentJoin);
                }
                _logger.Write(LogLevel.Warning, $"Errors found while formatting file: {errorBuilder}");
                return(null);
            }

            foreach (PSObject resultObj in result.Output)
            {
                string formatResult = resultObj?.BaseObject as string;
                if (formatResult != null)
                {
                    return(formatResult);
                }
            }

            return(null);
        }
        private async Task <PSObject[]> GetDiagnosticRecordsAsync <TSettings>(
            string scriptContent,
            string[] rules,
            TSettings settings) where TSettings : class
        {
            var diagnosticRecords = s_emptyDiagnosticResult;

            // When a new, empty file is created there are by definition no issues.
            // Furthermore, if you call Invoke-ScriptAnalyzer with an empty ScriptDefinition
            // it will generate a ParameterBindingValidationException.
            if (string.IsNullOrEmpty(scriptContent))
            {
                return(diagnosticRecords);
            }

            if (typeof(TSettings) == typeof(string) || typeof(TSettings) == typeof(Hashtable))
            {
                //Use a settings file if one is provided, otherwise use the default rule list.
                string settingParameter;
                object settingArgument;
                if (settings != null)
                {
                    settingParameter = "Settings";
                    settingArgument  = settings;
                }
                else
                {
                    settingParameter = "IncludeRule";
                    settingArgument  = rules;
                }

                PowerShellResult result = await InvokePowerShellAsync(
                    "Invoke-ScriptAnalyzer",
                    new Dictionary <string, object>
                {
                    { "ScriptDefinition", scriptContent },
                    { settingParameter, settingArgument },
                    // We ignore ParseErrors from PSSA because we already send them when we parse the file.
                    { "Severity", new [] { ScriptFileMarkerLevel.Error, ScriptFileMarkerLevel.Information, ScriptFileMarkerLevel.Warning } }
                });

                diagnosticRecords = result?.Output;
            }

            _logger.Write(
                LogLevel.Verbose,
                String.Format("Found {0} violations", diagnosticRecords.Count()));

            return(diagnosticRecords);
        }
Пример #6
0
        /// <summary>
        /// Format a script given its contents.
        /// </summary>
        /// <param name="scriptDefinition">The full text of a script.</param>
        /// <param name="formatSettings">The formatter settings to use.</param>
        /// <param name="rangeList">A possible range over which to run the formatter.</param>
        /// <returns></returns>
        public async Task <string> FormatAsync(string scriptDefinition, Hashtable formatSettings, int[] rangeList)
        {
            // We cannot use Range type therefore this workaround of using -1 default value.
            // Invoke-Formatter throws a ParameterBinderValidationException if the ScriptDefinition is an empty string.
            if (string.IsNullOrEmpty(scriptDefinition))
            {
                _logger.LogDebug("Script Definition was: " + scriptDefinition == null ? "null" : "empty string");
                return(scriptDefinition);
            }

            var psCommand = new PSCommand()
                            .AddCommand("Invoke-Formatter")
                            .AddParameter("ScriptDefinition", scriptDefinition)
                            .AddParameter("Settings", formatSettings);

            if (rangeList != null)
            {
                psCommand.AddParameter("Range", rangeList);
            }

            PowerShellResult result = await InvokePowerShellAsync(psCommand).ConfigureAwait(false);

            if (result == null)
            {
                _logger.LogError("Formatter returned null result");
                return(scriptDefinition);
            }

            if (result.HasErrors)
            {
                var errorBuilder = new StringBuilder().Append(s_indentJoin);
                foreach (ErrorRecord err in result.Errors)
                {
                    errorBuilder.Append(err).Append(s_indentJoin);
                }
                _logger.LogWarning($"Errors found while formatting file: {errorBuilder}");
                return(scriptDefinition);
            }

            foreach (PSObject resultObj in result.Output)
            {
                if (resultObj?.BaseObject is string formatResult)
                {
                    return(formatResult);
                }
            }

            _logger.LogError("Couldn't get result from output. Returning original script.");
            return(scriptDefinition);
        }
Пример #7
0
        /// <summary>
        /// Returns a list of builtin-in PSScriptAnalyzer rules
        /// </summary>
        public IEnumerable <string> GetPSScriptAnalyzerRules()
        {
            PowerShellResult getRuleResult = InvokePowerShell("Get-ScriptAnalyzerRule");

            if (getRuleResult == null)
            {
                _logger.Write(LogLevel.Warning, "Get-ScriptAnalyzerRule returned null result");
                return(s_emptyGetRuleResult);
            }

            var ruleNames = new List <string>();

            foreach (var rule in getRuleResult.Output)
            {
                ruleNames.Add((string)rule.Members["RuleName"].Value);
            }

            return(ruleNames);
        }
Пример #8
0
        /// <summary>
        /// Returns a list of builtin-in PSScriptAnalyzer rules
        /// </summary>
        private IEnumerable <string> GetPSScriptAnalyzerRules()
        {
            PowerShellResult getRuleResult = InvokePowerShell(new PSCommand().AddCommand("Get-ScriptAnalyzerRule"));

            if (getRuleResult == null)
            {
                _logger.LogWarning("Get-ScriptAnalyzerRule returned null result");
                return(Enumerable.Empty <string>());
            }

            var ruleNames = new List <string>(getRuleResult.Output.Count);

            foreach (var rule in getRuleResult.Output)
            {
                ruleNames.Add((string)rule.Members["RuleName"].Value);
            }

            return(ruleNames);
        }
Пример #9
0
        private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command)
        {
            PowerShellResult result = await InvokePowerShellAsync(command).ConfigureAwait(false);

            IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult;

            _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count));

            var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count];
            int i             = 0;

            foreach (PSObject diagnostic in diagnosticResults)
            {
                scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic);
                i++;
            }

            return(scriptMarkers);
        }
Пример #10
0
        private PowerShellResult InvokePowerShell(string command, IDictionary <string, object> paramArgMap = null)
        {
            using (var powerShell = System.Management.Automation.PowerShell.Create())
            {
                powerShell.RunspacePool = _analysisRunspacePool;
                powerShell.AddCommand(command);
                if (paramArgMap != null)
                {
                    foreach (KeyValuePair <string, object> kvp in paramArgMap)
                    {
                        powerShell.AddParameter(kvp.Key, kvp.Value);
                    }
                }

                PowerShellResult result = null;
                try
                {
                    PSObject[]    output = powerShell.Invoke().ToArray();
                    ErrorRecord[] errors = powerShell.Streams.Error.ToArray();
                    result = new PowerShellResult(output, errors, powerShell.HadErrors);
                }
                catch (CommandNotFoundException ex)
                {
                    // This exception is possible if the module path loaded
                    // is wrong even though PSScriptAnalyzer is available as a module
                    _logger.Write(LogLevel.Error, ex.Message);
                }
                catch (CmdletInvocationException ex)
                {
                    // We do not want to crash EditorServices for exceptions caused by cmdlet invocation.
                    // Two main reasons that cause the exception are:
                    // * PSCmdlet.WriteOutput being called from another thread than Begin/Process
                    // * CompositionContainer.ComposeParts complaining that "...Only one batch can be composed at a time"
                    _logger.Write(LogLevel.Error, ex.Message);
                }

                return(result);
            }
        }
        public async Task When_setting_execution_policy()
        {
            var executionPolicy  = "RemoteSigned";
            var powerShellResult = new PowerShellResult
            {
                AsString = RandomString()
            };

            GetMock <IPowerShell>().Setup(x => x.ExecuteAsync(Is <string>(y => y.Contains(executionPolicy)))).ReturnsAsync(powerShellResult);

            await BecauseAsync(() => ClassUnderTest.SetExecutionPolicyAsync());

            It("reports the set policy for PowerShell", () =>
            {
                GetMock <IConsoleLogger>().Verify(x => x.Result($"PowerShell - Execution Policy: {powerShellResult.AsString}"));
            });

            It("sets and reports the set policy for Windows PowerShell", () =>
            {
                GetMock <IWindowsPowerShell>().Verify(x => x.Execute(Is <string>(y => y.Contains("RemoteSigned"))));
                GetMock <IConsoleLogger>().Verify(x => x.Result($"Windows PowerShell - Execution Policy: {executionPolicy}"));
            });
        }
Пример #12
0
        public async Task When_downloading()
        {
            var argsJson = RandomString();
            var args     = new GitHubAssetDownloaderArgs
            {
                User      = RandomString(),
                Repo      = RandomString(),
                Extension = RandomString()
            };
            var powerShellResult = new PowerShellResult
            {
                AsString = RandomString()
            };
            var assetInfo = new GitHubAssetInfo
            {
                Filename = RandomString(),
                Url      = RandomString()
            };
            var expectedDownloadedFilePath = RandomString();

            GetMock <IJsonSerializer>().Setup(x => x.Deserialize <GitHubAssetDownloaderArgs>(argsJson)).Returns(args);
            GetMock <IPowerShell>().Setup(x => x.ExecuteAsync(Moq.It.Is <string>(y =>
                                                                                 y.Contains(args.User) && y.Contains(args.Repo) && y.Contains(args.Extension))))
            .ReturnsAsync(powerShellResult);
            GetMock <IJsonSerializer>().Setup(x => x.Deserialize <GitHubAssetInfo>(powerShellResult.AsString))
            .Returns(assetInfo);
            GetMock <IResourceDownloader>().Setup(x => x.DownloadAsync(assetInfo.Url, assetInfo.Filename))
            .ReturnsAsync(expectedDownloadedFilePath);

            var downloadedFilePath = await BecauseAsync(() => ClassUnderTest.DownloadAsync(argsJson));

            It("returns the downloaded file's path", () =>
            {
                downloadedFilePath.ShouldBe(expectedDownloadedFilePath);
            });
        }
Пример #13
0
        /// <summary>
        /// Log the features available from the PSScriptAnalyzer module that has been imported
        /// for use with the AnalysisService.
        /// </summary>
        private void LogAvailablePssaFeatures()
        {
            // Save ourselves some work here
            var featureLogLevel = LogLevel.Verbose;

            if (_logger.MinimumConfiguredLogLevel > featureLogLevel)
            {
                return;
            }

            // If we already know the module that was imported, save some work
            if (_pssaModuleInfo == null)
            {
                PowerShellResult getModuleResult = InvokePowerShell(
                    "Get-Module",
                    new Dictionary <string, object> {
                    { "Name", PSSA_MODULE_NAME }
                });

                if (getModuleResult == null)
                {
                    throw new AnalysisServiceLoadException("Get-Module call to find PSScriptAnalyzer module failed");
                }

                _pssaModuleInfo = getModuleResult.Output
                                  .Select(m => m.BaseObject)
                                  .OfType <PSModuleInfo>()
                                  .FirstOrDefault();
            }

            if (_pssaModuleInfo == null)
            {
                throw new AnalysisServiceLoadException("Unable to find loaded PSScriptAnalyzer module for logging");
            }

            var sb = new StringBuilder();

            sb.AppendLine("PSScriptAnalyzer successfully imported:");

            // Log version
            sb.Append("    Version: ");
            sb.AppendLine(_pssaModuleInfo.Version.ToString());

            // Log exported cmdlets
            sb.AppendLine("    Exported Cmdlets:");
            foreach (string cmdletName in _pssaModuleInfo.ExportedCmdlets.Keys.OrderBy(name => name))
            {
                sb.Append("    ");
                sb.AppendLine(cmdletName);
            }

            // Log available rules
            sb.AppendLine("    Available Rules:");
            foreach (string ruleName in GetPSScriptAnalyzerRules())
            {
                sb.Append("        ");
                sb.AppendLine(ruleName);
            }

            _logger.Write(featureLogLevel, sb.ToString());
        }