/// <summary> /// Event handler that's called when the connection window is closing. Clean up all of our threads, exit the PowerShell instance, and dispose of /// <see cref="_currentPowerShell"/>. /// </summary> /// <param name="sender">Object from which this event originated.</param> /// <param name="e">Arguments associated with this event.</param> protected void ParentForm_Closing(object sender, CancelEventArgs e) { try { if (_inputThread != null) { _inputThread.Abort(); } } catch { } try { ExecuteQuiet("exit"); } finally { if (_currentPowerShell != null) { _currentPowerShell.Dispose(); _currentPowerShell = null; } _powerShellHost.Exit(); } }
private void HandleJobStateChanged(object sender, JobStateEventArgs e) { base.SetJobState(e.JobStateInfo.State); if (this.IsFinishedState(e.JobStateInfo.State)) { base.PSEndTime = new DateTime?(DateTime.Now); System.Management.Automation.PowerShell powerShell = null; Runspace runspace = null; lock (base.SyncRoot) { if (this._job != null && this.IsFinishedState(this._job.JobStateInfo.State)) { this._powerShell = null; this._runspace = null; } } if (powerShell != null) { powerShell.Dispose(); } if (runspace != null) { runspace.Dispose(); } if (this._asyncJobStop) { this._asyncJobStop = false; this.OnStopJobCompleted(new AsyncCompletedEventArgs(null, false, null)); } this.RemoveSetShouldExitFromHost(); } }
/// <summary> /// Override EndProcessing. /// </summary> protected override void EndProcessing() { if (_powerShell != null) { _powerShell.Dispose(); } }
/// <summary> /// A helper class that builds and executes a pipeline that writes to the default output path, depending on the value of <paramref name="quiet"/>. Any /// exceptions that are thrown are just passed to the caller. /// </summary> /// <param name="command">The script to run.</param> /// <param name="input">Any input arguments to pass to the script. If null then nothing is passed in.</param> /// <param name="quiet">Whether or not the results of the call should be written to the console.</param> /// <returns>The results of the call to _currentPowerShell.<see cref="PowerShell.Invoke()"/>.</returns> protected Collection <PSObject> ExecuteHelper(string command, object input, bool quiet = false) { // Ignore empty command lines. if (String.IsNullOrEmpty(command)) { return(null); } lock (_executionLock) { // Create the pipeline object and make it available to the Ctrl-C handle through the _currentPowerShell instance variable. lock (_instanceLock) { _currentPowerShell = Shell.Create(); } // Create a pipeline for this execution, and then place the result in the _currentPowerShell variable so it is available to be stopped. try { _currentPowerShell.Runspace = Runspace; _currentPowerShell.AddScript(command); if (!quiet) { // Add the default outputter to the end of the pipe and then call the MergeMyResults method to merge the output and error streams from // the pipeline. This will result in the output being written using the PSHost and PSHostUserInterface classes instead of returning // objects to the host application. _currentPowerShell.AddCommand("out-default"); _currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output); } // If there is any input pass it in, otherwise just invoke the the pipeline. if (input != null) { return(_currentPowerShell.Invoke( new object[] { input })); } else { return(_currentPowerShell.Invoke()); } } finally { // Dispose the PowerShell object and set _currentPowerShell to null. It is locked because _currentPowerShell may be accessed by the Ctrl-C // handler. lock (_instanceLock) { _currentPowerShell.Dispose(); _currentPowerShell = null; } } } }
/* NOTE: You can see what the ExecutionPolicy is by doing "Get-ExecutionPolicy" (without double quotes). * Set the ExecutionPolicy with "Set-ExecutionPolicy -ExecutionPolicy <Restricted/AllSigned/RemoteSigned/Unrestricted>". * Add "-Scope CurrentUser" along with Set-ExecutionPolicy to set the ExecutionPolicy for ONLY the CURRENT USER. */ public string runPowerShell(string options, Dictionary <string, string> optionDict) { // Get script directory and clear session variable string scriptDirectory = HttpContext.Current.Session["scriptDirectory"].ToString(); HttpContext.Current.Session["scriptDirectory"] = ""; // Clean the Result TextBox string output = "Running script... \r\n"; // Powershell engine Runspace runspace = getRunspace(); using (runspace) { runspace.Open(); using (System.Management.Automation.PowerShell shell = System.Management.Automation.PowerShell.Create()) { shell.Runspace = runspace; // Get script path string scriptPath = getScriptPath(scriptDirectory); output += "Script path: " + scriptPath + "\r\n"; output += "Input: " + options + "\r\n"; if (File.Exists(scriptPath)) { // Add script shell.AddCommand(scriptPath); if (!string.IsNullOrEmpty(options)) { // Add parameters and arguments output += "Parsed parameters and arguments: " + string.Join("; ", optionDict.Select(dict => dict.Key + "=" + dict.Value).ToArray()) + "\r\n"; foreach (string key in optionDict.Keys) { if (key.StartsWith("-")) { shell.AddParameter(key, optionDict[key]); } else { shell.AddArgument(key); } } } shell.AddCommand("Out-String"); output += invokeScript(shell); } else { output += "File not found. Please check the file path. Otherwise, please go back to the home page and then try again."; } shell.Dispose(); } runspace.Close(); } return(output); }
private void ReleaseIndependentShell() { lock (executionLock) { independentShell?.Dispose(); independentShell = null; } }
public void CleanupPowerShell() { _ps.Dispose(); if (File.Exists(_tempFilePath)) { File.Delete(_tempFilePath); } }
public void Dispose() { _ps.Dispose(); if (File.Exists(_tempFilePath)) { File.Delete(_tempFilePath); } }
/// <summary> /// To display an exception using the display formatter, run a second pipeline passing in the error record. The runtime will bind this to the $input /// variable, which is why $input is being piped to the Out-String cmdlet. The WriteErrorLine method is called to make sure the error gets displayed in /// the correct error color. /// </summary> /// <param name="e">The exception to display.</param> private void ReportException(Exception e) { if (e != null) { IContainsErrorRecord errorRecord = e as IContainsErrorRecord; object error = errorRecord != null ? errorRecord.ErrorRecord : new ErrorRecord(e, "Host.ReportException", ErrorCategory.NotSpecified, null); lock (_instanceLock) { _currentPowerShell = Shell.Create(); } _currentPowerShell.Runspace = Runspace; try { _currentPowerShell.AddScript("$input").AddCommand("out-string"); // Do not merge errors, this function will swallow errors. Collection <PSObject> result; PSDataCollection <object> inputCollection = new PSDataCollection <object> { error }; inputCollection.Complete(); lock (_executionLock) { result = _currentPowerShell.Invoke(inputCollection); } if (result.Count > 0) { string output = result[0].BaseObject as string; // Remove \r\n, which is added by the Out-String cmdlet. if (!string.IsNullOrEmpty(output)) { _powerShellHost.UI.WriteErrorLine(output.Substring(0, output.Length - 2)); } } } finally { // Dispose of the pipeline and set it to null, locking it because _currentPowerShell may be accessed by the Ctrl-C handler. lock (_instanceLock) { _currentPowerShell.Dispose(); _currentPowerShell = null; } } } }
private void ReleaseShell() { lock (executionLock) { cancellationTask?.Dispose(); cancellationTask = null; shell?.Dispose(); shell = null; } }
public string[] GetTabCompletion(string commandLine) { string[] strArrays; if (commandLine != null) { lock (this.clientRequestLock) { if (this.State == PowwaSession.SessionState.Available) { this.State = PowwaSession.SessionState.ExecutingCommand; System.Management.Automation.PowerShell powerShell = null; try { try { powerShell = System.Management.Automation.PowerShell.Create(); powerShell.Runspace = this.Runspace; CommandCompletion commandCompletion = CommandCompletion.CompleteInput(commandLine, commandLine.Length, null, powerShell); string str = commandLine.Substring(0, commandCompletion.ReplacementIndex); string[] strArrays1 = new string[commandCompletion.CompletionMatches.Count]; for (int i = 0; i < commandCompletion.CompletionMatches.Count; i++) { strArrays1[i] = string.Concat(str, commandCompletion.CompletionMatches[i].CompletionText); } strArrays = strArrays1; } catch { strArrays = new string[0]; } } finally { if (powerShell != null) { powerShell.Dispose(); } this.State = PowwaSession.SessionState.Available; } } else { PowwaEvents.PowwaEVENT_DEBUG_LOG1("GetTabCompletion(): Invalid Session State", "SessionState", this.State.ToString()); throw new InvalidOperationException("The session is not available"); } } return(strArrays); } else { throw new ArgumentNullException("commandLine"); } }
private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _pwsh.Dispose(); } _pwsh = null; disposedValue = true; } }
private System.Management.Automation.PowerShell CreatePowerShellObject(PSHost host, string modulePath) { System.Management.Automation.PowerShell ps = null; try { //loading SHiPS module _sessionstate.ImportPSModule(new[] { SHiPSModule }); //loading dsl module if (!string.IsNullOrWhiteSpace(modulePath)) { _sessionstate.ImportPSModule(new[] { modulePath }); } _runspace = RunspaceFactory.CreateRunspace(host, _sessionstate); if (_runspace == null) { return(null); } else { _runspace.Open(); var error = _runspace.SessionStateProxy.PSVariable.GetValue("Error") as ArrayList; if (error != null && error.Count > 0) { _provider.ThrowTerminatingError(error[0] as ErrorRecord); return(null); } ps = System.Management.Automation.PowerShell.Create(); //Cannot use ps.Runspace = Runspace.DefaultRunspace, it will give you an error //Pipelines cannot be run concurrently ps.Runspace = _runspace; return(ps); } } catch (Exception) { // didn't create or import correctly. if (ps != null) { ps.Dispose(); } if (_runspace != null) { _runspace.Close(); } throw; } }
/// <summary> /// Dispose /// </summary> /// <param name="disposing"></param> protected override void Dispose(bool disposing) { if (disposing) { if (_ps.InvocationStateInfo.State == PSInvocationState.Running) { _ps.Stop(); } _ps.Dispose(); _input.Complete(); _output.Complete(); } base.Dispose(disposing); }
/// <summary> /// Disposes the pipeline. /// </summary> /// <param name="disposing">True, when called on Dispose().</param> protected override void Dispose(bool disposing) { try { if (_disposed) { return; } lock (_syncRoot) { if (_disposed) { return; } _disposed = true; } if (disposing) { // wait for the pipeline to stop..this will block // if the pipeline is already stopping. Stop(); // _pipelineFinishedEvent.Close(); if (_powershell != null) { _powershell.Dispose(); _powershell = null; } _inputCollection.Dispose(); _inputStream.Dispose(); _outputCollection.Dispose(); _outputStream.Dispose(); _errorCollection.Dispose(); _errorStream.Dispose(); MethodExecutorStream.Dispose(); PipelineFinishedEvent.Dispose(); } } finally { base.Dispose(disposing); } }
private void HandleJobStateChanged(object sender, JobStateEventArgs e) { SetJobState(e.JobStateInfo.State); if (IsFinishedState(e.JobStateInfo.State)) { PSEndTime = DateTime.Now; // Dispose the PowerShell and Runspace objects. System.Management.Automation.PowerShell disposePowerShell = null; Runspace disposeRunspace = null; lock (SyncRoot) { if (_job != null && IsFinishedState(_job.JobStateInfo.State)) { disposePowerShell = _powerShell; _powerShell = null; disposeRunspace = _runspace; _runspace = null; } } if (disposePowerShell != null) { disposePowerShell.Dispose(); } if (disposeRunspace != null) { disposeRunspace.Dispose(); } // Raise async job stopped event, if needed. if (_asyncJobStop) { _asyncJobStop = false; OnStopJobCompleted(new AsyncCompletedEventArgs(null, false, null)); } // Remove AllowSetShouldExit from host. RemoveSetShouldExitFromHost(); } }
private void ReleaseUnmanagedResources() { try { PowerShell?.Dispose(); } catch (Exception e) { Trace.WriteLine($"Encountered error while disposing powershell session: {e}"); } PowerShell = null; try { Runspace?.Dispose(); } catch (Exception e) { Trace.WriteLine($"Encountered error while disposing powershell runspace: {e}"); } Runspace = null; }
private static void RunScript(string script, string[] args) { lock (psLocker) { powershellHost = new Host(); powershellEngine = System.Management.Automation.PowerShell.Create(); } try { InitialSessionState initalState = InitialSessionState.CreateDefault(); List <ParameterItem> validCmds = new List <ParameterItem>(); //AddValidCommands Commandline cmdLine = new Commandline(args); if (cmdLine["help"] == "true" || cmdLine["?"] == "true") { AssemblyData assInfo = new AssemblyData(System.Reflection.Assembly.GetExecutingAssembly()); StringBuilder outputBuilder = new StringBuilder(); outputBuilder.AppendLine(); outputBuilder.AppendLine(string.Format("{0} v{1} by {2}", assInfo.Product, assInfo.Version, assInfo.Company)); outputBuilder.AppendLine(assInfo.Copyright); outputBuilder.AppendLine(); outputBuilder.AppendLine(" [-Help]"); outputBuilder.AppendLine(" Show help"); foreach (ParameterItem cmdName in validCmds) { if (cmdName.Mandatory) { outputBuilder.AppendLine(string.Format(" -{0} <{1}>", cmdName.Name, cmdName.Type)); } else { outputBuilder.AppendLine(string.Format(" [-{0} <{1}>]", cmdName.Name, cmdName.Type)); } if (!string.IsNullOrWhiteSpace(cmdName.HelpText)) { outputBuilder.AppendLine(string.Format(" {0}", cmdName.HelpText)); } } if (hideCon) { MessageBox.Show(outputBuilder.ToString(), "Help", MessageBoxButtons.OK, MessageBoxIcon.Question); } else { ConsoleHandler.WriteLine(outputBuilder.ToString()); } return; } Dictionary <string, object> cmdLineArgs = new Dictionary <string, object>(); foreach (string arg in cmdLine.GetKeys()) { ParameterItem paramItem = validCmds.FirstOrDefault(x => String.Equals(x.Name, arg, StringComparison.CurrentCultureIgnoreCase)); if (paramItem != null) { try { object realItem; switch (paramItem.Type) { case "sbyte": realItem = sbyte.Parse(cmdLine[arg]); break; case "byte": realItem = byte.Parse(cmdLine[arg]); break; case "short": realItem = short.Parse(cmdLine[arg]); break; case "ushort": realItem = ushort.Parse(cmdLine[arg]); break; case "int": realItem = int.Parse(cmdLine[arg]); break; case "uint": realItem = uint.Parse(cmdLine[arg]); break; case "ulong": realItem = ulong.Parse(cmdLine[arg]); break; case "long": realItem = long.Parse(cmdLine[arg]); break; case "float": realItem = float.Parse(cmdLine[arg]); break; case "double": realItem = double.Parse(cmdLine[arg]); break; case "decimal": realItem = decimal.Parse(cmdLine[arg]); break; case "char": realItem = char.Parse(cmdLine[arg]); break; case "switch": case "bool": realItem = bool.Parse(cmdLine[arg]); break; case "boolean": realItem = Boolean.Parse(cmdLine[arg]); break; default: realItem = cmdLine[arg]; break; } cmdLineArgs.Add(arg, realItem); } catch (Exception) { string errorString = string.Format("Parameter '-{0}' was not in correct format: '{1}'", arg, paramItem.Type); if (hideCon) { MessageBox.Show(errorString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { ConsoleHandler.WriteLine(errorString); } return; } } else { StringBuilder outputBuilder = new StringBuilder(); outputBuilder.AppendLine(string.Format("Parameter '-{0}' is not valid. Use '-help' to show valid parameters.", arg)); if (hideCon) { MessageBox.Show(outputBuilder.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { ConsoleHandler.WriteLine(outputBuilder.ToString()); } return; } } foreach (ParameterItem paramItem in validCmds.Where(x => x.Mandatory == true)) { if (!cmdLineArgs.ContainsKey(paramItem.Name.ToLower())) { StringBuilder outputBuilder = new StringBuilder(); outputBuilder.AppendLine(string.Format("Parameter '-{0}' of type '{1}' is mandatory.", paramItem.Name, paramItem.Type)); if (hideCon) { MessageBox.Show(outputBuilder.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { ConsoleHandler.WriteLine(outputBuilder.ToString()); } return; } } List <string> modulesToLoad = Common.ProcessManifest(initalState); powershellEngine.Runspace = RunspaceFactory.CreateRunspace(powershellHost, initalState); powershellEngine.Runspace.ApartmentState = System.Threading.ApartmentState.MTA; powershellEngine.Runspace.Open(); RunspaceInvoke runSpaceInvoker = new RunspaceInvoke(powershellEngine.Runspace); try { runSpaceInvoker.Invoke("Set-ExecutionPolicy Unrestricted -Scope Process"); } catch { } foreach (string module in modulesToLoad) { try { runSpaceInvoker.Invoke(string.Format("Import-Module {0} -Scope Global", module)); } catch (Exception e) { ConsoleHandler.WriteLine(string.Format("Could import module {0}: {0}", e.Message, module)); } } Pipeline pipeline = powershellEngine.Runspace.CreatePipeline(); Command command = new Command(script, true, true); foreach (KeyValuePair <string, object> cmdLineData in cmdLineArgs) { command.Parameters.Add(cmdLineData.Key, cmdLineData.Value); } pipeline.Commands.Add(command); Collection <PSObject> resultObjects = pipeline.Invoke(); foreach (PSObject resultObject in resultObjects) { ConsoleHandler.WriteLine(resultObject.ToString()); } } catch (Exception e) { ConsoleHandler.WriteLine(string.Format("Internal error: {0}", e.Message)); } finally { lock (psLocker) { powershellEngine.Dispose(); powershellEngine = null; } } }
/// <summary> /// A helper class that builds and executes a pipeline that writes to the /// default output path. Any exceptions that are thrown are just passed to /// the caller. Since all output goes to the default outter, this method() /// won't return anything. /// </summary> /// <param name="cmd">The script to run</param> /// <param name="input">Any input arguments to pass to the script. If null /// then nothing is passed in.</param> void executeHelper(string cmd, object input) { // Just ignore empty command lines... if (String.IsNullOrEmpty(cmd)) return; // Create the pipeline object and make it available // to the ctrl-C handle through the currentPowerShell instance // variable lock (instanceLock) { currentPowerShell = PowerShell.Create(); } currentPowerShell.Runspace = myRunSpace; // Create a pipeline for this execution - place the result in the currentPowerShell // instance variable so it is available to be stopped. try { currentPowerShell.AddScript(cmd); // Now add the default outputter to the end of the pipe and indicate // that it should handle both output and errors from the previous // commands. This will result in the output being written using the PSHost // and PSHostUserInterface classes instead of returning objects to the hosting // application. currentPowerShell.AddCommand("out-default"); currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output); // If there was any input specified, pass it in, otherwise just // execute the pipeline... if (input != null) { currentPowerShell.Invoke(new object[] { input }); } else { currentPowerShell.Invoke(); } } finally { // Dispose of the pipeline line and set it to null, locked because currentPowerShell // may be accessed by the ctrl-C handler... lock (instanceLock) { currentPowerShell.Dispose(); currentPowerShell = null; } } }
public virtual void TestCleanup() { powershell.Dispose(); }
public static string GetHelpUri(PSObject commandInfoPSObject) { if (null == commandInfoPSObject) { return(string.Empty); } CommandInfo cmdInfo = PSObject.Base(commandInfoPSObject) as CommandInfo; // GetHelpUri helper method is expected to be used only by System.Management.Automation.CommandInfo // objects from types.ps1xml if ((null == cmdInfo) || (string.IsNullOrEmpty(cmdInfo.Name))) { return(string.Empty); } // The type checking is needed to avoid a try..catch exception block as // the CommandInfo.CommandMetadata throws an InvalidOperationException // instead of returning null. if ((cmdInfo is CmdletInfo) || (cmdInfo is FunctionInfo) || (cmdInfo is ExternalScriptInfo) || (cmdInfo is ScriptInfo)) { if (!string.IsNullOrEmpty(cmdInfo.CommandMetadata.HelpUri)) { return(cmdInfo.CommandMetadata.HelpUri); } } AliasInfo aliasInfo = cmdInfo as AliasInfo; if ((null != aliasInfo) && (null != aliasInfo.ExternalCommandMetadata) && (!string.IsNullOrEmpty(aliasInfo.ExternalCommandMetadata.HelpUri))) { return(aliasInfo.ExternalCommandMetadata.HelpUri); } // if everything else fails..depend on Get-Help infrastructure to get us the Uri. string cmdName = cmdInfo.Name; if (!string.IsNullOrEmpty(cmdInfo.ModuleName)) { cmdName = string.Format(CultureInfo.InvariantCulture, "{0}\\{1}", cmdInfo.ModuleName, cmdInfo.Name); } if (DoesCurrentRunspaceIncludeCoreHelpCmdlet()) { // Win8: 651300 if core get-help is present in the runspace (and it is the only get-help command), use // help system directly and avoid perf penalty. var currentContext = System.Management.Automation.Runspaces.LocalPipeline.GetExecutionContextFromTLS(); if ((null != currentContext) && (null != currentContext.HelpSystem)) { HelpRequest helpRequest = new HelpRequest(cmdName, cmdInfo.HelpCategory); helpRequest.ProviderContext = new ProviderContext( string.Empty, currentContext, currentContext.SessionState.Path); helpRequest.CommandOrigin = CommandOrigin.Runspace; foreach ( Uri result in currentContext.HelpSystem.ExactMatchHelp(helpRequest).Select( helpInfo => helpInfo.GetUriForOnlineHelp()).Where(result => null != result)) { return(result.OriginalString); } } } else { // win8: 546025. Using Get-Help as command, instead of calling HelpSystem.ExactMatchHelp // for the following reasons: // 1. Exchange creates proxies for Get-Command and Get-Help in their scenario // 2. This method is primarily used to get uri faster while serializing the CommandInfo objects (from Get-Command) // 3. Exchange uses Get-Help proxy to not call Get-Help cmdlet at-all while serializing CommandInfo objects // 4. Using HelpSystem directly will not allow Get-Help proxy to do its job. System.Management.Automation.PowerShell getHelpPS = System.Management.Automation.PowerShell.Create( RunspaceMode.CurrentRunspace).AddCommand("get-help"). AddParameter("Name", cmdName).AddParameter("Category", cmdInfo.HelpCategory.ToString()); try { Collection <PSObject> helpInfos = getHelpPS.Invoke(); if (null != helpInfos) { for (int index = 0; index < helpInfos.Count; index++) { HelpInfo helpInfo; if (LanguagePrimitives.TryConvertTo <HelpInfo>(helpInfos[index], out helpInfo)) { Uri result = helpInfo.GetUriForOnlineHelp(); if (null != result) { return(result.OriginalString); } } else { Uri result = BaseCommandHelpInfo.GetUriFromCommandPSObject(helpInfos[index]); return((result != null) ? result.OriginalString : string.Empty); } } } } finally { getHelpPS.Dispose(); } } return(string.Empty); }
public void IterationCleanup() { pwsh.Dispose(); }
internal static PSKeyInfo ReadKey() { // Reading a key is handled on a different thread. During process shutdown, // PowerShell will wait in it's ConsoleCtrlHandler until the pipeline has completed. // If we're running, we're most likely blocked waiting for user input. // This is a problem for two reasons. First, exiting takes a long time (5 seconds // on Win8) because PowerShell is waiting forever, but the OS will forcibly terminate // the console. Also - if there are any event handlers for the engine event // PowerShell.Exiting, those handlers won't get a chance to run. // // By waiting for a key on a different thread, our pipeline execution thread // (the thread ReadLine is called from) avoid being blocked in code that can't // be unblocked and instead blocks on events we control. // First, set an event so the thread to read a key actually attempts to read a key. _singleton._readKeyWaitHandle.Set(); int handleId; System.Management.Automation.PowerShell ps = null; try { while (true) { // Next, wait for one of three things: // - a key is pressed // - the console is exiting // - 300ms timeout - to process events if we're idle // - ReadLine cancellation is requested externally handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300); if (handleId != WaitHandle.WaitTimeout) { break; } if (_handleIdleOverride is not null) { _handleIdleOverride(_singleton._cancelReadCancellationToken); continue; } // If we timed out, check for event subscribers (which is just // a hint that there might be an event waiting to be processed.) var eventSubscribers = _singleton._engineIntrinsics?.Events.Subscribers; if (eventSubscribers?.Count > 0) { bool runPipelineForEventProcessing = false; foreach (var sub in eventSubscribers) { if (sub.SourceIdentifier.Equals(PSEngineEvent.OnIdle, StringComparison.OrdinalIgnoreCase)) { // If the buffer is not empty, let's not consider we are idle because the user is in the middle of typing something. if (_singleton._buffer.Length > 0) { continue; } // There is an OnIdle event subscriber and we are idle because we timed out and the buffer is empty. // Normally PowerShell generates this event, but PowerShell assumes the engine is not idle because // it called PSConsoleHostReadLine which isn't returning. So we generate the event instead. runPipelineForEventProcessing = true; _singleton._engineIntrinsics.Events.GenerateEvent(PSEngineEvent.OnIdle, null, null, null); // Break out so we don't genreate more than one 'OnIdle' event for a timeout. break; } runPipelineForEventProcessing = true; } // If there are any event subscribers, run a tiny useless PowerShell pipeline // so that the events can be processed. if (runPipelineForEventProcessing) { if (ps == null) { ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); ps.AddScript("0", useLocalScope: true); } // To detect output during possible event processing, see if the cursor moved // and rerender if so. var console = _singleton._console; var y = console.CursorTop; ps.Invoke(); if (y != console.CursorTop) { _singleton._initialY = console.CursorTop; _singleton.Render(); } } } } } finally { ps?.Dispose(); } if (handleId == ConsoleExiting) { // The console is exiting - throw an exception to unwind the stack to the point // where we can return from ReadLine. if (_singleton.Options.HistorySaveStyle == HistorySaveStyle.SaveAtExit) { _singleton.SaveHistoryAtExit(); } _singleton._historyFileMutex.Dispose(); throw new OperationCanceledException(); } if (handleId == CancellationRequested) { // ReadLine was cancelled. Save the current line to be restored next time ReadLine // is called, clear the buffer and throw an exception so we can return an empty string. _singleton.SaveCurrentLine(); _singleton._getNextHistoryIndex = _singleton._history.Count; _singleton._current = 0; _singleton._buffer.Clear(); _singleton.Render(); throw new OperationCanceledException(); } var key = _singleton._queuedKeys.Dequeue(); return(key); }
object IPSConsoleReadLineMockableMethods.GetDynamicHelpContent(string commandName, string parameterName, bool isFullHelp) { if (string.IsNullOrEmpty(commandName)) { return(null); } System.Management.Automation.PowerShell ps = null; try { if (!_mockableMethods.RunspaceIsRemote(_runspace)) { ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); } else { ps = System.Management.Automation.PowerShell.Create(); ps.Runspace = _runspace; } if (isFullHelp) { return(ps .AddCommand($"Microsoft.PowerShell.Core\\Get-Help") .AddParameter("Name", commandName) .AddParameter("Full", value: true) .AddCommand($"Microsoft.PowerShell.Utility\\Out-String") .Invoke <string>() .FirstOrDefault()); } if (string.IsNullOrEmpty(parameterName)) { return(null); } return(ps .AddCommand("Microsoft.PowerShell.Core\\Get-Help") .AddParameter("Name", commandName) .AddParameter("Parameter", parameterName) .Invoke <PSObject>() .FirstOrDefault()); } catch (Exception) { return(null); } finally { ps?.Dispose(); // GetDynamicHelpContent could scroll the screen, e.g. via Write-Progress. For example, // Get-Help for unknown command under the CloudShell Azure drive will show the progress bar while searching for command. // We need to update the _initialY in case the current cursor postion has changed. if (_singleton._initialY > _console.CursorTop) { _singleton._initialY = _console.CursorTop; } } }
private static ConsoleKeyInfo ReadKey() { // Reading a key is handled on a different thread. During process shutdown, // PowerShell will wait in it's ConsoleCtrlHandler until the pipeline has completed. // If we're running, we're most likely blocked waiting for user input. // This is a problem for two reasons. First, exiting takes a long time (5 seconds // on Win8) because PowerShell is waiting forever, but the OS will forcibly terminate // the console. Also - if there are any event handlers for the engine event // PowerShell.Exiting, those handlers won't get a chance to run. // // By waiting for a key on a different thread, our pipeline execution thread // (the thread Readline is called from) avoid being blocked in code that can't // be unblocked and instead blocks on events we control. // First, set an event so the thread to read a key actually attempts to read a key. _singleton._readKeyWaitHandle.Set(); int handleId; System.Management.Automation.PowerShell ps = null; try { while (true) { // Next, wait for one of three things: // - a key is pressed // - the console is exiting // - 300ms - to process events if we're idle handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300); if (handleId != WaitHandle.WaitTimeout) { break; } if (_singleton._engineIntrinsics == null) { continue; } // If we timed out, check for event subscribers (which is just // a hint that there might be an event waiting to be processed.) var eventSubscribers = _singleton._engineIntrinsics.Events.Subscribers; if (eventSubscribers.Count > 0) { bool runPipelineForEventProcessing = false; foreach (var sub in eventSubscribers) { if (sub.SourceIdentifier.Equals("PowerShell.OnIdle", StringComparison.OrdinalIgnoreCase)) { // There is an OnIdle event. We're idle because we timed out. Normally // PowerShell generates this event, but PowerShell assumes the engine is not // idle because it called PSConsoleHostReadline which isn't returning. // So we generate the event intstead. _singleton._engineIntrinsics.Events.GenerateEvent("PowerShell.OnIdle", null, null, null); runPipelineForEventProcessing = true; break; } // If there are any event subscribers that have an action (which might // write to the console) and have a source object (i.e. aren't engine // events), run a tiny useless bit of PowerShell so that the events // can be processed. if (sub.Action != null && sub.SourceObject != null) { runPipelineForEventProcessing = true; break; } } if (runPipelineForEventProcessing) { if (ps == null) { ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); ps.AddScript("0"); } // To detect output during possible event processing, see if the cursor moved // and rerender if so. var console = _singleton._console; var y = console.CursorTop; ps.Invoke(); if (y != console.CursorTop) { _singleton._initialY = console.CursorTop; _singleton.Render(); } } } } } finally { if (ps != null) { ps.Dispose(); } } if (handleId == 1) { // The console is exiting - throw an exception to unwind the stack to the point // where we can return from ReadLine. if (_singleton.Options.HistorySaveStyle == HistorySaveStyle.SaveAtExit) { _singleton.SaveHistoryAtExit(); } _singleton._historyFileMutex.Dispose(); throw new OperationCanceledException(); } var key = _singleton._queuedKeys.Dequeue(); return(key); }
public void GlobalCleanup() { pwsh.Dispose(); }