@@ -55,6 +55,8 @@ internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRuns
5555
5656 private readonly IdempotentLatch _isRunningLatch = new ( ) ;
5757
58+ private EngineIntrinsics _mainRunspaceEngineIntrinsics ;
59+
5860 private bool _shouldExit = false ;
5961
6062 private string _localComputerName ;
@@ -345,17 +347,18 @@ public Task SetInitialWorkingDirectoryAsync(string path, CancellationToken cance
345347
346348 private void Run ( )
347349 {
348- ( PowerShell pwsh , RunspaceInfo localRunspaceInfo ) = CreateInitialPowerShellSession ( ) ;
350+ ( PowerShell pwsh , RunspaceInfo localRunspaceInfo , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShellSession ( ) ;
351+ _mainRunspaceEngineIntrinsics = engineIntrinsics ;
349352 _localComputerName = localRunspaceInfo . SessionDetails . ComputerName ;
350353 _runspaceStack . Push ( new RunspaceFrame ( pwsh . Runspace , localRunspaceInfo ) ) ;
351354 PushPowerShellAndRunLoop ( pwsh , PowerShellFrameType . Normal , localRunspaceInfo ) ;
352355 }
353356
354- private ( PowerShell , RunspaceInfo ) CreateInitialPowerShellSession ( )
357+ private ( PowerShell , RunspaceInfo , EngineIntrinsics ) CreateInitialPowerShellSession ( )
355358 {
356- PowerShell pwsh = CreateInitialPowerShell ( _hostInfo , _readLineProvider ) ;
359+ ( PowerShell pwsh , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShell ( _hostInfo , _readLineProvider ) ;
357360 RunspaceInfo localRunspaceInfo = RunspaceInfo . CreateFromLocalPowerShell ( _logger , pwsh ) ;
358- return ( pwsh , localRunspaceInfo ) ;
361+ return ( pwsh , localRunspaceInfo , engineIntrinsics ) ;
359362 }
360363
361364 private void PushPowerShellAndRunLoop ( SMA . PowerShell pwsh , PowerShellFrameType frameType , RunspaceInfo newRunspaceInfo = null )
@@ -611,7 +614,7 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
611614 return pwsh ;
612615 }
613616
614- public PowerShell CreateInitialPowerShell (
617+ public ( PowerShell , EngineIntrinsics ) CreateInitialPowerShell (
615618 HostStartupInfo hostStartupInfo ,
616619 ReadLineProvider readLineProvider )
617620 {
@@ -647,7 +650,7 @@ public PowerShell CreateInitialPowerShell(
647650 }
648651 }
649652
650- return pwsh ;
653+ return ( pwsh , engineIntrinsics ) ;
651654 }
652655
653656 private Runspace CreateInitialRunspace ( InitialSessionState initialSessionState )
@@ -666,7 +669,27 @@ private Runspace CreateInitialRunspace(InitialSessionState initialSessionState)
666669
667670 private void OnPowerShellIdle ( )
668671 {
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 )
670693 {
671694 return ;
672695 }
@@ -686,9 +709,21 @@ private void OnPowerShellIdle()
686709 return ;
687710 }
688711
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 ;
689716 task . ExecuteSynchronously ( cancellationScope . CancellationToken ) ;
690717 }
691718 }
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+ }
692727 }
693728
694729 private void OnCancelKeyPress ( object sender , ConsoleCancelEventArgs args )
@@ -769,7 +804,8 @@ private Task PopOrReinitializeRunspaceAsync()
769804 // If our main runspace was corrupted,
770805 // we must re-initialize our state.
771806 // TODO: Use runspace.ResetRunspaceState() here instead
772- ( PowerShell pwsh , RunspaceInfo runspaceInfo ) = CreateInitialPowerShellSession ( ) ;
807+ ( PowerShell pwsh , RunspaceInfo runspaceInfo , EngineIntrinsics engineIntrinsics ) = CreateInitialPowerShellSession ( ) ;
808+ _mainRunspaceEngineIntrinsics = engineIntrinsics ;
773809 PushPowerShell ( new PowerShellContextFrame ( pwsh , runspaceInfo , PowerShellFrameType . Normal ) ) ;
774810
775811 _logger . LogError ( $ "Top level runspace entered state '{ oldRunspaceState . State } ' for reason '{ oldRunspaceState . Reason } ' and was reinitialized."
0 commit comments