Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 54 additions & 28 deletions src/System.Management.Automation/engine/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,38 +1382,40 @@ internal static bool IsComObject(object obj)
// c. Commands must be in a simple pipeline
internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
{
try
using (var ps = System.Management.Automation.PowerShell.Create())
{
var scriptBlock = ScriptBlock.Create(command);
var scriptBlockAst = scriptBlock.Ast as ScriptBlockAst;
if (scriptBlockAst == null)
{
return false;
}
ps.Runspace = runspace;

// Make sure that this is a simple pipeline
string errorId;
string errorMsg;
scriptBlockAst.GetSimplePipeline(true, out errorId, out errorMsg);
if (errorId != null)
try
{
return false;
}
var scriptBlock = ScriptBlock.Create(command);
var scriptBlockAst = scriptBlock.Ast as ScriptBlockAst;
if (scriptBlockAst == null)
{
return false;
}

// Run checker
var checker = new PipelineForBatchingChecker { ScriptBeingConverted = scriptBlockAst };
scriptBlockAst.InternalVisit(checker);
// Make sure that this is a simple pipeline
string errorId;
string errorMsg;
scriptBlockAst.GetSimplePipeline(true, out errorId, out errorMsg);
if (errorId != null)
{
WriteVerbose(ps, ParserStrings.ImplicitRemotingPipelineBatchingNotASimplePipeline);
return false;
}

// If this is just a single command, there is no point in batching it
if (checker.Commands.Count < 2)
{
return false;
}
// Run checker
var checker = new PipelineForBatchingChecker { ScriptBeingConverted = scriptBlockAst };
scriptBlockAst.InternalVisit(checker);

// We have a valid batching candidate
using (var ps = System.Management.Automation.PowerShell.Create())
{
ps.Runspace = runspace;
// If this is just a single command, there is no point in batching it
if (checker.Commands.Count < 2)
{
return false;
}

// We have a valid batching candidate

// Check commands
if (!TryGetCommandInfoList(ps, checker.Commands, out Collection<CommandInfo> cmdInfoList))
Expand All @@ -1436,6 +1438,7 @@ internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
// Commands must be from implicit remoting module
if (cmdInfo.Module == null || string.IsNullOrEmpty(cmdInfo.ModuleName))
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingNotImplicitCommand, cmdInfo.Name));
success = false;
break;
}
Expand All @@ -1446,6 +1449,7 @@ internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
var sessionIdString = privateData["ImplicitSessionId"] as string;
if (string.IsNullOrEmpty(sessionIdString))
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingNotImplicitCommand, cmdInfo.Name));
success = false;
break;
}
Expand All @@ -1457,12 +1461,14 @@ internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
}
else if (psSessionId != sessionId)
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingWrongSession, cmdInfo.Name));
success = false;
break;
}
}
else
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingNotImplicitCommand, cmdInfo.Name));
success = false;
break;
}
Expand Down Expand Up @@ -1491,13 +1497,20 @@ internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
var psSession = ps.Invoke<System.Management.Automation.Runspaces.PSSession>().FirstOrDefault();
if (psSession == null || (ps.Streams.Error.Count > 0) || (psSession.Availability != RunspaceAvailability.Available))
{
WriteVerbose(ps, ParserStrings.ImplicitRemotingPipelineBatchingNoPSSession);
return false;
}

WriteVerbose(ps, ParserStrings.ImplicitRemotingPipelineBatchingSuccess);

// Create and invoke implicit remoting command pipeline
ps.Commands.Clear();
ps.AddCommand("Invoke-Command").AddParameter("Session", psSession).AddParameter("ScriptBlock", scriptBlock).AddParameter("HideComputerName", true)
.AddCommand("Out-Default");
foreach (var cmd in ps.Commands.Commands)
{
cmd.MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
}

try
{
Expand All @@ -1514,12 +1527,25 @@ internal static bool TryRunAsImplicitBatch(string command, Runspace runspace)
return true;
}
}
catch (ImplicitRemotingBatchingNotSupportedException ex)
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, "{0} : {1}", ex.Message, ex.ErrorId));
}
catch (Exception ex)
{
WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingException, ex.Message));
}
}
catch (Exception) { }


return false;
}

private static void WriteVerbose(PowerShell ps, string msg)
{
ps.Commands.Clear();
ps.AddCommand("Write-Verbose").AddParameter("Message", msg).Invoke();
}

private const string WhereObjectCommandAlias = "?";
private static bool TryGetCommandInfoList(PowerShell ps, HashSet<string> commandNames, out Collection<CommandInfo> cmdInfoList)
{
Expand Down
18 changes: 18 additions & 0 deletions src/System.Management.Automation/resources/ParserStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1470,4 +1470,22 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
<data name="ImplicitRemotingPipelineBatchingNotSupported" xml:space="preserve">
<value>Command pipeline not supported for implicit remoting batching.</value>
</data>
<data name="ImplicitRemotingPipelineBatchingNotASimplePipeline" xml:space="preserve">
<value>Command is not a simple pipeline and cannot be batched.</value>
</data>
<data name="ImplicitRemotingPipelineBatchingNotImplicitCommand" xml:space="preserve">
<value>The pipeline command '{0}' is not an implicit remoting command or an approved batching command.</value>
</data>
<data name="ImplicitRemotingPipelineBatchingWrongSession" xml:space="preserve">
<value>The pipeline command '{0}' is for a different remote session and cannot be batched.</value>
</data>
<data name="ImplicitRemotingPipelineBatchingNoPSSession" xml:space="preserve">
<value>The implicit remoting PSSession for batching could not be retrieved.</value>
</data>
<data name="ImplicitRemotingPipelineBatchingException" xml:space="preserve">
<value>Exception while checking the command for implicit remoting batching: {0}</value>
</data>
<data name="ImplicitRemotingPipelineBatchingSuccess" xml:space="preserve">
<value>Implicit remoting command pipeline has been batched for execution on remote target.</value>
</data>
</root>