0

I'm currently creating a tool for my IT department in PowerShell. I'm new to programming so I google and ask AI sometimes (I already asked AI and googled about this issue but neither could help).

My problem is about System.Windows.Forms.ComboBoxStyle being marked red even though the System.Windows.Forms is imported at the top. But all normal GUI components (which also need System.Windows.Forms) work. When I try to run it I also get an error saying

ParserError: Just some file path\LeihgeraeteManager\LeihgeraeteManager.ps1:175:45
Line |
 175 |  … eDropdown.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropD …
     |                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Unable to find type [System.Windows.Forms.ComboBoxStyle].

The weird thing is that when I run the line

Add-Type -AssemblyName System.Windows.Forms

at the top of the script manually (select and F8 in Visual Studio Code), it works after that. When I restart Visual Studio Code it won't work again until I do that.

I already tried it in the normal PowerShell ISE Editor but I get the same results there.

I use PowerShell Version 7.3.6 btw.

Here is the full code I've written so far if it helps (It's not finished yet + I've censored some file paths and Names due to data protection of internal stuff):

#############################################################
$FilePath = "Example" #Change this if the CSV Path changed
$ScriptVersion = 0.1.0.0 #Change this if it's a new version
#############################################################

Add-Type -AssemblyName System.Windows.Forms

function Write-Log($Message, $Path = $PSScriptRoot + "\", $Debug = $true, $reset = $false) {
    if ($reset -eq $True) {
        if (Test-Path -Path ($Path + "log.txt")) { # Check if File already exists
            Remove-Item -Path ($Path + "log.txt")
            return #Exit function
        }
    }

    if ($Debug) {Write-Debug $Message} # Write Debug
    $Path = $Path + "log.txt" # Add Filename to Text
    if (Test-Path -Path $Path) { # Check if File already exists
    } else {
        New-Item -Path $Path -ItemType File -Force | Out-Null #Creating new File
        Add-Content -Path $Path -Value "[dd-MM HH:mm:ss]" #Adding first line
    }
    $CurrentDate = Get-Date -Format "dd-MM HH:mm:ss" #Getting date
    $LogMessage = "[$CurrentDate] $Message" #Adding Date and message together
    Add-Content -Path $Path -Value $LogMessage #Adding the Message to the log file
}

function PopUpWindow ($WindowTitle, $WindowText, $WindowWidth = 250, $WindowHeight = 200) { 

    <#
    .SYNOPSIS
    Simple function for creating 
    #>


    $PopUp = New-Object System.Windows.Forms.Form
    $PopUp.Width = $WindowWidth
    $PopUp.Height = $WindowHeight
    $PopUp.Text = "$WindowTitle"
    $PopUp.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle #Locking window size
    $PopUp.MaximizeBox = $false #Disabling Maximize Button
    $PopUp.MinimizeBox = $false #Disabling Minimize Button

    $PopUpText = New-Object System.Windows.Forms.Label
    $PopUpText.Location = New-Object System.Drawing.Point(10,10)
    $PopUpText.AutoSize = $true
    $PopUpText.Text = "$($WindowText)"

    $PopUp.Controls.Add($PopUpText)

    $ButtonLocationWidth = (($WindowWidth - 65) / 2)
    $ButtonLocationHeight = ($WindowHeight - 70)

    $PopupCancelButton = new-object System.Windows.Forms.Button   # Creating the "Start" button
    $PopupCancelButton.Location = New-Object System.Drawing.Point($ButtonLocationWidth, $ButtonLocationHeight)
    $PopupCancelButton.Size = New-Object System.Drawing.Size(60, 25)
    $PopupCancelButton.Text = 'Close'
    $PopupCancelButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $PopUp.AcceptButton = $PopupCancelButton

    $PopUp.Controls.Add($PopupCancelButton)

    [void]$PopUp.ShowDialog()
}

function Get-FileAvailable($Path){

    if (Test-Path -Path $Path) { # If file exists...
        $IsAvail = $true # ... set variable to true
    } else {$IsAvail = $false} # If not then set to false

    return $IsAvail # Return the result
}

