forked from PowerShell/PowerShellEditorServices
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRunspaceDetails.cs
318 lines (282 loc) · 10.9 KB
/
RunspaceDetails.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Management.Automation.Runspaces;
using System.Collections.Generic;
namespace Microsoft.PowerShell.EditorServices.Session
{
/// <summary>
/// Specifies the possible types of a runspace.
/// </summary>
public enum RunspaceLocation
{
/// <summary>
/// A runspace on the local machine.
/// </summary>
Local,
/// <summary>
/// A runspace on a different machine.
/// </summary>
Remote
}
/// <summary>
/// Specifies the context in which the runspace was encountered.
/// </summary>
public enum RunspaceContext
{
/// <summary>
/// The original runspace in a local or remote session.
/// </summary>
Original,
/// <summary>
/// A runspace in a process that was entered with Enter-PSHostProcess.
/// </summary>
EnteredProcess,
/// <summary>
/// A runspace that is being debugged with Debug-Runspace.
/// </summary>
DebuggedRunspace
}
/// <summary>
/// Provides details about a runspace being used in the current
/// editing session.
/// </summary>
public class RunspaceDetails
{
#region Private Fields
private Dictionary<Type, IRunspaceCapability> capabilities =
new Dictionary<Type, IRunspaceCapability>();
#endregion
#region Properties
/// <summary>
/// Gets the Runspace instance for which this class contains details.
/// </summary>
internal Runspace Runspace { get; private set; }
/// <summary>
/// Gets the PowerShell version of the new runspace.
/// </summary>
public PowerShellVersionDetails PowerShellVersion { get; private set; }
/// <summary>
/// Gets the runspace location, either Local or Remote.
/// </summary>
public RunspaceLocation Location { get; private set; }
/// <summary>
/// Gets the context in which the runspace was encountered.
/// </summary>
public RunspaceContext Context { get; private set; }
/// <summary>
/// Gets the "connection string" for the runspace, generally the
/// ComputerName for a remote runspace or the ProcessId of an
/// "Attach" runspace.
/// </summary>
public string ConnectionString { get; private set; }
/// <summary>
/// Gets the details of the runspace's session at the time this
/// RunspaceDetails object was created.
/// </summary>
public SessionDetails SessionDetails { get; private set; }
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of the RunspaceDetails class.
/// </summary>
/// <param name="runspace">
/// The runspace for which this instance contains details.
/// </param>
/// <param name="sessionDetails">
/// The SessionDetails for the runspace.
/// </param>
/// <param name="powerShellVersion">
/// The PowerShellVersionDetails of the runspace.
/// </param>
/// <param name="runspaceLocation">
/// The RunspaceLocation of the runspace.
/// </param>
/// <param name="runspaceContext">
/// The RunspaceContext of the runspace.
/// </param>
/// <param name="connectionString">
/// The connection string of the runspace.
/// </param>
public RunspaceDetails(
Runspace runspace,
SessionDetails sessionDetails,
PowerShellVersionDetails powerShellVersion,
RunspaceLocation runspaceLocation,
RunspaceContext runspaceContext,
string connectionString)
{
this.Runspace = runspace;
this.SessionDetails = sessionDetails;
this.PowerShellVersion = powerShellVersion;
this.Location = runspaceLocation;
this.Context = runspaceContext;
this.ConnectionString = connectionString;
}
#endregion
#region Public Methods
internal void AddCapability<TCapability>(TCapability capability)
where TCapability : IRunspaceCapability
{
this.capabilities.Add(typeof(TCapability), capability);
}
internal TCapability GetCapability<TCapability>()
where TCapability : IRunspaceCapability
{
TCapability capability = default(TCapability);
this.TryGetCapability<TCapability>(out capability);
return capability;
}
internal bool TryGetCapability<TCapability>(out TCapability capability)
where TCapability : IRunspaceCapability
{
IRunspaceCapability capabilityAsInterface = default(TCapability);
if (this.capabilities.TryGetValue(typeof(TCapability), out capabilityAsInterface))
{
capability = (TCapability)capabilityAsInterface;
return true;
}
capability = default(TCapability);
return false;
}
internal bool HasCapability<TCapability>()
{
return this.capabilities.ContainsKey(typeof(TCapability));
}
/// <summary>
/// Creates and populates a new RunspaceDetails instance for the given runspace.
/// </summary>
/// <param name="runspace">
/// The runspace for which details will be gathered.
/// </param>
/// <param name="sessionDetails">
/// The SessionDetails for the runspace.
/// </param>
/// <param name="logger">An ILogger implementation used for writing log messages.</param>
/// <returns>A new RunspaceDetails instance.</returns>
internal static RunspaceDetails CreateFromRunspace(
Runspace runspace,
SessionDetails sessionDetails,
ILogger logger)
{
Validate.IsNotNull(nameof(runspace), runspace);
Validate.IsNotNull(nameof(sessionDetails), sessionDetails);
var runspaceLocation = RunspaceLocation.Local;
var runspaceContext = RunspaceContext.Original;
var versionDetails = PowerShellVersionDetails.GetVersionDetails(runspace, logger);
string connectionString = null;
if (runspace.ConnectionInfo != null)
{
// Use 'dynamic' to avoid missing NamedPipeRunspaceConnectionInfo
// on PS v3 and v4
try
{
dynamic connectionInfo = runspace.ConnectionInfo;
if (connectionInfo.ProcessId != null)
{
connectionString = connectionInfo.ProcessId.ToString();
runspaceContext = RunspaceContext.EnteredProcess;
}
}
catch (RuntimeBinderException)
{
// ProcessId property isn't on the object, move on.
}
// Grab the $host.name which will tell us if we're in a PSRP session or not
string hostName =
PowerShellContext.ExecuteScriptAndGetItem<string>(
"$Host.Name",
runspace,
defaultValue: string.Empty);
// hostname is 'ServerRemoteHost' when the user enters a session.
// ex. Enter-PSSession, Enter-PSHostProcess
if (hostName.Equals("ServerRemoteHost", StringComparison.Ordinal))
{
runspaceLocation = RunspaceLocation.Remote;
connectionString =
runspace.ConnectionInfo.ComputerName +
(connectionString != null ? $"-{connectionString}" : string.Empty);
}
}
return
new RunspaceDetails(
runspace,
sessionDetails,
versionDetails,
runspaceLocation,
runspaceContext,
connectionString);
}
/// <summary>
/// Creates a clone of the given runspace through which another
/// runspace was attached. Sets the IsAttached property of the
/// resulting RunspaceDetails object to true.
/// </summary>
/// <param name="runspaceDetails">
/// The RunspaceDetails object which the new object based.
/// </param>
/// <param name="runspaceContext">
/// The RunspaceContext of the runspace.
/// </param>
/// <param name="sessionDetails">
/// The SessionDetails for the runspace.
/// </param>
/// <returns>
/// A new RunspaceDetails instance for the attached runspace.
/// </returns>
public static RunspaceDetails CreateFromContext(
RunspaceDetails runspaceDetails,
RunspaceContext runspaceContext,
SessionDetails sessionDetails)
{
return
new RunspaceDetails(
runspaceDetails.Runspace,
sessionDetails,
runspaceDetails.PowerShellVersion,
runspaceDetails.Location,
runspaceContext,
runspaceDetails.ConnectionString);
}
/// <summary>
/// Creates a new RunspaceDetails object from a remote
/// debugging session.
/// </summary>
/// <param name="runspaceDetails">
/// The RunspaceDetails object which the new object based.
/// </param>
/// <param name="runspaceLocation">
/// The RunspaceLocation of the runspace.
/// </param>
/// <param name="runspaceContext">
/// The RunspaceContext of the runspace.
/// </param>
/// <param name="sessionDetails">
/// The SessionDetails for the runspace.
/// </param>
/// <returns>
/// A new RunspaceDetails instance for the attached runspace.
/// </returns>
public static RunspaceDetails CreateFromDebugger(
RunspaceDetails runspaceDetails,
RunspaceLocation runspaceLocation,
RunspaceContext runspaceContext,
SessionDetails sessionDetails)
{
// TODO: Get the PowerShellVersion correctly!
return
new RunspaceDetails(
runspaceDetails.Runspace,
sessionDetails,
runspaceDetails.PowerShellVersion,
runspaceLocation,
runspaceContext,
runspaceDetails.ConnectionString);
}
#endregion
}
}