VS Code Powershell Editor Services Throws Exception If Powershell Profile Contains ErrorActionPreference=Stop
caparkaya opened this issue ยท 4 comments
Prerequisites
- Write a descriptive title.
- Make sure you are able to repro it on the latest version
- Search the existing issues.
Steps to reproduce
Hello,
With the latest update of VS Code (v1.74.1) Powershell Extension (v2022.12.1), with Terminal > Integrated > Shell Integration: Enabled (Checked), Powershell Editor Services throws exception at startup if the powershell profile script file (Microsoft.VSCode_profile.ps1) contains
$ErrorActionPreference = "Stop"; Set-StrictMode -Version Latest
It fails in file "src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs", at line 567 (function Global:Prompt()):
$Global:__LastHistoryId = $LastHistoryEntry.Id
because $LastHistoryEntry is null. Looking at the code fragment, I understand that at line 529 the assignment statement might result in $null value (or the resulting object might not contain Id property) which is not handled properly.
Expected behavior
Setting
$ErrorActionPreference = "Stop"; Set-StrictMode -Version Latest
in powershell profile script should not cause any startup errors inside Powershell Editor Services.
Actual behavior
At editor services startup (with Powershell profile loaded in terminal):
The property 'Id' cannot be found on this object. Verify that the property exists.
At line:57 char:2
+ $Global:__LastHistoryId = $LastHistoryEntry.Id
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : PropertyNotFoundStrict
Error details
[Warn - 12:01:11] Microsoft.PowerShell.EditorServices.Services.PowerShell.Host.PsesInternalHost: Runtime exception occurred while executing command:
System.Management.Automation.RuntimeException: The variable '$IsWindows' cannot be retrieved because it has not been set.
at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke)
at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke[T](IEnumerable input, PSInvocationSettings settings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility.PowerShellExtensions.InvokeAndClear[TResult](PowerShell pwsh, PSInvocationSettings invocationSettings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution.SynchronousPowerShellTask`1.ExecuteNormally(CancellationToken cancellationToken) |
[Error - 12:01:11] OmniSharp.Extensions.JsonRpc.DefaultRequestInvoker: Failed to handle request initialize 0 - System.Management.Automation.RuntimeException: The variable '$IsWindows' cannot be retrieved because it has not been set.
at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke)
at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke[T](IEnumerable input, PSInvocationSettings settings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility.PowerShellExtensions.InvokeAndClear[TResult](PowerShell pwsh, PSInvocationSettings invocationSettings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution.SynchronousPowerShellTask`1.ExecuteNormally(CancellationToken cancellationToken)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution.SynchronousPowerShellTask`1.Run(CancellationToken cancellationToken)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution.SynchronousTask`1.ExecuteSynchronously(CancellationToken executorCancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Host.PsesInternalHost.<TryStartAsync>d__81.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.LanguageServer.Server.LanguageServer.<MediatR-IRequestHandler<OmniSharp-Extensions-LanguageServer-Protocol-Models-InternalInitializeParams\,OmniSharp-Extensions-LanguageServer-Protocol-Models-InitializeResult>-Handle>d__78.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.LanguageServer.Server.Pipelines.SemanticTokensDeltaPipeline`2.<Handle>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.LanguageServer.Server.Pipelines.ResolveCommandPipeline`2.<Handle>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestPreProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestPostProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.<Handle>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.JsonRpc.RequestRouterBase`1.<<RouteRequest>g__InnerRoute|7_0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.JsonRpc.RequestRouterBase`1.<RouteRequest>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at OmniSharp.Extensions.JsonRpc.DefaultRequestInvoker.<>c__DisplayClass10_0.<<RouteRequest>b__5>d.MoveNext() | Method='initialize' RequestId='0'
[Warn - 12:01:11] Microsoft.PowerShell.EditorServices.Services.PowerShell.Host.PsesInternalHost: Runtime exception occurred while executing command:
System.Management.Automation.PropertyNotFoundException: The property 'Id' cannot be found on this object. Verify that the property exists.
at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke)
at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke[T](IEnumerable input, PSInvocationSettings settings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility.PowerShellExtensions.InvokeAndClear[TResult](PowerShell pwsh, PSInvocationSettings invocationSettings)
at Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution.SynchronousPowerShellTask`1.ExecuteNormally(CancellationToken cancellationToken) |
[Warn - 12:01:11] OmniSharp.Extensions.LanguageServer.Server.LspServerOutputFilter: Tried to send request or notification before initialization was completed and will be sent later OmniSharp.Extensions.JsonRpc.Server.Messages.InternalError | @Request='OmniSharp.Extensions.JsonRpc.Server.Messages.InternalError'
Environment data
Name Value
---- -----
PSVersion 5.1.19041.1682
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.1682
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Version
Powershell Extension Version: v2022.12.1, VSCode Version: 1.74.1
Visuals
No response
At the end of the first pass, It looks like it sets the global to null
$Global:__LastHistoryId = $LastHistoryEntry.Id # which is null
pass 1:
- sets
$Global:__LastHistoryId = -1
- fails test:
if ( $Global:__LastHistoryId -ne -1 ) { }
- because
-1 -ne -1
- because
- sets
$Global:__LastHistoryId = $null
pass 2:
- pass test:
if ( $Global:__LastHistoryId -ne -1 ) { }
- because
$null -ne -1
- because
- this time
LastHistoryEntry
has a value - fails
$LastHistoryEntry.Id -eq $Global:__LastHistoryId
- because
<any int> -eq $null
- because
- sets
$Global:__LastHistoryId = $LastHistoryEntry.Id
- therefore
$Global:__LastHistoryId == <any int>
- therefore
pass 3
- global stabilizes, things are okay from now on?
My annotations are the ๐ฆ
-comments. The rest is the truncated original.
# Prevent installing more than once per session
if (Test-Path variable:global:__VSCodeOriginalPrompt) {
return;
}
# Disable shell integration when the language mode is restricted
if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") {
return;
}
$Global:__VSCodeOriginalPrompt = $function:Prompt
$Global:__LastHistoryId = -1
function Global:Prompt() {
$FakeCode = [int]!$global:?
$LastHistoryEntry = Get-History -Count 1
# ๐ฆ $LastHistoryEntry: is true null
# Skip finishing the command if the first command has not yet started
if ($Global:__LastHistoryId -ne -1) {
# ๐ฆ -1 -ne -1 == false
if ($LastHistoryEntry.Id -eq $Global:__LastHistoryId) {
# if entered ๐ฆ $null.Id -eq -1 == false
}
else {
# if entered then ๐ฆ that means: $Global:__LastHistoryId != -1
$Result = '..'
if ($LastHistoryEntry.CommandLine) {
#๐ฆ if $null , therefore: false
$CommandLine = $LastHistoryEntry.CommandLine
}
else {
$CommandLine = ""
}
}
}
$Result += $Global:__VSCodeOriginalPrompt.Invoke()
$Global:__LastHistoryId = $LastHistoryEntry.Id
# ๐ฆ $global:__lastHistoryId = $null
return $Result
}
Thank you @ninmonkey , I'm not much familiar with this process but I understand that you were able to repro this issue. Should I propose a code-based solution & open a pull-request myself or will someone from the dev-team do this within a time-frame upon availability?
I may not be able to see how my proposed solution will affect in the big picture, that's the reason of my hesitation.
This should be resolved. The problem was actually the use of Set-StrictMode -Version Latest
being incompatible with how the VS Code team wrote their shell integration script. We worked around it by adding:
# NOTE: We disable strict mode for the scope of this function because it unhelpfully throws an
# error when $LastHistoryEntry is null, and is not otherwise useful.
Set-StrictMode -Off
to the prompt wrapper in that script.
This issue has been marked as answered and has not had any activity in a day. It has been automatically closed for housekeeping purposes.