Write-Log -reset $true # Deleting old Log file if there is one
Write-Log "Started script and set functions" #Log
class Manager{ # Manager is saving all of the device objects and has all important Fuctions
    hidden [array]$Devices #Device Array

    AddDevice() { # This function simply creates a new device with the given data
        Write-Log "Starting AddWindow GUI creation..."
        $AddWindow = New-Object System.Windows.Forms.Form
        $AddWindow.Width = 1000
        $AddWindow.Height = 1000
        $AddWindow.Text = "Enter Information"
        Write-Log "Defined Window"

        #Computer Name
        $AddWindowTextCN = New-Object System.Windows.Forms.Label
        $AddWindowTextCN.Location = New-Object System.Drawing.Point(50,30)
        $AddWindowTextCN.Size = New-Object System.Drawing.Size(200,15)
        $AddWindowTextCN.Text = "Enter Device Name:"

        $AddWindowBoxCN = New-Object System.Windows.Forms.TextBox 
        $AddWindowBoxCN.Location = New-Object System.Drawing.Point(50,50)
        $AddWindowBoxCN.Size = New-Object System.Drawing.Size(260,20)
        $AddWindowBoxCN.Text = "NBW03"

        $AddWindow.Controls.Add($AddWindowTextCN)
        $AddWindow.Controls.Add($AddWindowBoxCN)

        #Model
        $AddWindowTextM = New-Object System.Windows.Forms.Label
        $AddWindowTextM.Location = New-Object System.Drawing.Point(50,80)
        $AddWindowTextM.Size = New-Object System.Drawing.Size(200,15)
        $AddWindowTextM.Text = "Enter Device Model:"

        $AddWindowBoxM = New-Object System.Windows.Forms.TextBox
        $AddWindowBoxM.Location = New-Object System.Drawing.Point(50,100)
        $AddWindowBoxM.Size = New-Object System.Drawing.Size(260,20)
        $AddWindowBoxM.Text = ""

        $AddWindow.Controls.Add($AddWindowTextM)
        $AddWindow.Controls.Add($AddWindowBoxM)

        #Serial Number
        $AddWindowTextSN = New-Object System.Windows.Forms.Label
        $AddWindowTextSN.Location = New-Object System.Drawing.Point(50,130)
        $AddWindowTextSN.Size = New-Object System.Drawing.Size(200,15)
        $AddWindowTextSN.Text = "Enter Serial Number:"

        $AddWindowBoxSN = New-Object System.Windows.Forms.TextBox
        $AddWindowBoxSN.Location = New-Object System.Drawing.Point(50,150)
        $AddWindowBoxSN.Size = New-Object System.Drawing.Size(260,20)
        $AddWindowBoxSN.Text = ""

        $AddWindow.Controls.Add($AddWindowTextSN)
        $AddWindow.Controls.Add($AddWindowBoxSN)

        #Owner
        $AddWindowTextO = New-Object System.Windows.Forms.Label
        $AddWindowTextO.Location = New-Object System.Drawing.Point(50,130)
        $AddWindowTextO.Size = New-Object System.Drawing.Size(200,15)
        $AddWindowTextO.Text = "Enter Manager of Device:"

        $AddWindowBoxO = New-Object System.Windows.Forms.TextBox
        $AddWindowBoxO.Location = New-Object System.Drawing.Point(50,50)
        $AddWindowBoxO.Size = New-Object System.Drawing.Size(260,20)
        $AddWindowBoxO.Text = ""

        $AddWindow.Controls.Add($AddWindowTextO)
        $AddWindow.Controls.Add($AddWindowBoxO)

        

        


        $AddWindow.ShowDialog()
        #$newDevice = [Leihgeraete]::new($ComputerName, $Model, $SerialNumber, $Owner, $InstallHinweis)
        Write-Log "Adding new Device" #Log
        #$this.Devices += $newDevice # Adds the new device to array
        Write-Log "Added new device to device array" #Log
    }
    RemoveDevice(){
        Write-Log "Starting RemoveWindow GUI creation..." #Log
        $RemoveWindow = New-Object System.Windows.Forms.Form #Window to choose the device
        $RemoveWindow.Width = 475
        $RemoveWindow.Height = 200
        $RemoveWindow.Text = "Choose Device"
        Write-Log "Defined Window" #Log

        $ChooseRemDevText = New-Object System.Windows.Forms.Label # New Text for the Window
        $ChooseRemDevText.Location = New-Object System.Drawing.Point(50,30)
        $ChooseRemDevText.Size = New-Object System.Drawing.Size(400,15)
        $ChooseRemDevText.Text = "Choose Computer to delete:"
        Write-Log "Added Text" #Log

        $RemoveWindow.Controls.Add($ChooseRemDevText) # Adding Text to the window

        $RemDeviceDropdown = New-Object System.Windows.Forms.ComboBox # Creating the dropdown menu to choose device
        $RemDeviceDropdown.Location = New-Object System.Drawing.Point(50,50)
        $RemDeviceDropdown.Width = 340

        $RemDeviceDropdown.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList # Setting Style so User can't enter custom things

        $RemDeviceDropdown.Items.Add("<None>") # Adding Default Choice

        foreach ($device in $this.Devices) { # Adding all Names to menu that are in devices array
            $RemDeviceDropdown.Items.Add($device.ComputerName)
        }

        $RemDeviceDropdown.SelectedIndex = 0 # Setting <None> to default

        $RemoveWindow.Controls.Add($RemDeviceDropdown)
        Write-Log "Added and filled Dropdown Menu" #Log

        Write-Log "Creating Buttons..." #Log
        $DeleteButton = new-object System.Windows.Forms.Button   # Creating the "Delete" button
        $DeleteButton.Location = '90, 100'
        $DeleteButton.Size = '100, 40'
        $DeleteButton.Text = 'Delete'
        $DeleteButton.Add_Click({ #Runs when button is clicked
            Write-Log "Delete button pressed" #Log
            [string]$selectedDeviceDel = $RemDeviceDropdown.SelectedItem # Saving selected device
            if ($selectedDeviceDel -ne "<None>") {
                Write-Log "Selected device is not <None>" #Log
                $RemoveWindowConf = New-Object System.Windows.Forms.Form #Window to confirm the deletion
                $RemoveWindowConf.Width = 350
                $RemoveWindowConf.Height = 200
                $RemoveWindowConf.Text = "Confirm"
                Write-Log "Created new confirmation Window" #Log

                $ConfText = New-Object System.Windows.Forms.Label # Confirm Text
                $ConfText.Location = New-Object System.Drawing.Point(50, 30)
                $ConfText.Size = New-Object System.Drawing.Size(160, 15)
                $ConfText.Text = "Do you really want to delete "
                Write-Log "Added Text" #Log

                $SelectedDeviceDelText = New-Object System.Windows.Forms.Label # Adding Computer Name in Bold for better reading
                $SelectedDeviceDelText.Location = New-Object System.Drawing.Point(210, 30)
                $SelectedDeviceDelText.Size = New-Object System.Drawing.Size(50, 15)
                $SelectedDeviceDelText.Text = $selectedDeviceDel
                $SelectedDeviceDelText.Font = [System.Drawing.Font]::new($SelectedDeviceDelText.Font, [System.Drawing.FontStyle]::Bold)
                Write-Log "Added Device Name" #Log
                
                $RemoveWindowConf.Controls.Add($ConfText)
                $RemoveWindowConf.Controls.Add($SelectedDeviceDelText)

                $ConfButtonY = new-object System.Windows.Forms.Button   # Creating the "YES" button
                $ConfButtonY.Location = '50, 80'
                $ConfButtonY.Size = '100, 40'
                $ConfButtonY.Text = 'YES'
                Write-Log "Creating Buttons" #Log
                $ConfButtonY.Add_Click({ # When click Yes the run the deletion process
                    Write-Log "Clicked on Yes on confirm Window" #Log
                    $updatedDevices = @()
                    $deviceRemoved = $false

                    foreach ($device in $Manager.Devices) { #Check if chosen device is in the array and deletes it after that
                        [string]$StrDev = $device.ComputerName # Converting Name to string
                        if ($StrDev -ne $selectedDeviceDel) {
                            $updatedDevices += $device
                            Write-Log "Added $device to new temporary array" #Log
                        } else {
                            $deviceRemoved = $true
                            Write-Log "Not added $device to new temporary array because it has the same value as the selected Device" #Log
                        }
                    }

                    if ($deviceRemoved) {
                        $Manager.Devices = $updatedDevices # Writing updated array in the original one
                        Write-Log "Replaced array in Manager class" #Log
                    }
                    $RemoveWindowConf.Close() # Closing Windows
                    $RemoveWindow.Close()
                })

                $ConfButtonN = new-object System.Windows.Forms.Button # Creating "no" button
                $ConfButtonN.Location = '180, 80'
                $ConfButtonN.Size = '100, 40'
                $ConfButtonN.Text = 'NO'
                $ConfButtonN.Add_Click({
                    $RemoveWindowConf.Close()
                    Write-Log "Canceled Confirmation for Deletion" #Log
                })
                $RemoveWindowConf.Controls.Add($ConfButtonY)
                $RemoveWindowConf.Controls.Add($ConfButtonN)
                $RemoveWindowConf.ShowDialog()
            } else {
                Write-Host "Please choose a Computer from the List!" # Informing user if they haven't changed from "<None>"
                Write-Log "Selected device is <None>" #Log
            }
            
        })
        $RemoveWindow.AcceptButton = $DeleteButton #Pressing enter will be the same as clicking on "Delete"

        $RemoveWindow.Controls.Add($DeleteButton)  #Adding the button to the Window

        Write-Log "Creating Cancel Button for Main Delete Window" #Log
        $DelCancelButton = new-object System.Windows.Forms.Button # Pressing Button that will close the deletion window
        $DelCancelButton.Location = '220, 100'
        $DelCancelButton.Size = '100, 40'
        $DelCancelButton.Text = 'Cancel'
        $DelCancelButton.Add_Click({ #Runs when button is clicked
            $RemoveWindow.Close()
        })
        $RemoveWindow.Controls.Add($DelCancelButton)
        
        Write-Log "Showing Window..." #Log
        $RemoveWindow.ShowDialog()
        
    }
}

