/// <summary> /// Execute PSScriptAnalyzer cmdlets in PowerShell while preserving the PSModulePath. /// Attempts to prevent PSModulePath mutation by runspace creation within the PSScriptAnalyzer module. /// </summary> /// <param name="powershell">The PowerShell instance to execute.</param> /// <returns>The output of PowerShell execution.</returns> private Collection <PSObject> InvokePowerShellWithModulePathPreservation(System.Management.Automation.PowerShell powershell) { using (PSModulePathPreserver.Take()) { return(powershell.Invoke()); } }
/// <summary> /// Create a new runspace pool around a PSScriptAnalyzer module for asynchronous script analysis tasks. /// This looks for the latest version of PSScriptAnalyzer on the path and loads that. /// </summary> /// <returns>A runspace pool with PSScriptAnalyzer loaded for running script analysis tasks.</returns> private static RunspacePool CreatePssaRunspacePool(out PSModuleInfo pssaModuleInfo) { using (var ps = System.Management.Automation.PowerShell.Create()) { // Run `Get-Module -ListAvailable -Name "PSScriptAnalyzer"` ps.AddCommand("Get-Module") .AddParameter("ListAvailable") .AddParameter("Name", PSSA_MODULE_NAME); try { using (PSModulePathPreserver.Take()) { // Get the latest version of PSScriptAnalyzer we can find pssaModuleInfo = ps.Invoke <PSModuleInfo>()? .OrderByDescending(moduleInfo => moduleInfo.Version) .FirstOrDefault(); } } catch (Exception e) { throw new FileNotFoundException("Unable to find PSScriptAnalyzer module on the module path", e); } if (pssaModuleInfo == null) { throw new FileNotFoundException("Unable to find PSScriptAnalyzer module on the module path"); } // Now that we know where the PSScriptAnalyzer we want to use is, // create a base session state with PSScriptAnalyzer loaded #if DEBUG InitialSessionState sessionState = Environment.GetEnvironmentVariable("PSES_TEST_USE_CREATE_DEFAULT") == "1" ? InitialSessionState.CreateDefault() : InitialSessionState.CreateDefault2(); #else InitialSessionState sessionState = InitialSessionState.CreateDefault2(); #endif sessionState.ImportPSModule(new [] { pssaModuleInfo.ModuleBase }); RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool(sessionState); runspacePool.SetMaxRunspaces(1); runspacePool.ThreadOptions = PSThreadOptions.ReuseThread; // Open the runspace pool here so we can deterministically handle the PSModulePath change issue using (PSModulePathPreserver.Take()) { runspacePool.Open(); } return(runspacePool); } }
/// <summary> /// Create a new runspace pool around a PSScriptAnalyzer module for asynchronous script analysis tasks. /// This looks for the latest version of PSScriptAnalyzer on the path and loads that. /// </summary> /// <returns>A runspace pool with PSScriptAnalyzer loaded for running script analysis tasks.</returns> private static RunspacePool CreatePssaRunspacePool(out PSModuleInfo pssaModuleInfo) { using (var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.NewRunspace)) { // Run `Get-Module -ListAvailable -Name "PSScriptAnalyzer"` ps.AddCommand("Get-Module") .AddParameter("ListAvailable") .AddParameter("Name", PSSA_MODULE_NAME); try { using (PSModulePathPreserver.Take()) { // Get the latest version of PSScriptAnalyzer we can find pssaModuleInfo = ps.Invoke <PSModuleInfo>()? .OrderByDescending(moduleInfo => moduleInfo.Version) .FirstOrDefault(); } } catch (Exception e) { throw new FileNotFoundException("Unable to find PSScriptAnalyzer module on the module path", e); } if (pssaModuleInfo == null) { throw new FileNotFoundException("Unable to find PSScriptAnalyzer module on the module path"); } // Now that we know where the PSScriptAnalyzer we want to use is, create a base // session state with PSScriptAnalyzer loaded // // We intentionally use `CreateDefault2()` as it loads `Microsoft.PowerShell.Core` // only, which is a more minimal and therefore safer state. InitialSessionState sessionState = InitialSessionState.CreateDefault2(); sessionState.ImportPSModule(new [] { pssaModuleInfo.ModuleBase }); RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool(sessionState); runspacePool.SetMaxRunspaces(1); runspacePool.ThreadOptions = PSThreadOptions.ReuseThread; // Open the runspace pool here so we can deterministically handle the PSModulePath change issue using (PSModulePathPreserver.Take()) { runspacePool.Open(); } return(runspacePool); } }