PowerShell / PowerShell/PowerShell

It is impossible to create a Windows Forms class without loading the assembly before parsing the file containing the class

Open
#21,140 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Needs-Triage
Dominant language
C#
Stars
55.5k
Forks
8.5k
Avg merge
1d 2h
Merged PRs (30d)
88

Description

Prerequisites
Steps to reproduce
  1. Create a simple Windows Forms class in a .ps1 :
using namespace System.Windows.Forms
Add-Type -Assembly System.Windows.Forms

class MyForm : Form {
    MyForm() {
        [Application]::EnableVisualStyles()
        
        $this.Text = 'My Form'
        $this.Size = New-Object System.Drawing.Size(300, 200)
        $this.StartPosition = 'CenterScreen'
    }
}

$myForm = [MyForm]::new()
$myForm.ShowDialog()
  1. Try to run it :
    PS> .\myform.ps1
Expected behavior
Empty form opens up
Actual behavior
PS> .\myform.ps1
ParserError: C:\myform.ps1:5
Line |
   5 |  class MyForm : Form {
     |                 ~~~~
     | Unable to find type [Form].

Note that this class works correctly if i instead do this :

PS> Add-Type -Assembly System.Windows.Forms
PS> .\myform.ps1

Removing "using namespace" and specifying "System.Windows.Forms" on each type does not change anything to this behavior, nor does adding a "using assembly" statement (which is supposedly made for this if i understand the documentation about it correctly).

using assembly 'C:\Program Files\PowerShell\7\System.Windows.Forms.dll'
Add-Type -Assembly System.Windows.Forms

class MyForm : System.Windows.Forms.Form {
    MyForm() {
        [System.Windows.Forms.Application]::EnableVisualStyles()
        
        $this.Text = 'My Form'
        $this.Size = New-Object System.Drawing.Size(300, 200)
        $this.StartPosition = 'CenterScreen'
    }
}

$myForm = [MyForm]::new()
$myForm.ShowDialog()
PS> .\myform.ps1
ParserError: C:\myform.ps1:4
Line |
   4 |  class MyForm : System.Windows.Forms.Form {
     |                 ~~~~~~~~~~~~~~~~~~~~~~~~~
     | Unable to find type [System.Windows.Forms.Form].
Error details
Exception             :
    Type        : System.Management.Automation.ParseException
    Errors      :
        Extent  : Form
        ErrorId : TypeNotFound
        Message : Unable to find type [Form].

        Extent  : Application
        ErrorId : TypeNotFound
        Message : Unable to find type [Application].
    Message     : At C:\myform.ps1:5 char:16
                  + class MyForm : Form {
                  +                ~~~~
                  Unable to find type [Form].

                  At C:\myform.ps1:7 char:10
                  +         [Application]::EnableVisualStyles()
                  +          ~~~~~~~~~~~
                  Unable to find type [Application].
    ErrorRecord :
        Exception             :
            Type    : System.Management.Automation.ParentContainsErrorRecordException
            Message : At C:\myform.ps1:5 char:16
                      + class MyForm : Form {
                      +                ~~~~
                      Unable to find type [Form].

                      At C:\myform.ps1:7 char:10
                      +         [Application]::EnableVisualStyles()
                      +          ~~~~~~~~~~~
                      Unable to find type [Application].
            HResult : -2146233087
        CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
        FullyQualifiedErrorId : TypeNotFound
        InvocationInfo        :
            ScriptLineNumber : 5
            OffsetInLine     : 16
            HistoryId        : 2
            ScriptName       : C:\myform.ps1
            Line             : class MyForm : Form {

            Statement        : Form
            PositionMessage  : At C:\myform.ps1:5 char:16
                               + class MyForm : Form {
                               +                ~~~~
            PSScriptRoot     : C:\
            PSCommandPath    : C:\myform.ps1
            CommandOrigin    : Internal
        ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
    TargetSite  :
        Name          : Create
        DeclaringType : scriptblock
        MemberType    : Method
        Module        : System.Management.Automation.dll
    Data        : System.Collections.ListDictionaryInternal
    Source      : System.Management.Automation
    HResult     : -2146233087
    StackTrace  :
   at System.Management.Automation.ScriptBlock.Create(Parser parser, String fileName, String fileContents)
   at System.Management.Automation.ExternalScriptInfo.ParseScriptContents(Parser parser, String fileName, String
fileContents, Nullable`1 definingLanguageMode)
   at System.Management.Automation.ExternalScriptInfo.get_ScriptBlock()
   at System.Management.Automation.CommandDiscovery.CreateCommandProcessorForScript(ExternalScriptInfo scriptInfo,
ExecutionContext context, Boolean useNewScope, SessionStateInternal sessionState)
   at System.Management.Automation.CommandDiscovery.LookupCommandProcessor(CommandInfo commandInfo, CommandOrigin
commandOrigin, Nullable`1 useLocalScope, SessionStateInternal sessionState)
   at System.Management.Automation.ExecutionContext.CreateCommand(String command, Boolean dotSource)
   at System.Management.Automation.PipelineOps.AddCommand(PipelineProcessor pipe, CommandParameterInternal[]
commandElements, CommandBaseAst commandBaseAst, CommandRedirection[] redirections, ExecutionContext context)
   at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput,
CommandParameterInternal[][] pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][]
commandRedirections, FunctionContext funcContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
CategoryInfo          : ParserError: (:) [], ParseException
FullyQualifiedErrorId : TypeNotFound
InvocationInfo        :
    ScriptLineNumber : 5
    OffsetInLine     : 16
    HistoryId        : 2
    ScriptName       : C:\myform.ps1
    Line             : class MyForm : Form {

    Statement        : Form
    PositionMessage  : At C:\myform.ps1:5 char:16
                       + class MyForm : Form {
                       +                ~~~~
    PSScriptRoot     : C:\
    PSCommandPath    : C:\myform.ps1
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
Environment data
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Microsoft Windows 10.0.23619
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Visuals

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with the myform.ps1 example, then trace parsing from ScriptBlock.Create through ExternalScriptInfo.ParseScriptContents as shown in the stack trace. Inspect how using assembly, using namespace, and Add-Type affect type resolution before a class declaration; done means the script parses and opens the empty form without a prior command.

Written by the indexing model from the issue text.

Assessment

Tech stack
powershell
Domain
cli, compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.