Skip to content

Commit 82bc081

Browse files
committed
Fix final issues before preview release
- Send TerminatedEvent from debug service when script execution completes - Set VariableDetails value string to space when extendable (VS Code bug) - Add ExecutionPolicy setting for machines with higher default setting - Add extensive logging in PowerShellSession
1 parent c47306f commit 82bc081

File tree

5 files changed

+152
-16
lines changed

5 files changed

+152
-16
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.PowerShell.EditorServices.Transport.Stdio.Message;
2+
3+
namespace Microsoft.PowerShell.EditorServices.Transport.Stdio.Event
4+
{
5+
[MessageTypeName("terminated")]
6+
public class TerminatedEvent : EventBase<object>
7+
{
8+
}
9+
}

src/PowerShellEditorServices.Transport.Stdio/PowerShellEditorServices.Transport.Stdio.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<Compile Include="Event\ReplWriteOutputEvent.cs" />
7171
<Compile Include="Event\StartedEvent.cs" />
7272
<Compile Include="Event\StoppedEvent.cs" />
73+
<Compile Include="Event\TerminatedEvent.cs" />
7374
<Compile Include="Message\IMessageProcessor.cs" />
7475
<Compile Include="Message\MessageBase.cs" />
7576
<Compile Include="Message\MessageParseException.cs" />

src/PowerShellEditorServices.Transport.Stdio/Request/LaunchRequest.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using Microsoft.PowerShell.EditorServices.Session;
2+
using Microsoft.PowerShell.EditorServices.Transport.Stdio.Event;
23
using Microsoft.PowerShell.EditorServices.Transport.Stdio.Message;
34
using Microsoft.PowerShell.EditorServices.Transport.Stdio.Response;
5+
using Microsoft.PowerShell.EditorServices.Utility;
46
using Nito.AsyncEx;
7+
using System;
58
using System.Collections.Generic;
69
using System.Threading.Tasks;
710

