PowerShell / PowerShell/vscode-powershell

Casting problems in Visual Studio Code Windows Powershell 5.1 terminal

Aperta
#4,426 4 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Bug: PowerShell 5.1 Issue-Bug
Lingua principale
TypeScript
Stelle
1.9k
Fork
548
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

Prerequisites
  • I have written a descriptive issue title.
  • I have searched all open and closed issues to ensure it has not already been reported.
  • I have read the troubleshooting guide.
  • I am sure this issue is with the extension itself and does not reproduce in a standalone PowerShell instance.
  • I have verified that I am using the latest version of Visual Studio Code and the PowerShell extension.
  • 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

ms-vscode.powershell@2023.1.0
tobysmith568.run-in-powershell@1.1.1
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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia eseguendo lo script inline di riproduzione con le DLL Microsoft.Extensions v7.0.0 indicate nel terminale Windows PowerShell 5.1, quindi confrontalo con le console funzionanti elencate. Ispeziona la configurazione del terminale e della sessione PowerShell dell'estensione per identificare perché gli stessi tipi generici vengono caricati in modo incompatibile. Il lavoro è completato quando viene spiegato il comportamento esclusivo di VS Code e viene documentato o corretto un percorso riproducibile per i costruttori e i casts segnalati.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
powershell, typescript, vscode
Ambito
developer-experience, tooling
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
28/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.