Public/Enter-EditorServicesProcess.ps1
using namespace System.Management.Automation using namespace System.Collections.Generic function Enter-EditorServicesProcess { <# .EXTERNALHELP EditorServicesProcess-help.xml #> [CmdletBinding()] param( [Parameter(Position=0, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] [int] $ProcessId ) begin { $infoList = [List[int]]::new() } process { if ($ProcessId) { $infoList.Add($ProcessId) }} end { if ($infoList) { $targetProcess = $infoList[0] } else { $targetProcess = (Get-EditorServicesProcess)[0].ProcessId } # Sometimes when Get-EditorServicesProcess is ran before this, a process or two might be missing # for a short time while it's cleaning up. So we wait. $timeoutLoop = 0 while (-not ($pipeInfo = (GetNamedPipes) -match $targetProcess)) { Start-Sleep -Milliseconds 500 if (($timeoutLoop++) -eq 10) { $PSCmdlet.ThrowTerminatingError( [ErrorRecord]::new( [ArgumentException]::new($Strings.CannotFindProcess), 'CannotFindProcess', [ErrorCategory]::InvalidArgument, $targetProcess)) } } $pipeInfo = $pipeInfo | GetPipeInfo $runspace = NewRemoteRunspace $pipeInfo.ProcessId $pipeInfo.AppDomain -Prepare if (-not $runspace) { $PSCmdlet.ThrowTerminatingError( [ErrorRecord]::new( [ArgumentException]::new($Strings.CannotFindProcess), 'CannotFindProcess', [ErrorCategory]::InvalidArgument, $targetProcess)) } # If the pipe gets parsed wrong the runspace can come out broken. Also if cleanup wasn't done # currently after exiting the runspace. if ('Broken' -eq $runspace.State) { $PSCmdlet.ThrowTerminatingError( [ErrorRecord]::new( [RuntimeException]::new($Strings.InvalidRunspaceState, $runspace.State.Reason), 'InvalidRunspaceState', [ErrorCategory]::InvalidArgument, $targetProcess)) } $ps = [PowerShell]::Create(). AddScript(' $global:psEditorRunspace = Get-Runspace 2 $global:psEditor = $psEditorRunspace.SessionStateProxy.PSVariable.GetValue("psEditor") Set-Location $psEditor.Workspace.Path Import-Module (Join-Path ($psEditorRunspace. SessionStateProxy. InvokeCommand. GetCommand("Find-Ast", "Function"). Module. ModuleBase) "PowerShellEditorServices.Commands.psd1") ') try { $ps.Runspace = $runspace $ps.Invoke() } finally { $ps.Dispose() } # The runspace will close itself on pop, but not dispose, this will take care of that. $runspace.add_StateChanged({ param($Runspace, $RunspaceStateArgs) if ('Closed' -eq $RunspaceStateArgs.RunspaceStateInfo.State) { $Runspace.Dispose() }}) try { $host.PushRunspace($runspace) } catch { $runspace.Close() } } } |