@@ -17,8 +20,17 @@ public override async Task ProcessMessage(
1720
// Execute the given PowerShell script and send the response.
1821
// Note that we aren't waiting for execution to complete here
1922
// because the debugger could stop while the script executes.
20-
editorSession.PowerShellSession.ExecuteScript(
21-
this.Arguments.Program);
23+
editorSession.PowerShellSession
24+
.ExecuteScriptAtPath(this.Arguments.Program)
25+
.ContinueWith(
26+
async (t) =>
27+
{
28+
Logger.Write(LogLevel.Verbose, "Execution completed, terminating...");
29+
30+
// TODO: Find a way to exit more gracefully!
31+
await messageWriter.WriteMessage(new TerminatedEvent());
32+
Environment.Exit(0);
33+
});
2234

2335
await messageWriter.WriteMessage(
2436
this.PrepareResponse(

src/PowerShellEditorServices/Console/PowerShellSession.cs

Lines changed: 127 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace Microsoft.PowerShell.EditorServices.Console
1111
using System.Management.Automation;
1212
using System.Management.Automation.Host;
1313
using System.Management.Automation.Runspaces;
14+
using System.Text;
1415
using System.Threading;
1516

1617
/// <summary>
@@ -152,6 +153,9 @@ private void Initialize(Runspace initialRunspace)
152153
this.powerShell.InvocationStateChanged += powerShell_InvocationStateChanged;
153154
this.powerShell.Runspace = this.currentRunspace;
154155

156+
// TODO: Should this be configurable?
157+
this.SetExecutionPolicy(ExecutionPolicy.RemoteSigned);
158+
155159
this.SessionState = PowerShellSessionState.Ready;
156160
}
157161

@@ -192,6 +196,8 @@ public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
192196
if (Thread.CurrentThread.ManagedThreadId != this.pipelineThreadId &&
193197
this.pipelineExecutionTask != null)
194198
{
199+
Logger.Write(LogLevel.Verbose, "Passing command execution to pipeline thread.");
200+
195201
PipelineExecutionRequest<TResult> executionRequest =
196202
new PipelineExecutionRequest<TResult>(
197203
this, psCommand, sendOutputToHost);
@@ -205,23 +211,29 @@ public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
205211
}
206212
else
207213
{
208-
// Instruct PowerShell to send output and errors to the host
209-
if (sendOutputToHost)
214+
try
210215
{
211-
psCommand.Commands[0].MergeMyResults(
212-
PipelineResultTypes.Error,
213-
PipelineResultTypes.Output);
216+
// Instruct PowerShell to send output and errors to the host
217+
if (sendOutputToHost)
218+
{
219+
psCommand.Commands[0].MergeMyResults(
220+
PipelineResultTypes.Error,
221+
PipelineResultTypes.Output);
214222

215-
psCommand.Commands.Add(
216-
this.GetOutputCommand(
217-
endOfStatement: false));
218-
}
223+
psCommand.Commands.Add(
224+
this.GetOutputCommand(
225+
endOfStatement: false));
226+
}
219227

220-
try
221-
{
222228
if (this.currentRunspace.RunspaceAvailability == RunspaceAvailability.AvailableForNestedCommand ||
223229
this.debuggerStoppedTask != null)
224230
{
231+
Logger.Write(
232+
LogLevel.Verbose,
233+
string.Format(
234+
"Attempting to execute nested pipeline command(s):\r\n\r\n{0}",
235+
GetStringForPSCommand(psCommand)));
236+
225237
using (Pipeline pipeline = this.currentRunspace.CreateNestedPipeline())
226238
{
227239
foreach (var command in psCommand.Commands)
@@ -240,6 +252,12 @@ public async Task<IEnumerable<TResult>> ExecuteCommand<TResult>(
240252
}
241253
else
242254
{
255+
Logger.Write(
256+
LogLevel.Verbose,
257+
string.Format(
258+
"Attempting to execute command(s):\r\n\r\n{0}",
259+
GetStringForPSCommand(psCommand)));
260+
243261
// Set the runspace
244262
var runspaceHandle = await this.GetRunspaceHandle();
245263
if (runspaceHandle.Runspace.RunspaceAvailability != RunspaceAvailability.AvailableForNestedCommand)
@@ -264,14 +282,30 @@ await Task.Factory.StartNew<IEnumerable<TResult>>(
264282

265283
runspaceHandle.Dispose();
266284

285+
if (this.powerShell.HadErrors)
286+
{
287+
// TODO: Find a good way to extract errors!
288+
Logger.Write(
289+
LogLevel.Error,
290+
"Execution completed with errors.");
291+
}
292+
else
293+
{
294+
Logger.Write(
295+
LogLevel.Verbose,
296+
"Execution completed successfully.");
297+
}
298+
267299
bool hadErrors = this.powerShell.HadErrors;
268300
return taskResult;
269301
}
270302
}
271303
catch (RuntimeException e)
272304
{
273305
// TODO: Return an error
274-
string boo = e.Message;
306+
Logger.Write(
307+
LogLevel.Error,
308+
"Exception occurred while attempting to execute command:\r\n\r\n" + e.ToString());
275309
}
276310
}
277311

@@ -307,13 +341,16 @@ public async Task ExecuteScriptAtPath(string scriptPath)
307341

308342
public void AbortExecution()
309343
{
310-
// TODO: Verify this behavior
344+
Logger.Write(LogLevel.Verbose, "Execution abort requested...");
345+
311346
this.powerShell.BeginStop(null, null);
312347
this.ResumeDebugger(DebuggerResumeAction.Stop);
313348
}
314349

315350
public void BreakExecution()
316351
{
352+
Logger.Write(LogLevel.Verbose, "Debugger break requested...");
353+
317354
this.currentRunspace.Debugger.SetDebuggerStepMode(true);
318355
}
319356

@@ -383,6 +420,13 @@ internal void ReleaseRunspaceHandle(RunspaceHandle runspaceHandle)
383420

384421
private void OnSessionStateChanged(object sender, SessionStateChangedEventArgs e)
385422
{
423+
Logger.Write(
424+
LogLevel.Verbose,
425+
string.Format(
426+
"Session state changed --\r\n\r\n Old state: {0}\r\n New state: {1}",
427+
this.SessionState.ToString(),
428+
e.NewSessionState.ToString()));
429+
386430
this.SessionState = e.NewSessionState;
387431

388432
if (this.SessionStateChanged != null)
@@ -472,6 +516,66 @@ private Command GetOutputCommand(bool endOfStatement)
472516
return outputCommand;
473517
}
474518

519+
private static string GetStringForPSCommand(PSCommand psCommand)
520+
{
521+
StringBuilder stringBuilder = new StringBuilder();
522+
523+
foreach (var command in psCommand.Commands)
524+
{
525+
stringBuilder.Append(" ");
526+
stringBuilder.AppendLine(command.ToString());
527+
}
528+
529+
return stringBuilder.ToString();
530+
}
531+
532+
private void SetExecutionPolicy(ExecutionPolicy desiredExecutionPolicy)
533+
{
534+
var currentPolicy = ExecutionPolicy.Undefined;
535+
536+
// Get the current execution policy so that we don't set it higher than it already is
537+
this.powerShell.Commands.AddCommand("Get-ExecutionPolicy");
538+
539+
var result = this.powerShell.Invoke<ExecutionPolicy>();
540+
if (result.Count > 0)
541+
{
542+
currentPolicy = result.FirstOrDefault();
543+
}
544+
545+
if (desiredExecutionPolicy < currentPolicy ||
546+
desiredExecutionPolicy == ExecutionPolicy.Bypass ||
547+
currentPolicy == ExecutionPolicy.Undefined)
548+
{
549+
Logger.Write(
550+
LogLevel.Verbose,
551+
string.Format(
552+
"Setting execution policy:\r\n Current = ExecutionPolicy.{0}\r\n Desired = ExecutionPolicy.{1}",
553+
currentPolicy,
554+
desiredExecutionPolicy));
555+
556+
this.powerShell.Commands.Clear();
557+
this.powerShell
558+
.AddCommand("Set-ExecutionPolicy")
559+
.AddParameter("ExecutionPolicy", desiredExecutionPolicy)
560+
.AddParameter("Scope", ExecutionPolicyScope.Process)
561+
.AddParameter("Force");
562+
563+
this.powerShell.Invoke();
564+
this.powerShell.Commands.Clear();
565+
566+
// TODO: Ensure there were no errors?
567+
}
568+
else
569+
{
570+
Logger.Write(
571+
LogLevel.Verbose,
572+
string.Format(
573+
"Current execution policy: ExecutionPolicy.{0}",
574+
currentPolicy));
575+
576+
}
577+
}
578+
475579
#endregion
476580

477581
#region Events
@@ -482,6 +586,8 @@ private void OnDebuggerStop(object sender, DebuggerStopEventArgs e)
482586
{
483587
if (!this.isStopping)
484588
{
589+
Logger.Write(LogLevel.Verbose, "Debugger stopped execution.");
590+
485591
// Set the task so a result can be set
486592
this.debuggerStoppedTask =
487593
new TaskCompletionSource<DebuggerResumeAction>();
@@ -499,6 +605,8 @@ private void OnDebuggerStop(object sender, DebuggerStopEventArgs e)
499605
this.DebuggerStop(sender, e);
500606
}
501607

608+
Logger.Write(LogLevel.Verbose, "Starting pipeline thread message loop...");
609+
502610
while (true)
503611
{
504612
int taskIndex =
@@ -509,17 +617,23 @@ private void OnDebuggerStop(object sender, DebuggerStopEventArgs e)
509617
if (taskIndex == 0)
510618
{
511619
e.ResumeAction = this.debuggerStoppedTask.Task.Result;
620+
Logger.Write(LogLevel.Verbose, "Received debugger resume action " + e.ResumeAction.ToString());
621+
512622
break;
513623
}
514624
else if (taskIndex == 1)
515625
{
626+
Logger.Write(LogLevel.Verbose, "Received pipeline thread execution request.");
627+
516628
IPipelineExecutionRequest executionRequest =
517629
this.pipelineExecutionTask.Task.Result;
518630

519631
this.pipelineExecutionTask = new TaskCompletionSource<IPipelineExecutionRequest>();
520632

521633
executionRequest.Execute().Wait();
522634

635+
Logger.Write(LogLevel.Verbose, "Pipeline thread execution completed.");
636+
523637
this.pipelineResultTask.SetResult(executionRequest);
524638
}
525639
else

src/PowerShellEditorServices/Console/VariableDetails.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public VariableDetails(string name, object value)
5353
this.ValueString =
5454
this.IsExpandable == false ?
5555
GetValueString(value) :
56-
string.Empty;
56+
" "; // An empty string isn't enough due to a temporary bug in VS Code.
5757
}
5858

5959
#endregion

0 commit comments

Comments
 (0)