2020-03-24 11:08:37 -07:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
2018-02-13 09:23:53 -08:00
|
|
|
// Licensed under the MIT License.
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2017-06-08 00:52:33 +02:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Management.Automation.Runspaces;
|
|
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
namespace System.Management.Automation
|
|
|
|
|
{
|
2017-06-08 00:52:33 +02:00
|
|
|
internal class PowerShellExecutionHelper
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
2017-06-08 00:52:33 +02:00
|
|
|
// Creates a new PowerShellExecutionHelper with the PowerShell instance that will be used to execute the tab expansion commands
|
2016-03-30 14:20:52 -07:00
|
|
|
// Used by the ISE
|
2017-06-08 00:52:33 +02:00
|
|
|
internal PowerShellExecutionHelper(PowerShell powershell)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
if (powershell == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2020-05-19 19:57:52 +01:00
|
|
|
throw PSTraceSource.NewArgumentNullException(nameof(powershell));
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
2017-06-08 00:52:33 +02:00
|
|
|
CurrentPowerShell = powershell;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Constructors
|
|
|
|
|
|
|
|
|
|
#region Fields and Properties
|
|
|
|
|
|
|
|
|
|
// Gets and sets a flag set to false at the beginning of each tab completion and
|
|
|
|
|
// set to true if a pipeline is stopped to indicate all commands should return empty matches
|
|
|
|
|
internal bool CancelTabCompletion { get; set; }
|
|
|
|
|
|
|
|
|
|
// Gets and sets the PowerShell instance used to run command completion commands
|
|
|
|
|
// Used by the ISE
|
|
|
|
|
internal PowerShell CurrentPowerShell { get; set; }
|
|
|
|
|
|
|
|
|
|
// Returns true if this instance is currently executing a command
|
2017-06-08 00:52:33 +02:00
|
|
|
internal bool IsRunning => CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Running;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// Returns true if the command executed by this instance was stopped
|
2017-06-08 00:52:33 +02:00
|
|
|
internal bool IsStopped => CurrentPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
#endregion Fields and Properties
|
|
|
|
|
|
|
|
|
|
#region Command Execution
|
|
|
|
|
|
|
|
|
|
internal Collection<PSObject> ExecuteCommand(string command)
|
|
|
|
|
{
|
|
|
|
|
Exception unused;
|
2017-06-08 00:52:33 +02:00
|
|
|
return ExecuteCommand(command, true, out unused, null);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal bool ExecuteCommandAndGetResultAsBool()
|
|
|
|
|
{
|
|
|
|
|
Exception exceptionThrown;
|
|
|
|
|
Collection<PSObject> streamResults = ExecuteCurrentPowerShell(out exceptionThrown);
|
|
|
|
|
|
2020-07-30 16:06:38 -07:00
|
|
|
if (exceptionThrown != null || streamResults == null || streamResults.Count == 0)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-16 13:31:14 -08:00
|
|
|
// we got back one or more objects.
|
2016-03-30 14:20:52 -07:00
|
|
|
return (streamResults.Count > 1) || (LanguagePrimitives.IsTrue(streamResults[0]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal string ExecuteCommandAndGetResultAsString()
|
|
|
|
|
{
|
|
|
|
|
Exception exceptionThrown;
|
|
|
|
|
Collection<PSObject> streamResults = ExecuteCurrentPowerShell(out exceptionThrown);
|
|
|
|
|
|
2020-07-30 16:06:38 -07:00
|
|
|
if (exceptionThrown != null || streamResults == null || streamResults.Count == 0)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we got back one or more objects. Pick off the first result.
|
2020-07-30 16:06:38 -07:00
|
|
|
if (streamResults[0] == null)
|
2018-12-31 20:44:16 +05:00
|
|
|
return string.Empty;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// And convert the base object into a string. We can't use the proxied
|
|
|
|
|
// ToString() on the PSObject because there is no default runspace
|
|
|
|
|
// available.
|
|
|
|
|
return SafeToString(streamResults[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal Collection<PSObject> ExecuteCommand(string command, bool isScript, out Exception exceptionThrown, Hashtable args)
|
|
|
|
|
{
|
|
|
|
|
Diagnostics.Assert(command != null, "caller to verify command is not null");
|
|
|
|
|
|
|
|
|
|
exceptionThrown = null;
|
|
|
|
|
|
|
|
|
|
// This flag indicates a previous call to this method had its pipeline cancelled
|
2017-06-08 00:52:33 +02:00
|
|
|
if (CancelTabCompletion)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return new Collection<PSObject>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentPowerShell.AddCommand(command);
|
|
|
|
|
|
|
|
|
|
Command cmd = new Command(command, isScript);
|
|
|
|
|
if (args != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (DictionaryEntry arg in args)
|
|
|
|
|
{
|
|
|
|
|
cmd.Parameters.Add((string)(arg.Key), arg.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Collection<PSObject> results = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// blocks until all results are retrieved.
|
2019-01-06 06:51:20 +05:00
|
|
|
// results = this.ExecuteCommand(cmd);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// If this pipeline has been stopped lets set a flag to cancel all future tab completion calls
|
|
|
|
|
// untill the next completion
|
2017-06-08 00:52:33 +02:00
|
|
|
if (IsStopped)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
results = new Collection<PSObject>();
|
2017-06-08 00:52:33 +02:00
|
|
|
CancelTabCompletion = true;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
exceptionThrown = e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal Collection<PSObject> ExecuteCurrentPowerShell(out Exception exceptionThrown, IEnumerable input = null)
|
|
|
|
|
{
|
|
|
|
|
exceptionThrown = null;
|
|
|
|
|
|
|
|
|
|
// This flag indicates a previous call to this method had its pipeline cancelled
|
2017-06-08 00:52:33 +02:00
|
|
|
if (CancelTabCompletion)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return new Collection<PSObject>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Collection<PSObject> results = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
results = CurrentPowerShell.Invoke(input);
|
|
|
|
|
|
|
|
|
|
// If this pipeline has been stopped lets set a flag to cancel all future tab completion calls
|
|
|
|
|
// untill the next completion
|
2017-06-08 00:52:33 +02:00
|
|
|
if (IsStopped)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
results = new Collection<PSObject>();
|
2017-06-08 00:52:33 +02:00
|
|
|
CancelTabCompletion = true;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
exceptionThrown = e;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
CurrentPowerShell.Commands.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Command Execution
|
|
|
|
|
|
|
|
|
|
#region Helpers
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts an object to a string safely...
|
|
|
|
|
/// </summary>
|
2018-12-28 16:39:06 +05:00
|
|
|
/// <param name="obj">The object to convert.</param>
|
2016-03-30 14:20:52 -07:00
|
|
|
/// <returns>The result of the conversion...</returns>
|
|
|
|
|
internal static string SafeToString(object obj)
|
|
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
if (obj == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
PSObject pso = obj as PSObject;
|
|
|
|
|
string result;
|
|
|
|
|
if (pso != null)
|
|
|
|
|
{
|
|
|
|
|
object baseObject = pso.BaseObject;
|
2020-11-05 05:23:50 +00:00
|
|
|
if (baseObject != null && baseObject is not PSCustomObject)
|
2016-03-30 14:20:52 -07:00
|
|
|
result = baseObject.ToString();
|
|
|
|
|
else
|
|
|
|
|
result = pso.ToString();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = obj.ToString();
|
|
|
|
|
}
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
return result;
|
|
|
|
|
}
|
2016-11-01 15:24:07 -07:00
|
|
|
catch (Exception)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// We swallow all exceptions from command completion because we don't want the shell to crash
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-01-06 04:40:24 +05:00
|
|
|
/// Converts an object to a string adn, if the string is not empty, adds it to the list.
|
2016-03-30 14:20:52 -07:00
|
|
|
/// </summary>
|
2018-12-28 16:39:06 +05:00
|
|
|
/// <param name="list">The list to update.</param>
|
2016-03-30 14:20:52 -07:00
|
|
|
/// <param name="obj">The object to convert to a string...</param>
|
|
|
|
|
internal static void SafeAddToStringList(List<string> list, object obj)
|
|
|
|
|
{
|
2020-07-30 16:06:38 -07:00
|
|
|
if (list == null)
|
2016-03-30 14:20:52 -07:00
|
|
|
return;
|
|
|
|
|
string result = SafeToString(obj);
|
|
|
|
|
if (!string.IsNullOrEmpty(result))
|
|
|
|
|
list.Add(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion Helpers
|
|
|
|
|
}
|
2017-06-08 00:52:33 +02:00
|
|
|
|
|
|
|
|
internal static class PowerShellExtensionHelpers
|
|
|
|
|
{
|
|
|
|
|
internal static PowerShell AddCommandWithPreferenceSetting(this PowerShellExecutionHelper helper,
|
|
|
|
|
string command, Type type = null)
|
|
|
|
|
{
|
|
|
|
|
return helper.CurrentPowerShell.AddCommandWithPreferenceSetting(command, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static PowerShell AddCommandWithPreferenceSetting(this PowerShell powershell, string command, Type type = null)
|
|
|
|
|
{
|
|
|
|
|
Diagnostics.Assert(powershell != null, "the passed-in powershell cannot be null");
|
2018-12-31 20:44:16 +05:00
|
|
|
Diagnostics.Assert(!string.IsNullOrWhiteSpace(command),
|
2017-06-08 00:52:33 +02:00
|
|
|
"the passed-in command name should not be null or whitespaces");
|
|
|
|
|
|
|
|
|
|
if (type != null)
|
|
|
|
|
{
|
|
|
|
|
var cmdletInfo = new CmdletInfo(command, type);
|
|
|
|
|
|
|
|
|
|
powershell.AddCommand(cmdletInfo);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
powershell.AddCommand(command);
|
|
|
|
|
}
|
2018-12-23 22:20:06 -08:00
|
|
|
|
2017-06-08 00:52:33 +02:00
|
|
|
powershell
|
|
|
|
|
.AddParameter("ErrorAction", ActionPreference.Ignore)
|
|
|
|
|
.AddParameter("WarningAction", ActionPreference.Ignore)
|
|
|
|
|
.AddParameter("InformationAction", ActionPreference.Ignore)
|
|
|
|
|
.AddParameter("Verbose", false)
|
|
|
|
|
.AddParameter("Debug", false);
|
|
|
|
|
|
|
|
|
|
return powershell;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|