@@ -55,6 +55,8 @@ internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRuns
55
55
56
56
private readonly IdempotentLatch _isRunningLatch = new ( ) ;
57
57
58
+ private EngineIntrinsics _mainRunspaceEngineIntrinsics ;
59
+
58
60
private bool _shouldExit = false ;
59
61
60
62
private string _localComputerName ;
@@ -345,17 +347,18 @@ public Task SetInitialWorkingDirectoryAsync(string path, CancellationToken cance
345
347
346
348
private void Run ( )
347
349
{
348
- ( PowerShell pwsh , RunspaceInfo localRunspaceInfo ) = CreateInitialPowerShellSession ( ) ;
350
+ ( PowerShell pwsh , RunspaceInfo localRunspaceInfo , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShellSession ( ) ;
351
+ _mainRunspaceEngineIntrinsics = engineIntrinsics ;
349
352
_localComputerName = localRunspaceInfo . SessionDetails . ComputerName ;
350
353
_runspaceStack . Push ( new RunspaceFrame ( pwsh . Runspace , localRunspaceInfo ) ) ;
351
354
PushPowerShellAndRunLoop ( pwsh , PowerShellFrameType . Normal , localRunspaceInfo ) ;
352
355
}
353
356
354
- private ( PowerShell , RunspaceInfo ) CreateInitialPowerShellSession ( )
357
+ private ( PowerShell , RunspaceInfo , EngineIntrinsics ) CreateInitialPowerShellSession ( )
355
358
{
356
- PowerShell pwsh = CreateInitialPowerShell ( _hostInfo , _readLineProvider ) ;
359
+ ( PowerShell pwsh , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShell ( _hostInfo , _readLineProvider ) ;
357
360
RunspaceInfo localRunspaceInfo = RunspaceInfo . CreateFromLocalPowerShell ( _logger , pwsh ) ;
358
- return ( pwsh , localRunspaceInfo ) ;
361
+ return ( pwsh , localRunspaceInfo , engineIntrinsics ) ;
359
362
}
360
363
361
364
private void PushPowerShellAndRunLoop ( SMA . PowerShell pwsh , PowerShellFrameType frameType , RunspaceInfo newRunspaceInfo = null )
@@ -611,7 +614,7 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
611
614
return pwsh ;
612
615
}
613
616
614
- public PowerShell CreateInitialPowerShell (
617
+ public ( PowerShell , EngineIntrinsics ) CreateInitialPowerShell (
615
618
HostStartupInfo hostStartupInfo ,
616
619
ReadLineProvider readLineProvider )
617
620
{
@@ -647,7 +650,7 @@ public PowerShell CreateInitialPowerShell(
647
650
}
648
651
}
649
652
650
- return pwsh ;
653
+ return ( pwsh , engineIntrinsics ) ;
651
654
}
652
655
653
656
private Runspace CreateInitialRunspace ( InitialSessionState initialSessionState )
@@ -666,7 +669,27 @@ private Runspace CreateInitialRunspace(InitialSessionState initialSessionState)
666
669
667
670
private void OnPowerShellIdle ( )
668
671
{
669
- if ( _taskQueue . Count == 0 )
672
+ IReadOnlyList < PSEventSubscriber > eventSubscribers = _mainRunspaceEngineIntrinsics . Events . Subscribers ;
673
+
674
+ // Go through pending event subscribers and:
675
+ // - if we have any subscribers, ensure we process any events
676
+ // - if we have any idle events, generate an idle event and process that
677
+ bool runPipelineForEventProcessing = false ;
678
+ foreach ( PSEventSubscriber subscriber in eventSubscribers )
679
+ {
680
+ runPipelineForEventProcessing = true ;
681
+
682
+ if ( string . Equals ( subscriber . SourceIdentifier , PSEngineEvent . OnIdle , StringComparison . OrdinalIgnoreCase ) )
683
+ {
684
+ // PowerShell thinks we're in a call (the ReadLine call) rather than idle,
685
+ // but we know we're sitting in the prompt.
686
+ // So we need to generate the idle event ourselves
687
+ _mainRunspaceEngineIntrinsics . Events . GenerateEvent ( PSEngineEvent . OnIdle , sender : null , args : null , extraData : null ) ;
688
+ break ;
689
+ }
690
+ }
691
+
692
+ if ( ! runPipelineForEventProcessing && _taskQueue . Count == 0 )
670
693
{
671
694
return ;
672
695
}
@@ -686,9 +709,21 @@ private void OnPowerShellIdle()
686
709
return ;
687
710
}
688
711
712
+ // If we're executing a task, we don't need to run an extra pipeline later for events
713
+ // TODO: This may not be a PowerShell task, so ideally we can differentiate that here.
714
+ // For now it's mostly true and an easy assumption to make.
715
+ runPipelineForEventProcessing = false ;
689
716
task . ExecuteSynchronously ( cancellationScope . CancellationToken ) ;
690
717
}
691
718
}
719
+
720
+ // We didn't end up executinng anything in the background,
721
+ // so we need to run a small artificial pipeline instead
722
+ // to force event processing
723
+ if ( runPipelineForEventProcessing )
724
+ {
725
+ InvokePSCommand ( new PSCommand ( ) . AddScript ( "0" , useLocalScope : true ) , PowerShellExecutionOptions . Default , CancellationToken . None ) ;
726
+ }
692
727
}
693
728
694
729
private void OnCancelKeyPress ( object sender , ConsoleCancelEventArgs args )
@@ -769,7 +804,8 @@ private Task PopOrReinitializeRunspaceAsync()
769
804
// If our main runspace was corrupted,
770
805
// we must re-initialize our state.
771
806
// TODO: Use runspace.ResetRunspaceState() here instead
772
- ( PowerShell pwsh , RunspaceInfo runspaceInfo ) = CreateInitialPowerShellSession ( ) ;
807
+ ( PowerShell pwsh , RunspaceInfo runspaceInfo , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShellSession ( ) ;
808
+ _mainRunspaceEngineIntrinsics = engineIntrinsics ;
773
809
PushPowerShell ( new PowerShellContextFrame ( pwsh , runspaceInfo , PowerShellFrameType . Normal ) ) ;
774
810
775
811
_logger . LogError ( $ "Top level runspace entered state '{ oldRunspaceState . State } ' for reason '{ oldRunspaceState . Reason } ' and was reinitialized."
0 commit comments