From acf5eb5053b38c14c13126b4927d34b8a5d15bdd Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Mon, 5 Nov 2018 15:22:46 -0800 Subject: [PATCH] Adding verbose output for experimental implicit remoting batching feature (#8166) --- .../engine/Utils.cs | 82 ++++++++++++------- .../resources/ParserStrings.resx | 18 ++++ 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index de4bdc5b0b..a940f3aaac 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1382,38 +1382,40 @@ namespace System.Management.Automation // 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 cmdInfoList)) @@ -1436,6 +1438,7 @@ namespace System.Management.Automation // 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; } @@ -1446,6 +1449,7 @@ namespace System.Management.Automation var sessionIdString = privateData["ImplicitSessionId"] as string; if (string.IsNullOrEmpty(sessionIdString)) { + WriteVerbose(ps, string.Format(CultureInfo.CurrentCulture, ParserStrings.ImplicitRemotingPipelineBatchingNotImplicitCommand, cmdInfo.Name)); success = false; break; } @@ -1457,12 +1461,14 @@ namespace System.Management.Automation } 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; } @@ -1491,13 +1497,20 @@ namespace System.Management.Automation var psSession = ps.Invoke().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 { @@ -1514,12 +1527,25 @@ namespace System.Management.Automation 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 commandNames, out Collection cmdInfoList) { diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 66d17c033e..ab3e6cbc08 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -1470,4 +1470,22 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent Command pipeline not supported for implicit remoting batching. + + Command is not a simple pipeline and cannot be batched. + + + The pipeline command '{0}' is not an implicit remoting command or an approved batching command. + + + The pipeline command '{0}' is for a different remote session and cannot be batched. + + + The implicit remoting PSSession for batching could not be retrieved. + + + Exception while checking the command for implicit remoting batching: {0} + + + Implicit remoting command pipeline has been batched for execution on remote target. +