Skip to content

Commit c3c19b1

Browse files
committed
Enable support for PowerShell v3 and v4
This change finishes our PowerShell v3 and v4 support by conditionally changing behavior for those versions. This works by using an interface facade in front of any version-specific behavior so that the CLR doesn't try to resolve method names that aren't available in a particular version. Resolves #73.
1 parent a1e6dbc commit c3c19b1

File tree

8 files changed

+241
-82
lines changed

8 files changed

+241
-82
lines changed

src/PowerShellEditorServices.Protocol/Server/DebugAdapter.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,14 @@ protected Task HandlePauseRequest(
295295
object pauseParams,
296296
RequestContext<object> requestContext)
297297
{
298-
editorSession.DebugService.Break();
298+
try
299+
{
300+
editorSession.DebugService.Break();
301+
}
302+
catch (NotSupportedException e)
303+
{
304+
return requestContext.SendError(e.Message);
305+
}
299306

300307
// This request is responded to by sending the "stopped" event
301308
return Task.FromResult(true);

src/PowerShellEditorServices/PowerShellEditorServices.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,12 @@
9898
<Compile Include="Console\ChoiceDetails.cs" />
9999
<Compile Include="Session\EditorSession.cs" />
100100
<Compile Include="Console\IConsoleHost.cs" />
101+
<Compile Include="Session\IVersionSpecificOperations.cs" />
101102
<Compile Include="Session\OutputType.cs" />
102103
<Compile Include="Session\OutputWrittenEventArgs.cs" />
104+
<Compile Include="Session\PowerShell3Operations.cs" />
105+
<Compile Include="Session\PowerShell4Operations.cs" />
106+
<Compile Include="Session\PowerShell5Operations.cs" />
103107
<Compile Include="Session\PowerShellExecutionResult.cs" />
104108
<Compile Include="Session\PowerShellContext.cs" />
105109
<Compile Include="Session\PowerShellContextState.cs" />

src/PowerShellEditorServices/Session/EditorSession.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
using Microsoft.PowerShell.EditorServices.Console;
77
using Microsoft.PowerShell.EditorServices.Utility;
8+
using System;
89
using System.IO;
910
using System.Management.Automation;
1011
using System.Management.Automation.Runspaces;
12+
using System.Reflection;
1113
using System.Threading;
1214

1315
namespace Microsoft.PowerShell.EditorServices
@@ -66,17 +68,34 @@ public void StartSession()
6668
this.DebugService = new DebugService(this.PowerShellContext);
6769
this.ConsoleService = new ConsoleService(this.PowerShellContext);
6870

69-
// AnalysisService will throw FileNotFoundException if
70-
// Script Analyzer binaries are not included.
71-
try
71+
// Only enable the AnalysisService if the machine has PowerShell
72+
// v5 installed. Script Analyzer works on earlier PowerShell
73+
// versions but our hard dependency on their binaries complicates
74+
// the deployment and assembly loading since we would have to
75+
// conditionally load the binaries for v3/v4 support. This problem
76+
// will be solved in the future by using Script Analyzer as a
77+
// module rather than an assembly dependency.
78+
if (this.PowerShellContext.PowerShellVersion.Major >= 5)
7279
{
73-
this.AnalysisService = new AnalysisService();
80+
// AnalysisService will throw FileNotFoundException if
81+
// Script Analyzer binaries are not included.
82+
try
83+
{
84+
this.AnalysisService = new AnalysisService();
85+
}
86+
catch (FileNotFoundException)
87+
{
88+
Logger.Write(
89+
LogLevel.Warning,
90+
"Script Analyzer binaries not found, AnalysisService will be disabled.");
91+
}
7492
}
75-
catch (FileNotFoundException)
93+
else
7694
{
7795
Logger.Write(
78-
LogLevel.Warning,
79-
"Script Analyzer binaries not found, AnalysisService will be disabled.");
96+
LogLevel.Normal,
97+
"Script Analyzer cannot be loaded due to unsupported PowerShell version " +
98+
this.PowerShellContext.PowerShellVersion.ToString());
8099
}
81100

