@@ -33,7 +33,7 @@ public sealed class EditorServicesLoader : IDisposable
3333 {
3434#if ! CoreCLR
3535 // See https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
36- private const int Net462Version = 394802 ;
36+ private const int Net48Version = 528040 ;
3737
3838 private static readonly string s_psesBaseDirPath = Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) ;
3939#endif
@@ -49,37 +49,28 @@ public sealed class EditorServicesLoader : IDisposable
4949 /// </summary>
5050 /// <param name="logger">The host logger to use.</param>
5151 /// <param name="hostConfig">The host configuration to start editor services with.</param>
52- /// <param name="sessionFileWriter">The session file writer to write the session file with.</param>
53- /// <returns></returns>
54- public static EditorServicesLoader Create (
55- HostLogger logger ,
56- EditorServicesConfig hostConfig ,
57- ISessionFileWriter sessionFileWriter ) => Create ( logger , hostConfig , sessionFileWriter , loggersToUnsubscribe : null ) ;
58-
59- /// <summary>
60- /// Create a new Editor Services loader.
61- /// </summary>
62- /// <param name="logger">The host logger to use.</param>
63- /// <param name="hostConfig">The host configuration to start editor services with.</param>
64- /// <param name="sessionFileWriter">The session file writer to write the session file with.</param>
52+ /// <param name="sessionDetailsPath">Path to the session file to create on startup or startup failure.</param>
6553 /// <param name="loggersToUnsubscribe">The loggers to unsubscribe form writing to the terminal.</param>
66- /// <returns></returns>
6754 public static EditorServicesLoader Create (
6855 HostLogger logger ,
6956 EditorServicesConfig hostConfig ,
70- ISessionFileWriter sessionFileWriter ,
57+ string sessionDetailsPath ,
7158 IReadOnlyCollection < IDisposable > loggersToUnsubscribe )
7259 {
73- if ( logger == null )
60+ if ( logger is null )
7461 {
7562 throw new ArgumentNullException ( nameof ( logger ) ) ;
7663 }
7764
78- if ( hostConfig == null )
65+ if ( hostConfig is null )
7966 {
8067 throw new ArgumentNullException ( nameof ( hostConfig ) ) ;
8168 }
8269
70+ Version powerShellVersion = GetPSVersion ( ) ;
71+ SessionFileWriter sessionFileWriter = new ( logger , sessionDetailsPath , powerShellVersion ) ;
72+ logger . Log ( PsesLogLevel . Diagnostic , "Session file writer created" ) ;
73+
8374#if CoreCLR
8475 // In .NET Core, we add an event here to redirect dependency loading to the new AssemblyLoadContext we load PSES' dependencies into
8576 logger . Log ( PsesLogLevel . Verbose , "Adding AssemblyResolve event handler for new AssemblyLoadContext dependency loading" ) ;
@@ -167,7 +158,7 @@ public static EditorServicesLoader Create(
167158 } ;
168159#endif
169160
170- return new EditorServicesLoader ( logger , hostConfig , sessionFileWriter , loggersToUnsubscribe ) ;
161+ return new EditorServicesLoader ( logger , hostConfig , sessionFileWriter , loggersToUnsubscribe , powerShellVersion ) ;
171162 }
172163
173164 private readonly EditorServicesConfig _hostConfig ;
@@ -178,33 +169,38 @@ public static EditorServicesLoader Create(
178169
179170 private readonly IReadOnlyCollection < IDisposable > _loggersToUnsubscribe ;
180171
172+ private readonly Version _powerShellVersion ;
173+
181174 private EditorServicesRunner _editorServicesRunner ;
182175
183176 private EditorServicesLoader (
184177 HostLogger logger ,
185178 EditorServicesConfig hostConfig ,
186179 ISessionFileWriter sessionFileWriter ,
187- IReadOnlyCollection < IDisposable > loggersToUnsubscribe )
180+ IReadOnlyCollection < IDisposable > loggersToUnsubscribe ,
181+ Version powerShellVersion )
188182 {
189183 _logger = logger ;
190184 _hostConfig = hostConfig ;
191185 _sessionFileWriter = sessionFileWriter ;
192186 _loggersToUnsubscribe = loggersToUnsubscribe ;
187+ _powerShellVersion = powerShellVersion ;
193188 }
194189
195190 /// <summary>
196191 /// Load Editor Services and its dependencies in an isolated way and start it.
197192 /// This method's returned task will end when Editor Services shuts down.
198193 /// </summary>
199- /// <returns></returns>
200194 public Task LoadAndRunEditorServicesAsync ( )
201195 {
202196 // Log important host information here
203197 LogHostInformation ( ) ;
204198
199+ CheckPowerShellVersion ( ) ;
200+
205201#if ! CoreCLR
206202 // Make sure the .NET Framework version supports .NET Standard 2.0
207- CheckNetFxVersion ( ) ;
203+ CheckDotNetVersion ( ) ;
208204#endif
209205
210206 // Add the bundled modules to the PSModulePath
@@ -241,10 +237,30 @@ private static void LoadEditorServices() =>
241237 // The call within this method is therefore a total no-op
242238 EditorServicesLoading . LoadEditorServicesForHost ( ) ;
243239
240+ private void CheckPowerShellVersion ( )
241+ {
242+ PSLanguageMode languageMode = Runspace . DefaultRunspace . SessionStateProxy . LanguageMode ;
243+
244+ _logger . Log ( PsesLogLevel . Verbose , $@ "
245+ == PowerShell Details ==
246+ - PowerShell version: { _powerShellVersion }
247+ - Language mode: { languageMode }
248+ " ) ;
249+
250+ if ( ( _powerShellVersion < new Version ( 5 , 1 ) )
251+ || ( _powerShellVersion >= new Version ( 6 , 0 ) && _powerShellVersion < new Version ( 7 , 2 ) ) )
252+ {
253+ _logger . Log ( PsesLogLevel . Error , $ "PowerShell { _powerShellVersion } is not supported, please update!") ;
254+ _sessionFileWriter . WriteSessionFailure ( "powerShellVersion" ) ;
255+ }
256+
257+ // TODO: Check if language mode still matters for support.
258+ }
259+
244260#if ! CoreCLR
245- private void CheckNetFxVersion ( )
261+ private void CheckDotNetVersion ( )
246262 {
247- _logger . Log ( PsesLogLevel . Diagnostic , "Checking that .NET Framework version is at least 4.6.2 " ) ;
263+ _logger . Log ( PsesLogLevel . Verbose , "Checking that .NET Framework version is at least 4.8 " ) ;
248264 using RegistryKey key = Registry . LocalMachine . OpenSubKey ( @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full" ) ;
249265 object netFxValue = key ? . GetValue ( "Release" ) ;
250266 if ( netFxValue == null || netFxValue is not int netFxVersion )
@@ -254,9 +270,10 @@ private void CheckNetFxVersion()
254270
255271 _logger . Log ( PsesLogLevel . Verbose , $ ".NET registry version: { netFxVersion } ") ;
256272
257- if ( netFxVersion < Net462Version )
273+ if ( netFxVersion < Net48Version )
258274 {
259- _logger . Log ( PsesLogLevel . Warning , $ ".NET Framework version { netFxVersion } lower than .NET 4.6.2. This runtime is not supported and you may experience errors. Please update your .NET runtime version.") ;
275+ _logger . Log ( PsesLogLevel . Error , $ ".NET Framework { netFxVersion } is out-of-date, please install at least 4.8: https://dotnet.microsoft.com/en-us/download/dotnet-framework") ;
276+ _sessionFileWriter . WriteSessionFailure ( "dotNetVersion" ) ;
260277 }
261278 }
262279#endif
@@ -322,30 +339,6 @@ private void LogHostInformation()
322339 - PowerShell output encoding: { GetPSOutputEncoding ( ) }
323340" ) ;
324341
325- LogPowerShellDetails ( ) ;
326-
327- LogOperatingSystemDetails ( ) ;
328- }
329-
330- private static string GetPSOutputEncoding ( )
331- {
332- using SMA . PowerShell pwsh = SMA . PowerShell . Create ( ) ;
333- return pwsh . AddScript ( "$OutputEncoding.EncodingName" , useLocalScope : true ) . Invoke < string > ( ) [ 0 ] ;
334- }
335-
336- private void LogPowerShellDetails ( )
337- {
338- PSLanguageMode languageMode = Runspace . DefaultRunspace . SessionStateProxy . LanguageMode ;
339-
340- _logger . Log ( PsesLogLevel . Verbose , $@ "
341- == PowerShell Details ==
342- - PowerShell version: { GetPSVersion ( ) }
343- - Language mode: { languageMode }
344- " ) ;
345- }
346-
347- private void LogOperatingSystemDetails ( )
348- {
349342 _logger . Log ( PsesLogLevel . Verbose , $@ "
350343== Environment Details ==
351344 - OS description: { RuntimeInformation . OSDescription }
@@ -354,6 +347,12 @@ private void LogOperatingSystemDetails()
354347" ) ;
355348 }
356349
350+ private static string GetPSOutputEncoding ( )
351+ {
352+ using SMA . PowerShell pwsh = SMA . PowerShell . Create ( ) ;
353+ return pwsh . AddScript ( "$OutputEncoding.EncodingName" , useLocalScope : true ) . Invoke < string > ( ) [ 0 ] ;
354+ }
355+
357356 // TODO: Deduplicate this with VersionUtils.
358357 private static string GetOSArchitecture ( )
359358 {
@@ -401,7 +400,7 @@ private void ValidateConfiguration()
401400 }
402401 }
403402
404- private static object GetPSVersion ( )
403+ private static Version GetPSVersion ( )
405404 {
406405 // In order to read the $PSVersionTable variable,
407406 // we are forced to create a new runspace to avoid concurrency issues,
@@ -412,7 +411,7 @@ private static object GetPSVersion()
412411 return typeof ( PSObject ) . Assembly
413412 . GetType ( "System.Management.Automation.PSVersionInfo" )
414413 . GetMethod ( "get_PSVersion" , BindingFlags . Static | BindingFlags . Public | BindingFlags . NonPublic )
415- . Invoke ( null , new object [ 0 ] /* Cannot use Array.Empty, since it must work in net452 */ ) ;
414+ . Invoke ( null , new object [ 0 ] /* Cannot use Array.Empty, since it must work in net452 */ ) as Version ;
416415#pragma warning restore CA1825
417416 }
418417 }
0 commit comments