PowerShellEditorServices
PowerShellEditorServices copied to clipboard
Integrating PSES into Visual Studio
Hi, Not sure is an issue or I doing something wrong... I am trying to kickoff POC project to integrate PSES into Visual Studio. Before starting to work on extension itself I would like to check how to deal with PSES in a simple console application (with some hardcoded settings).
First step is to start Server - is done. I guess it is done, at least I see running process, log.txt, StartEditorServices.log and sessionDetails.json files with proper data inside.
Second step is to create and initialize Client - and here is an issue... I have find out that PSES itself using OmniShart under the hood to startup Server so I decided to go same way by using "OmniSharp.Extensions.LanguageServer.Client" and "var PsesLanguageClient = LanguageClient.Create(options => ..." to get an instance of Client. I have stuck on "await PsesLanguageClient.Initialize(new CancellationToken()).ConfigureAwait(false);". Playing with that in a different ways - I guess the issue is, request is sent but no response because of "Access deny" issue in internal "System.IO" implementation for named pipes.
Environment details:
- OS Windows 10 Enterprise, Version 21H1, Build 19043.1165
- Net Framework runtime 4.7.1
- PowerShell Version 5.1.19041.1151
- LSP Transport is duplex named pipe
startup.ps1 file looks like that:
$PSES_BUNDLE_PATH = "D:\PowerShellEditorServices"
$SESSION_TEMP_PATH = "D:\pslog"
. $PSES_BUNDLE_PATH/PowerShellEditorServices/Start-EditorServices.ps1 `
-BundledModulesPath $PSES_BUNDLE_PATH `
-LogPath "$SESSION_TEMP_PATH/logs.log" `
-SessionDetailsPath "$SESSION_TEMP_PATH/session.json" `
-FeatureFlags @() `
-AdditionalModules @() `
-HostName 'My Client' `
-HostProfileId 'myclient' `
-HostVersion 1.0.0 `
-LogLevel Verbose
Maybe you have or may provide simple sample? I have found some based on NodeJs but nothing for C#. And maybe my main question is - do you officially support to work on Windows with combination of PS v5 and Net 4.7.1?
Please let me know if I may provide any additional information, and thanks a lot for any help...
Playing with that in a different ways - I guess the issue is, request is sent but no response because of "Access deny" issue in internal "System.IO" implementation for named pipes.
Hmm could you elaborate on this? A full repro example would also be very helpful
do you officially support to work on Windows with combination of PS v5 and Net 4.7.1?
More specifically PS v5.1 but yeah definitely
Thanks for so quick response, Here is solution file - https://github.com/Xrumet/PowerShellTools/tree/main/Draft Startup.ps1 - https://github.com/Xrumet/PowerShellTools/blob/main/Draft/ConsoleApp2/startup.ps1 Program.cs ->Main - https://github.com/Xrumet/PowerShellTools/blob/main/Draft/ConsoleApp2/Program.cs
It is dirty a bit, but still the issue is on line # 195 of program.cs I guess
Hmm could you elaborate on this?
That's what I see if pause application:

And also when I switched pipe from duplex mode to separate in and out pipes, I got an exception about permission deny when try to connect to output pipe - "//await outPipeClient.ConnectAsync(4000);"
I only guessing, maybe I do something wrong there by passing -HostProfileId 'myclient' ?...
I think this line here might be the problem:
https://github.com/Xrumet/PowerShellTools/blob/e577ed9ee77ef3b4e5d53acabf6d034416bb6fff/Draft/ConsoleApp2/Program.cs#L240
Starting the language server in an elevated process is going to make is so non-elevated processes are unable to access the named pipe it creates.
So, should I try to run Start-EditorServices.ps1 directly? And I guess still with "startInfo.Verb = "runAs";" ?
I'd just comment out that line and give it ago however you've been doin' it.
The verb RunAs attempts to elevate the process, probably triggering a UAC prompt. By default for security reasons, the named pipe created by an elevated process cannot be connected to by one that isn't. That's why you get an access denied error, so you should be able to ditch setting the verb and at the very least get further than before.
Noup, didn't help, Will try to switch back to separate in\out pipes to see exact error and share it.
Yeap, that's it:

May it be because of:
- Profile paths:
+ AllUsersAllHosts: C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
+ AllUsersCurrentHost: C:\Windows\System32\WindowsPowerShell\v1.0\myclient_profile.ps1
+ CurrentUserAllHosts: C:\Users\xrumet\Documents\WindowsPowerShell\profile.ps1
+ CurrentUserCurrentHost: C:\Users\xrumet\Documents\WindowsPowerShell\myclient_profile.ps1
I guess System32 folder is protected too much :) I do not have any experience working with pipes so have no even idea where to looking to solve this issue...
From other hand input pipe connected successfully... CanRead and CanWrite properties have correct values, Maybe the issue that "ConnectAsync" is used but "IsAsync = false"?
Have pushed all changes.
Added System.IO.Pipes.PipeOptions.Asynchronous to make it async - didn't help :(
afaik there's only one pipe, not one for read and one for write.
an example session details file looks like this:
{
"status":"started",
"languageServiceTransport":"NamedPipe",
"languageServicePipeName":"\\\\.\\pipe\\PSES_2wbpjblh.pnn",
"debugServiceTransport":"NamedPipe",
"debugServicePipeName":"\\\\.\\pipe\\PSES_ndg4d4tp.2pr"
}
So it's unclear what exactly you're getting back in sessionInfoObj.
I have added this line: -SplitInOutPipes to startup.ps1, so session looks like that for me:
{
"status": "started",
"languageServiceTransport": "NamedPipeSimplex",
"languageServiceReadPipeName": "\\\\.\\pipe\\in_PSES_xqriwnay.d1o",
"languageServiceWritePipeName": "\\\\.\\pipe\\out_PSES_xqriwnay.d1o",
"debugServiceTransport": "NamedPipeSimplex",
"debugServiceReadPipeName": "\\\\.\\pipe\\in_PSES_w2ufkaig.dfj",
"debugServiceWritePipeName": "\\\\.\\pipe\\out_PSES_w2ufkaig.dfj"
}
and in program.cs reading it from sessionInfoObj.languageServiceReadPipeName and languageServiceWritePipeName properties, in runtime/debug values looks pretty correct...
Wonder if Visual Studio debugging process have limited permissions so tried to run app manually with admin console:

no luck yet :(
Oh okay I stand corrected, we support that apparently. I'd probably try to get it working without splitting them first as that's the most tested path.
You're getting the same error message while not splitting right? When you get the exception can you verify that the serverName and pipeName are correct?
You're getting the same error message while not splitting right?
Noup, it is "successfully" connected and silently hangs when try to call client.initialize
When you get the exception can you verify that the serverName and pipeName are correct?
I see next values:
?sessionInfoObj.languageServiceWritePipeName
"\\\\.\\pipe\\out_PSES_fjriplcj.3xt" (this is raw value from session)
?outserverName
"." (this is what I have extracted and try to pass as input parameter into NamedPipeClientStream)
?outpipeName
"out_PSES_fjriplcj.3xt"
Not sure, but guess that's what should be there
Just in case, I have looked around a bit (a lot :) ), and found some suggestions like that: https://stackoverflow.com/questions/3478166/named-pipe-server-throws-unauthorizedaccessexception-when-creating-a-second-inst
Unfortunately for me most of them to be applied on server-side...
@SeeminglyScience, one more Thanks for your help and attention, at least not I am not alone there now.
Noup, it is "successfully" connected and silently hangs when try to call client.initialize
Ah okay that's very different and more likely to be the exact thing we need to troubleshoot. That's also a little harder to direct you into places to check, so I'll need to build it myself and check some things a bit later. Can you push the latest changes?
Just in case, I have looked around a bit (a lot :) ), and found some suggestions like that: stackoverflow.com/questions/3478166/named-pipe-server-throws-unauthorizedaccessexception-when-creating-a-second-inst
Unfortunately for me most of them to be applied on server-side...
I don't think this is related FYI
Yes, I have pushed all I have.
Finally I tried to compile PSES binaries locally and somehow it works now! So, this issue may be closed.
That may be thanks to the awesome work @andschwa has done getting PSES to work in different clients ❤️