82101
// Create a workspace to contain open files
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Collections.Generic;
7+
using System.Management.Automation;
8+
using System.Management.Automation.Runspaces;
9+
10+
namespace Microsoft.PowerShell.EditorServices.Session
11+
{
12+
internal interface IVersionSpecificOperations
13+
{
14+
void ConfigureDebugger(Runspace runspace);
15+
16+
void PauseDebugger(Runspace runspace);
17+
18+
IEnumerable<TResult> ExecuteCommandInDebugger<TResult>(
19+
PowerShellContext powerShellContext,
20+
Runspace currentRunspace,
21+
PSCommand psCommand,
22+
bool sendOutputToHost);
23+
}
24+
}
25+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Management.Automation;
10+
using System.Management.Automation.Runspaces;
11+
12+
namespace Microsoft.PowerShell.EditorServices.Session
13+
{
14+
internal class PowerShell3Operations : IVersionSpecificOperations
15+
{
16+
public void ConfigureDebugger(Runspace runspace)
17+
{
18+
// The debugger has no SetDebugMode in PowerShell v3.
19+
}
20+
21+
public void PauseDebugger(Runspace runspace)
22+
{
23+
// The debugger cannot be paused in PowerShell v3.
24+
throw new NotSupportedException("Debugger cannot be paused in PowerShell v3");
25+
}
26+
27+
public IEnumerable<TResult> ExecuteCommandInDebugger<TResult>(
28+
PowerShellContext powerShellContext,
29+
Runspace currentRunspace,
30+
PSCommand psCommand,
31+
bool sendOutputToHost)
32+
{
33+
IEnumerable<TResult> executionResult = null;
34+
35+
using (var nestedPipeline = currentRunspace.CreateNestedPipeline())
36+
{
37+
foreach (var command in psCommand.Commands)
38+
{
39+
nestedPipeline.Commands.Add(command);
40+
}
41+
42+
executionResult =
43+
nestedPipeline
44+
.Invoke()
45+
.Select(pso => pso.BaseObject)
46+
.Cast<TResult>();
47+
}
48+
49+
// Write the output to the host if necessary
50+
if (sendOutputToHost)
51+
{
52+
foreach (var line in executionResult)
53+
{
54+
powerShellContext.WriteOutput(line.ToString(), true);
55+
}
56+
}
57+
58+
return executionResult;
59+
}
60+
}
61+
}
62+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Management.Automation;
10+
using System.Management.Automation.Runspaces;
11+
12+
namespace Microsoft.PowerShell.EditorServices.Session
13+
{
14+
internal class PowerShell4Operations : IVersionSpecificOperations
15+
{
16+
public void ConfigureDebugger(Runspace runspace)
17+
{
18+
#if !PowerShellv3
19+
runspace.Debugger.SetDebugMode(DebugModes.LocalScript | DebugModes.RemoteScript);
20+
#endif
21+
}
22+
23+
public virtual void PauseDebugger(Runspace runspace)
24+
{
25+
// The debugger cannot be paused in PowerShell v4.
26+
throw new NotSupportedException("Debugger cannot be paused in PowerShell v4");
27+
}
28+
29+
public IEnumerable<TResult> ExecuteCommandInDebugger<TResult>(
30+
PowerShellContext powerShellContext,
31+
Runspace currentRunspace,
32+
PSCommand psCommand,
33+
bool sendOutputToHost)
34+
{
35+
PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
36+
37+
#if !PowerShellv3
38+
if (sendOutputToHost)
39+
{
40+
outputCollection.DataAdded +=
41+
(obj, e) =>
42+
{
43+
for (int i = e.Index; i < outputCollection.Count; i++)
44+
{
45+
powerShellContext.WriteOutput(
46+
outputCollection[i].ToString(),
47+
true);
48+
}
49+
};
50+
}
51+
52+
DebuggerCommandResults commandResults =
53+
currentRunspace.Debugger.ProcessCommand(
54+
psCommand,
55+
outputCollection);
56+
#endif
57+
58+
return
59+
outputCollection
60+
.Select(pso => pso.BaseObject)
61+
.Cast<TResult>();
62+
}
63+
}
64+
}
65+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Management.Automation.Runspaces;
7+
8+
namespace Microsoft.PowerShell.EditorServices.Session
9+
{
10+
internal class PowerShell5Operations : PowerShell4Operations
11+
{
12+
public override void PauseDebugger(Runspace runspace)
13+
{
14+
#if !PowerShellv3 && !PowerShellv4
15+
runspace.Debugger.SetDebuggerStepMode(true);
16+
#endif
17+
}
18+
}
19+
}
20+

0 commit comments

Comments
 (0)