Casting problems in Visual Studio Code Windows Powershell 5.1 terminal
Prerequisites
- [X] I have written a descriptive issue title.
- [X] I have searched all open and closed issues to ensure it has not already been reported.
- [X] I have read the troubleshooting guide.
- [X] I am sure this issue is with the extension itself and does not reproduce in a standalone PowerShell instance.
- [X] I have verified that I am using the latest version of Visual Studio Code and the PowerShell extension.
- [X] If this is a security issue, I have read the security issue reporting guidance.
Summary
I have had these casting problems several times. Now I am taking the time to document them. They were always error messages like "Type A cannot be converted to type A". But only in the Windows Powershell 5.1 terminal.
Also, the example script below in "Steps to Reproduce" does not work in the Windows Powershell 5.1 terminal only.
Expected:
info: int[0]
Hello from Windows Powershell
But I get this:
PS C:\GithubIssue> . 'C:\GithubIssue\Github VS Code.ps1'
Cannot find an overload for "new" and the argument count: "1".
At C:\GithubIssue\Github VS Code.ps1:26 char:1
+ $loggerFactory = [Microsoft.Extensions.Logging.LoggerFactory]::new(
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Cannot find an overload for "new" and the argument count: "1".
At C:\GithubIssue\Github VS Code.ps1:61 char:5
+ [Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider]::new ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Constructor not found.
Constructor not found.
Microsoft.Extensions.Options.IOptionsMonitor`1[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions, Microsoft.Extensions.Logging.Console, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]
Microsoft.Extensions.Options.OptionsMonitor`1[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions, Microsoft.Extensions.Logging.Console, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]
Exception calling "Invoke" with "1" argument(s): "Object of type
'Microsoft.Extensions.Options.OptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]' cannot be converted to type
'Microsoft.Extensions.Options.IOptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]'."
At C:\GithubIssue\Github VS Code.ps1:86 char:5
+ $foolMe = $constructor.Invoke(@($optionsMonitor))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
Exception calling "Invoke" with "1" argument(s): "Object of type
'Microsoft.Extensions.Options.OptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]' cannot be converted to type
'Microsoft.Extensions.Options.IOptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]'."
At C:\GithubIssue\Github VS Code.ps1:90 char:5
+ $foolMe = $constructor.Invoke(@($cast))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
Exception calling "Invoke" with "1" argument(s): "Object of type
'Microsoft.Extensions.Options.OptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]' cannot be converted to type
'Microsoft.Extensions.Options.IOptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]'."
At C:\GithubIssue\Github VS Code.ps1:94 char:5
+ $foolMe = $constructor.Invoke(@($cast))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
The crucial error is:
"Object of type
'Microsoft.Extensions.Options.OptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]' cannot be converted to type
'Microsoft.Extensions.Options.IOptionsMonitor`1[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]'."
Why does this happen and how can I avoid it?
I know that one type is an interface. But for one thing, Powershell doesn't know the difference. On the other hand, why does it work in a Windows Powershell 5.1 console, but not in the Windows Powershell 5.1 terminal of VS Code?
PowerShell Version
PS C:\> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.2364
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.2364
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Visual Studio Code Version
PS C:\> code --version
1.75.1
441438abd1ac652551dbe4d408dfcec8a499b8bf
x64
Extension Version
PS C:\> code --list-extensions --show-versions | Select-String powershell
[email protected]
[email protected]
Steps to Reproduce
# This works fine in
# Windows Powershell 5.1 console
# Powershell Core 7.3.2 console
# Visual Studio Code Powershell Core 7.3.2 terminal
# BUT NOT IN
# Visual Studio Code Windows Powershell 5.1 terminal
Add-Type -Path "$PSScriptRoot\v7.0.0\Microsoft.Extensions.Logging.dll"
Add-Type -Path "$PSScriptRoot\v7.0.0\Microsoft.Extensions.Logging.Console.dll"
Add-Type -Path "$PSScriptRoot\v7.0.0\Microsoft.Extensions.Options.dll"
$configureNamedOptions = [Microsoft.Extensions.Options.ConfigureNamedOptions[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]::new('', $null)
$optionsFactory = [Microsoft.Extensions.Options.OptionsFactory[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]::new(
[Microsoft.Extensions.Options.ConfigureNamedOptions[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions][]] @($configureNamedOptions),
[System.Collections.Generic.List[Microsoft.Extensions.Options.IPostConfigureOptions[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]]::new()
)
$optionsMonitor = [Microsoft.Extensions.Options.OptionsMonitor[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]::new(
$optionsFactory,
[System.Collections.Generic.List[Microsoft.Extensions.Options.IOptionsChangeTokenSource[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]]::new(),
[Microsoft.Extensions.Options.OptionsCache[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]]::new()
)
$loggerFactory = [Microsoft.Extensions.Logging.LoggerFactory]::new(
[Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider[]] @([Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider]::new($optionsMonitor)),
[Microsoft.Extensions.Logging.LoggerFilterOptions] @{ MinLevel = [Microsoft.Extensions.Logging.LogLevel]::Trace }
)
if ($null -ne $loggerFactory) {
$method = [Microsoft.Extensions.Logging.LoggerFactoryExtensions].GetMethod('CreateLogger',
[System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::Public, $null,
[Type[]]@([Microsoft.Extensions.Logging.ILoggerFactory]), $null
)
$method = $method.MakeGenericMethod(@([int]))
$logger = $method.Invoke($null, @($loggerFactory))
$method = [Microsoft.Extensions.Logging.LoggerExtensions].GetMethod('LogInformation',
[System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::Public,
$null,
[Type[]]@([Microsoft.Extensions.Logging.ILogger], [string], [object[]]),
$null
)
$loggerFactory.Dispose()
}
if ($null -ne $logger) {
if ($PSVersionTable.PSVersion.Major -gt 5) {
$method.Invoke($null, @($logger, "Hello from Powershell Core", $null))
}
else {
$method.Invoke($null, @($logger, "Hello from Windows Powershell", $null))
}
}
### Try to narrow down the error ####################################################################
if ($null -eq $loggerFactory) {
# Get original error message.
[Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider]::new($optionsMonitor)
# Get a better error message.
$constructor = [Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider].GetConstructor(
[Type[]]@([Microsoft.Extensions.Options.OptionsMonitor[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions]], [string], [object[]])
)
if ($null -eq $constructor) {
Write-Host -F Yellow 'Constructor not found.'
}
# Let's try FullName.
$constructor = [Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider].GetConstructor(
[Type[]]@([Microsoft.Extensions.Options.IOptionsMonitor[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions, Microsoft.Extensions.Logging.Console, Version = 7.0.0.0, Culture = neutral, PublicKeyToken = adb9793829ddae60]]], [string], [object[]])
)
if ($null -eq $constructor) {
Write-Host -F Yellow 'Constructor not found.'
}
#But it exists!
$constructor = [Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider].GetConstructors()[0]
$constructor.GetParameters().ParameterType.FullName
$optionsMonitor.GetType().FullName
# Try constructor.
$foolMe = $constructor.Invoke(@($optionsMonitor))
# Ok, try to cast it.
$cast = [Microsoft.Extensions.Options.IOptionsMonitor[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions, Microsoft.Extensions.Logging.Console, Version = 7.0.0.0, Culture = neutral, PublicKeyToken = adb9793829ddae60]]] $optionsMonitor
$foolMe = $constructor.Invoke(@($cast))
# Ok, try to cast it again.
$cast = $optionsMonitor -as [Microsoft.Extensions.Options.IOptionsMonitor[[Microsoft.Extensions.Logging.Console.ConsoleLoggerOptions, Microsoft.Extensions.Logging.Console, Version = 7.0.0.0, Culture = neutral, PublicKeyToken = adb9793829ddae60]]]
$foolMe = $constructor.Invoke(@($cast))
# I give up.
}
Visuals
No response
Logs
No response
Thanks @SamLowryMOI sounds like the workaround is to use PowerShell 7, this looks like an issue with the GAC
looks like an issue with the GAC
I don't think so, the GAC is the same for all programmes, isn't it?
I compared which Powershell 5.1 assemblies are loaded in the Windows console and the VS Code Terminal.
These dlls are loaded by both:
GlobalAssemblyCache FullName
------------------- --------
False Anonymously Hosted DynamicMethods Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
True Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.ConsoleHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.ConsoleHost.resources, Version=3.0.0.0, Culture=de, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.Security, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True mscorlib.resources, Version=4.0.0.0, Culture=de, PublicKeyToken=b77a5c561934e089
True System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Configuration.Install, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True System.Management.Automation.resources, Version=3.0.0.0, Culture=de, PublicKeyToken=31bf3856ad364e35
True System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
This dll is only loaded by the Windows console:
GlobalAssemblyCache FullName
------------------- --------
False Microsoft.Powershell.PSReadline, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
These dlls are only loaded by the VS Code Terminal:
GlobalAssemblyCache FullName
------------------- --------
False MediatR, Version=8.0.0.0, Culture=neutral, PublicKeyToken=bb9a41a5e8aaa7e2
False Microsoft.Extensions.Configuration, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.Configuration.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.DependencyInjection.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.Logging, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.Logging.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.Options, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.Extensions.Primitives, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
False Microsoft.PowerShell.CrossCompatibility, Version=1.21.0.0, Culture=neutral, PublicKeyToken=null
False Microsoft.PowerShell.EditorServices, Version=3.8.1.0, Culture=neutral, PublicKeyToken=null
False Microsoft.PowerShell.EditorServices.Hosting, Version=3.8.1.0, Culture=neutral, PublicKeyToken=null
False Microsoft.PowerShell.EditorServices.VSCode, Version=3.8.1.0, Culture=neutral, PublicKeyToken=null
False Microsoft.PowerShell.PSReadLine.Polyfiller, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
False Microsoft.PowerShell.PSReadLine2, Version=2.2.6.0, Culture=neutral, PublicKeyToken=null
False Microsoft.VisualStudio.Threading, Version=16.10.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False Microsoft.VisualStudio.Validation, Version=16.10.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False Microsoft.Windows.PowerShell.ScriptAnalyzer, Version=1.21.0.0, Culture=neutral, PublicKeyToken=null
False Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules, Version=1.21.0.0, Culture=neutral, PublicKeyToken=null
False Nerdbank.Streams, Version=2.8.0.0, Culture=neutral, PublicKeyToken=cac503e1823ce71c
False Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
False Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed
False OmniSharp.Extensions.DebugAdapter, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False OmniSharp.Extensions.DebugAdapter.Server, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False OmniSharp.Extensions.JsonRpc, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False OmniSharp.Extensions.LanguageProtocol, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False OmniSharp.Extensions.LanguageServer, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False OmniSharp.Extensions.LanguageServer.Shared, Version=0.19.0.0, Culture=neutral, PublicKeyToken=6d868dff454e6022
False Serilog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10
False Serilog.Extensions.Logging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10
False Serilog.Sinks.Async, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10
False Serilog.Sinks.File, Version=5.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10
False System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
False System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False System.IO.Pipelines, Version=5.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
False System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
False System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False System.Reactive, Version=5.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263
False System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False System.Threading.Channels, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
False System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
True Microsoft.PowerShell.Commands.Diagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.Commands.Management, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.Commands.Utility.resources, Version=3.0.0.0, Culture=de, PublicKeyToken=31bf3856ad364e35
True Microsoft.PowerShell.Security.resources, Version=3.0.0.0, Culture=de, PublicKeyToken=31bf3856ad364e35
True Microsoft.WSMan.Management, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
True Microsoft.WSMan.Management.resources, Version=3.0.0.0, Culture=de, PublicKeyToken=31bf3856ad364e35
True netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
True System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.Dynamic, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Reflection.Emit.ILGeneration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Reflection.Emit.Lightweight, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.resources, Version=4.0.0.0, Culture=de, PublicKeyToken=b77a5c561934e089
True System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
True System.ValueTuple, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
True System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
True System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
You can see that the VS Code Terminal loads 57 dlls in addition.
I don't know the tasks of the additional dlls, but labels like
False Microsoft.VisualStudio.Validation, Version=16.10.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
False Microsoft.Windows.PowerShell.ScriptAnalyzer, Version=1.21.0.0, Culture=neutral, PublicKeyToken=null
False Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules, Version=1.21.0.0, Culture=neutral, PublicKeyToken=null
lead me to believe that the VS Code Terminal performs additional checks and, in contrast to the Windows console, makes a distinction between classes and interfaces.
But unfortunately, there is no way around this, as Powershell does not make a difference despite the correct declaration.
And as workarounds, I run the script in VS Code with the extension "Run in Powershell" and debug in Powershell ISE.
What Sydney means is that, since Windows PowerShell 5.1 uses the .NET Framework, it has to use the GAC for assembly resolution instead of an Assembly Load Context (as available in PowerShell Core 7.x because it's built on .NET Core). This means that when using 5.1, the dependencies of the extension (the module PowerShell Editor Services and its dependencies, as you listed out) are not able to be isolated, thus leading to this problem where it works in a non-Extension Terminal, and it works in an Extension Terminal when using 7.x.
@andschwa This explains why the terminal loads the additional dlls, but not why the error occurs.
Loading a dll and using it are different things, aren't they?
If it is necessary to use a specific debugger that recognises the difference between OptionsMonitor and IOptionsMonitor because of the limitations you mentioned, ok.
But the error still occurs primarily because of the debugger. Or not?
I would just like to understand it.