class Leihgeraete{      #Examples
    [string]$ComputerName #Example
    [datetime]$SinceWhen #1.1.2023
    [datetime]$UntilWhen #2.2.2023
    [string]$Model #Example
    [bool]$InUse #true or false
    [string]$UsedBy #Example
    [string]$SerialNumber #SNRAD9012
    [string]$Owner #Example
    [string]$InstallHinweis #Example
    [string]$BookHinweis #Praktikant

    Leihgeraete($ComputerName, $Model, $SerialNumber, $Owner, $InstallHinweis){ # Function for creating new Leihgeraete Object
        $this.ComputerName = $ComputerName
        $this.Model = $Model
        $this.SerialNumber = $SerialNumber
        $this.Owner = $Owner
        $this.InstallHinweis = $InstallHinweis
        Write-Log "[Class:Leihgeraete] Created new Leihgeraet" #Log
    }
}

$Manager = [Manager]::new() # Creating Manager
Write-Log "Created Manager" #Log

### Test
$Manager.AddDevice("Name","Model","SN","Own","Hinw")
$Manager.AddDevice("Namea","Modeaal","SNa","Owan","Hinwa")

I tried using different ways but none of them was fitting for my needs. I also tried starting an extra job for adding the System.Windows.Forms but this resulted in my GUI elements also not working.

1 Answers1

0

This is a bug in PowerShell: https://github.com/PowerShell/PowerShell/issues/2074

The workaround on there for dot sourcing worked for me, but only in ISE, not VS code, so you could use that, if using ISE instead of VS Code is ok.

So you create another script file with literally just this in it:

Add-Type -AssemblyName 'System.Windows.Forms'

then add that file dot sourced to the top of your class methods like:

AddDevice() { # This function simply creates a new device with the given data
    . .\AddType.ps1
    Write-Log "Starting AddWindow GUI creation..."
    $AddWindow = New-Object System.Windows.Forms.Form
    rest of method.......

That currently just works off the current directory, but you could keep that dot sourced file where ever you want.

KG-DROID
  • 268
  • 6